Skip to content

Commit

Permalink
Experimental opacity dithering for splats (#5905)
Browse files Browse the repository at this point in the history
* Opacity dithering

* shadow transparency dithering

* missed default value

* typos

* Experimental opacity dithering for splats

---------

Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
  • Loading branch information
mvaligursky and Martin Valigursky authored Dec 20, 2023
1 parent 62fe0b4 commit c65677c
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 19 deletions.
3 changes: 2 additions & 1 deletion examples/src/examples/loaders/splat.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ async function example({ canvas, deviceType, assetPath, scriptsPath, glslangPath
cameraEntity: camera,
debugRender: false,
fragment: fragment,
vertex: vertex
vertex: vertex,
dither: false
});
splat.setLocalPosition(px, py, pz);
splat.setLocalScale(scale, scale, scale);
Expand Down
14 changes: 11 additions & 3 deletions extras/splat/shader-generator-splat.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ const splatCoreFS = /* glsl_ */ `
diffuse = toneMap(diffuse);
diffuse = gammaCorrectOutput(diffuse);
#ifdef DITHER
opacityDither(B);
#endif
return vec4(diffuse, B);
#endif
Expand All @@ -270,15 +274,19 @@ class ShaderGeneratorSplat {
generateKey(options) {
const vsHash = hashCode(options.vertex);
const fsHash = hashCode(options.fragment);
return `splat-${options.pass}-${options.gamma}-${options.toneMapping}-${vsHash}-${fsHash}-${options.debugRender}`;
return `splat-${options.pass}-${options.gamma}-${options.toneMapping}-${vsHash}-${fsHash}-${options.debugRender}-${options.dither}}`;
}

createShaderDefinition(device, options) {

const defines = (options.debugRender ? '#define DEBUG_RENDER\n' : '') +
(device.isWebGL1 ? '' : '#define INT_INDICES\n');
const defines =
(options.debugRender ? '#define DEBUG_RENDER\n' : '') +
(device.isWebGL1 ? '' : '#define INT_INDICES\n') +
(options.dither ? '#define DITHER\n' : '');

const vs = defines + splatCoreVS + options.vertex;
const fs = defines + shaderChunks.decodePS +
(options.dither ? shaderChunks.bayerPS + shaderChunks.opacityDitherPS : '') +
ShaderGenerator.tonemapCode(options.toneMapping) +
ShaderGenerator.gammaCode(options.gamma) +
splatCoreFS + options.fragment;
Expand Down
22 changes: 12 additions & 10 deletions extras/splat/splat-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,17 @@ class SplatInstance {
// clone centers to allow multiple instancing of sorter
this.centers = new Float32Array(splat.centers);

this.sorter = new SplatSorter();
this.sorter.init(this.vb, this.centers, !this.splat.device.isWebGL1);

// if camera entity is provided, automatically use it to sort splats
const cameraEntity = options.cameraEntity;
if (cameraEntity) {
this.callbackHandle = cameraEntity._app.on('prerender', () => {
this.sort(cameraEntity);
});
if (!options.dither) {
this.sorter = new SplatSorter();
this.sorter.init(this.vb, this.centers, !this.splat.device.isWebGL1);

// if camera entity is provided, automatically use it to sort splats
const cameraEntity = options.cameraEntity;
if (cameraEntity) {
this.callbackHandle = cameraEntity._app.on('prerender', () => {
this.sort(cameraEntity);
});
}
}

this.updateViewport();
Expand All @@ -114,7 +116,7 @@ class SplatInstance {
this.material.destroy();
this.vb.destroy();
this.meshInstance.destroy();
this.sorter.destroy();
this.sorter?.destroy();
this.callbackHandle?.off();
}

Expand Down
12 changes: 7 additions & 5 deletions extras/splat/splat-material.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
BLEND_NORMAL,
BLEND_NORMAL, BLEND_NONE,
ShaderProcessorOptions,
getProgramLibrary,
CULLFACE_BACK,
Expand Down Expand Up @@ -34,6 +34,7 @@ const splatMainFS = `
* @property {boolean} [debugRender] - Adds #define DEBUG_RENDER for shader.
* @property {string} [vertex] - Custom vertex shader, see SPLAT MANY example.
* @property {string} [fragment] - Custom fragment shader, see SPLAT MANY example.
* @property {boolean} [dither] - True if opacity dithering should be used instead of opacity.
*/

/**
Expand All @@ -44,13 +45,13 @@ const splatMainFS = `
*/
const createSplatMaterial = (options = {}) => {

const debugRender = options.debugRender;
const { debugRender, dither } = options;

const material = new Material();
material.name = 'splatMaterial';
material.cull = debugRender ? CULLFACE_BACK : CULLFACE_NONE;
material.blendType = BLEND_NORMAL;
material.depthWrite = false;
material.blendType = dither ? BLEND_NONE : BLEND_NORMAL;
material.depthWrite = dither;

material.getShaderVariant = function (device, scene, defs, unused, pass, sortedLights, viewUniformFormat, viewBindGroupFormat) {

Expand All @@ -60,7 +61,8 @@ const createSplatMaterial = (options = {}) => {
toneMapping: (pass === SHADER_FORWARDHDR ? TONEMAP_LINEAR : scene.toneMapping),
vertex: options.vertex ?? splatMainVS,
fragment: options.fragment ?? splatMainFS,
debugRender: debugRender
debugRender: debugRender,
dither: !!dither
};

const processingOptions = new ShaderProcessorOptions(viewUniformFormat, viewBindGroupFormat);
Expand Down

0 comments on commit c65677c

Please sign in to comment.