diff --git a/examples/editor/index.html b/examples/editor/index.html index e18cbbb..70f5f71 100644 --- a/examples/editor/index.html +++ b/examples/editor/index.html @@ -498,6 +498,11 @@ gui.addColor(guiOptions, "backgroundColor").name("Background color").onChange((value) => { scene.background.set(value); }); + // spark.defaultView.stochastic = true; + gui.add(spark.defaultView, "stochastic").name("Stochastic sort-free").listen().onChange(() => { + // spark.prepareViewpoint(); + touch(); + }); const debugFolder = gui.addFolder("Debug").close(); const normalColor = dyno.dynoBool(false); @@ -524,10 +529,6 @@ debugFolder.add(spark.defaultView, "sort32").name("Float32 sort").listen(); debugFolder.add(spark, "maxPixelRadius", 1, 1024, 1).name("Max pixel radius").listen(); debugFolder.add(spark, "minAlpha", 0, 1, 0.001).name("Min alpha").listen(); - spark.defaultView.stochastic = true; - debugFolder.add(spark.defaultView, "stochastic").name("Stochastic sort-free").listen().onChange(() => { - spark.prepareViewpoint(); - }); debugFolder.add(spark, "premultipliedAlpha").name("Premultiplied alpha").listen(); const accumFolder = debugFolder.addFolder("Accumulator encoding").close();; @@ -778,6 +779,8 @@ lastTime = time; stats.begin(); + renderer.clear(true, true, false); + if (guiOptions.autoRotate) { frame.rotation.y += deltaTime / 5000; } diff --git a/src/SparkRenderer.ts b/src/SparkRenderer.ts index 846dd9e..3ebc25d 100644 --- a/src/SparkRenderer.ts +++ b/src/SparkRenderer.ts @@ -260,6 +260,7 @@ export class SparkRenderer extends THREE.Mesh { private lastUpdateTime: number | null = null; // List of cameras used for the current viewpoint (for WebXR) private defaultCameras: THREE.Matrix4[] = []; + private lastStochastic: boolean | null = null; // Should be set to the defaultView, but can be temporarily changed to another // viewpoint using prepareViewpoint() for rendering from a different viewpoint. @@ -533,6 +534,10 @@ export class SparkRenderer extends THREE.Mesh { this.uniforms.deltaTime.value = deltaTime; // Alternating debug flag that can aid in visual debugging this.uniforms.debugFlag.value = (performance.now() / 1000.0) % 2.0 < 1.0; + + // if (viewpoint.stochastic) { + // (this.geometry as SplatGeometry).instanceCount = this.uniforms.numSplats.value; + // } } if (viewpoint.target) { @@ -577,6 +582,13 @@ export class SparkRenderer extends THREE.Mesh { this.uniforms.clipXY.value = this.clipXY; this.uniforms.focalAdjustment.value = this.focalAdjustment; + if (this.lastStochastic !== !viewpoint.stochastic) { + this.lastStochastic = !viewpoint.stochastic; + this.material.transparent = !viewpoint.stochastic; + this.material.depthWrite = viewpoint.stochastic; + this.material.needsUpdate = true; + } + if (this.splatTexture) { const { enable, texture, multiply, add, near, far, mid } = this.splatTexture; @@ -638,6 +650,7 @@ export class SparkRenderer extends THREE.Mesh { this.geometry = geometry; this.material.transparent = !this.viewpoint.stochastic; this.material.depthWrite = this.viewpoint.stochastic; + this.material.needsUpdate = true; } else { // No Gsplats to display for this viewpoint yet this.uniforms.numSplats.value = 0; diff --git a/src/SparkViewpoint.ts b/src/SparkViewpoint.ts index 6f7d3ad..84bc4c3 100644 --- a/src/SparkViewpoint.ts +++ b/src/SparkViewpoint.ts @@ -569,7 +569,9 @@ export class SparkViewpoint { let activeSplats = 0; let ordering = this.orderingFreelist.alloc(maxSplats); - if (numSplats > 0) { + if (this.stochastic) { + activeSplats = numSplats; + } else if (numSplats > 0) { const { reader, doubleSortReader, diff --git a/src/shaders/splatFragment.glsl b/src/shaders/splatFragment.glsl index 132f680..358ca57 100644 --- a/src/shaders/splatFragment.glsl +++ b/src/shaders/splatFragment.glsl @@ -28,6 +28,7 @@ out vec4 fragColor; in vec4 vRgba; in vec2 vSplatUv; in vec3 vNdc; +flat in uint vSplatIndex; void main() { vec4 rgba = vRgba; @@ -72,18 +73,16 @@ void main() { } if (stochastic) { - uint uTime = floatBitsToUint(time); + const bool STEADY = false; + uint uTime = STEADY ? 0u : floatBitsToUint(time); uvec2 coord = uvec2(gl_FragCoord.xy); - uint state = uTime + 0x9e3779b9u * coord.x + 0x85ebca6bu * coord.y; + uint state = uTime + 0x9e3779b9u * coord.x + 0x85ebca6bu * coord.y + 0xc2b2ae35u * uint(vSplatIndex); state = state * 747796405u + 2891336453u; uint hash = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; hash = (hash >> 22u) ^ hash; - float rand = float(hash) / 4294967295.0; - // rand *= 2.0; + float rand = float(hash) / 4294967296.0; if (rand < rgba.a) { fragColor = vec4(rgba.rgb, 1.0); - // gl_FragDepth = gl_FragCoord.z; - // fragColor = vec4(rgba.r, 0.0, 0.0, 1.0); } else { discard; } diff --git a/src/shaders/splatVertex.glsl b/src/shaders/splatVertex.glsl index e148cde..0162293 100644 --- a/src/shaders/splatVertex.glsl +++ b/src/shaders/splatVertex.glsl @@ -10,6 +10,7 @@ attribute uint splatIndex; out vec4 vRgba; out vec2 vSplatUv; out vec3 vNdc; +flat out uint vSplatIndex; uniform vec2 renderSize; uniform uint numSplats; @@ -21,6 +22,7 @@ uniform float time; uniform float deltaTime; uniform bool debugFlag; uniform float minAlpha; +uniform bool stochastic; uniform bool enable2DGS; uniform float blurAmount; uniform float preBlurAmount; @@ -39,16 +41,25 @@ void main() { if (uint(gl_InstanceID) >= numSplats) { return; } - if (splatIndex == 0xffffffffu) { - // Special value reserved for "no splat" - return; - } - ivec3 texCoord = ivec3( - splatIndex & SPLAT_TEX_WIDTH_MASK, - (splatIndex >> SPLAT_TEX_WIDTH_BITS) & SPLAT_TEX_HEIGHT_MASK, - splatIndex >> SPLAT_TEX_LAYER_BITS - ); + ivec3 texCoord; + if (stochastic) { + texCoord = ivec3( + uint(gl_InstanceID) & SPLAT_TEX_WIDTH_MASK, + (uint(gl_InstanceID) >> SPLAT_TEX_WIDTH_BITS) & SPLAT_TEX_HEIGHT_MASK, + (uint(gl_InstanceID) >> SPLAT_TEX_LAYER_BITS) + ); + } else { + if (splatIndex == 0xffffffffu) { + // Special value reserved for "no splat" + return; + } + texCoord = ivec3( + splatIndex & SPLAT_TEX_WIDTH_MASK, + (splatIndex >> SPLAT_TEX_WIDTH_BITS) & SPLAT_TEX_HEIGHT_MASK, + splatIndex >> SPLAT_TEX_LAYER_BITS + ); + } uvec4 packed = texelFetch(packedSplats, texCoord, 0); vec3 center, scales; @@ -85,6 +96,9 @@ void main() { return; } + // Record the splat index for entropy + vSplatIndex = splatIndex; + // Compute view space quaternion of splat vec4 viewQuaternion = quatQuat(renderToViewQuat, quaternion);