Просмотр исходного кода

WebGPURenderer: Logarithmic Depth Refinement (#29561)

* 1. Improved wording on a TODO in AnalyticLightNode.js.
2. Removed unnecessary TODO in NodeMaterial.js.
3. Removed unnecessary ".add( 1 ).div( 2 )" from the log depth calculation and added more detail to the log depth comments in ViewportDepthNode.js.

* Made the camera near plane a precalculated variable in perspectiveDepthToLogarithmicDepth(), added Desmos link for logarithmic curve visualization.

* Adding 1 to each division by cameraNear to ensure the depth curve is shifted to the left as cameraNear increases. Updated Desmos graph link.

* Fixed typo in comment.
PoseidonEnergy 1 год назад
Родитель
Сommit
af3a657147

+ 0 - 6
src/materials/nodes/NodeMaterial.js

@@ -240,12 +240,6 @@ class NodeMaterial extends Material {
 
 				if ( camera.isPerspectiveCamera ) {
 
-					// Note: normally we could use "float( camera.near )" and "float( camera.far )" for the near/far arguments, but
-					// there is currently a bug with TSL/Three Shading Language whereby a "float()" expression using a huge value
-					// in scientific notation like "float( 1e27 )" will output "1e+27.0" to the shader code, which is causing problems.
-					// Since it's possible that camera.near/camera.far values may be using huge values like this (such as the logarithmic
-					// depth buffer examples on threejs.org), we must use the cameraNear/cameraFar nodes for now.
-					// TODO: can the float() node be fixed to allow for expressions like "float( 1e27 )"?
 					depthNode = perspectiveDepthToLogarithmicDepth( modelViewProjection().w, cameraNear, cameraFar );
 
 				} else {

+ 24 - 17
src/nodes/display/ViewportDepthNode.js

@@ -118,26 +118,33 @@ export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).d
 
 export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) => {
 
-	// The final logarithmic depth formula used here is adapted from one described in an article
-	// by Thatcher Ulrich (see http://tulrich.com/geekstuff/log_depth_buffer.txt), which was an
-	// improvement upon an earlier formula one described in an
+	// The final logarithmic depth formula used here is adapted from one described in an
+	// article by Thatcher Ulrich (see http://tulrich.com/geekstuff/log_depth_buffer.txt),
+	// which was an improvement upon an earlier formula one described in an
 	// Outerra article (https://outerra.blogspot.com/2009/08/logarithmic-z-buffer.html).
-	// The Outerra article ignored the camera near plane (it always assumed it was 0) and instead
+	// Ulrich's formula is the following:
+	//     z = K * log( w / cameraNear ) / log( cameraFar / cameraNear )
+	//     where K = 2^k - 1, and k is the number of bits in the depth buffer.
+	// The Outerra variant ignored the camera near plane (it assumed it was 0) and instead
 	// opted for a "C-constant" for resolution adjustment of objects near the camera.
-	// Outerra states this about their own formula: "Notice that the 'C' variant doesn’t use a near
-	// plane distance, it has it set at 0." (quote from https://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html)
-	// It was debated here whether Outerra's "C-constant" version or Ulrich's "near plane" version should
-	// be used, and ultimately Ulrich's "near plane" version was chosen for simplicity, since no "C-constant"
-	// needs to be worried about.
-	// Outerra eventually made another improvement to their original "C-constant" formula, but it still
-	// does not incorporate the camera near plane (for this version,
+	// Outerra states: "Notice that the 'C' variant doesn’t use a near plane distance, it has it
+	// set at 0" (quote from https://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html).
+	// Ulrich's variant has the benefit of constant relative precision over the whole near-far range.
+	// It was debated here whether Outerra's "C-constant" or Ulrich's "near plane" variant should
+	// be used, and ultimately Ulrich's "near plane" version was chosen.
+	// Outerra eventually made another improvement to their original "C-constant" variant,
+	// but it still does not incorporate the camera near plane (for this version,
 	// see https://outerra.blogspot.com/2013/07/logarithmic-depth-buffer-optimizations.html).
-	near = near.max( 1e-6 ); // <-- clamp so we don't divide by 0
-	const numerator = log2( perspectiveW.div( near ) );
-	const denominator = log2( far.div( near ) );
-	// The only modification we make to Ulrich's formula is
-	// adding 1 to the final depth value and dividing by 2.
-	return numerator.div( denominator ).add( 1 ).div( 2 );
+	// Here we make 4 changes to Ulrich's formula:
+	// 1. Clamp the camera near plane so we don't divide by 0.
+	// 2. Use log2 instead of log to avoid an extra multiply (shaders implement log using log2).
+	// 3. Assume K is 1 (K = maximum value in depth buffer; see Ulrich's formula above).
+	// 4. Add 1 to each division by cameraNear to ensure the depth curve is shifted to the left as cameraNear increases.
+	// For visual representation of this depth curve, see https://www.desmos.com/calculator/lz5rqfysih
+	near = near.max( 1e-6 ).toVar();
+	const numerator = log2( perspectiveW.div( near ).add( 1 ) );
+	const denominator = log2( far.div( near ).add( 1 ) );
+	return numerator.div( denominator );
 
 };
 

+ 1 - 1
src/nodes/lighting/AnalyticLightNode.js

@@ -337,7 +337,7 @@ class AnalyticLightNode extends LightingNode {
 
 				// The normally available "cameraNear" and "cameraFar" nodes cannot be used here because they do not get
 				// updated to use the shadow camera. So, we have to declare our own "local" ones here.
-				// TODO: Can we fix cameraNear/cameraFar in src/nodes/accessors/Camera.js so we don't have to declare local ones here?
+				// TODO: How do we get the cameraNear/cameraFar nodes to use the shadow camera so we don't have to declare local ones here?
 				const cameraNearLocal = uniform( 'float' ).onRenderUpdate( () => shadow.camera.near );
 				const cameraFarLocal = uniform( 'float' ).onRenderUpdate( () => shadow.camera.far );
 

粤ICP备19079148号