From 27eeb6a02df29c3b24f8a331c64311e02b2a22ca Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 7 Nov 2025 05:13:13 +0000 Subject: [PATCH] WebGPURenderer: Optimize VSM shadow code Port optimizations from PR #32181 to the WebGPU renderer: - Extract mean variable for clarity - Add early return optimization for fully lit pixels - Improve variable naming (d, p_max) - Correct variance epsilon from 0 to 0.0000001 - Pre-compute constant (0.65 instead of 0.95 - 0.3) - Remove redundant outer clamp - Add clarifying comments These changes improve performance by reducing operations per pixel while maintaining identical visual output. --- src/nodes/lighting/ShadowFilterNode.js | 27 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/nodes/lighting/ShadowFilterNode.js b/src/nodes/lighting/ShadowFilterNode.js index adad68bb4a7636..9d94dd894513c7 100644 --- a/src/nodes/lighting/ShadowFilterNode.js +++ b/src/nodes/lighting/ShadowFilterNode.js @@ -185,8 +185,6 @@ export const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoo */ export const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, depthLayer } ) => { - const occlusion = float( 1 ).toVar(); - let distribution = texture( depthTexture ).sample( shadowCoord.xy ); if ( depthTexture.isArrayTexture ) { @@ -197,19 +195,28 @@ export const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, distribution = distribution.rg; - const hardShadow = step( shadowCoord.z, distribution.x ); + const mean = distribution.x; + const variance = max( 0.0000001, distribution.y.mul( distribution.y ) ); + + const hardShadow = step( shadowCoord.z, mean ); - If( hardShadow.notEqual( float( 1.0 ) ), () => { + // Early return if fully lit + If( hardShadow.equal( 1.0 ), () => { - const distance = shadowCoord.z.sub( distribution.x ); - const variance = max( 0, distribution.y.mul( distribution.y ) ); - let softnessProbability = variance.div( variance.add( distance.mul( distance ) ) ); // Chebeyshevs inequality - softnessProbability = clamp( sub( softnessProbability, 0.3 ).div( 0.95 - 0.3 ) ); - occlusion.assign( clamp( max( hardShadow, softnessProbability ) ) ); + return float( 1.0 ); } ); - return occlusion; + // Distance from mean + const d = shadowCoord.z.sub( mean ); + + // Chebyshev's inequality for upper bound on probability + let p_max = variance.div( variance.add( d.mul( d ) ) ); + + // Reduce light bleeding by remapping [amount, 1] to [0, 1] + p_max = clamp( sub( p_max, 0.3 ).div( 0.65 ) ); + + return max( hardShadow, p_max ); } );