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

WebGPU: Logarithmic Depth Buffer Rename/Revision + GTAONode Fixes (#29870)

* 1. Renamed the function 'perspectiveDepthToLogarithmicDepth' to 'viewZToLogarithmicDepth' and modified it to expect a negative viewZ value in order maintain consistency with 'viewZToOrthographicDepth' and 'viewZToPerspectiveDepth'
2. Added function 'logarithmicDepthToViewZ'
3. Fixed AO not working when 'logarithmicDepthBuffer' is true

* Update GTAONode.js

Clean up.

* Update ShadowNode.js

Clean up.

* Update ShadowNode.js

Add `setGroup()`.

* Update ShadowNode.js

---------

Co-authored-by: Michael Herzog <michael.herzog@human-interactive.org>
PoseidonEnergy 1 год назад
Родитель
Сommit
485f7f0826

+ 20 - 2
examples/jsm/tsl/display/GTAONode.js

@@ -1,5 +1,5 @@
 import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3 } from 'three';
-import { getNormalFromDepth, getScreenPosition, getViewPosition, QuadMesh, TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp, NodeMaterial, PostProcessingUtils } from 'three/tsl';
+import { reference, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getNormalFromDepth, getScreenPosition, getViewPosition, QuadMesh, TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp, NodeMaterial, PostProcessingUtils } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
 const _size = /*@__PURE__*/ new Vector2();
@@ -27,6 +27,9 @@ class GTAONode extends TempNode {
 
 		this.resolutionScale = 1;
 
+		this.cameraNear = reference( 'near', 'float', camera );
+		this.cameraFar = reference( 'far', 'float', camera );
+
 		this.radius = uniform( 0.25 );
 		this.resolution = uniform( new Vector2() );
 		this.thickness = uniform( 1 );
@@ -107,7 +110,22 @@ class GTAONode extends TempNode {
 
 		const uvNode = uv();
 
-		const sampleDepth = ( uv ) => this.depthNode.uv( uv ).x;
+		const sampleDepth = ( uv ) => {
+
+			const depth = this.depthNode.uv( uv ).x;
+
+			if ( builder.renderer.logarithmicDepthBuffer === true ) {
+
+				const viewZ = logarithmicDepthToViewZ( depth, this.cameraNear, this.cameraFar );
+
+				return viewZToPerspectiveDepth( viewZ, this.cameraNear, this.cameraFar );
+
+			}
+
+			return depth;
+
+		};
+
 		const sampleNoise = ( uv ) => this._noiseNode.uv( uv );
 		const sampleNormal = ( uv ) => ( this.normalNode !== null ) ? this.normalNode.uv( uv ).rgb.normalize() : getNormalFromDepth( uv, this.depthNode.value, this._cameraProjectionMatrixInverse );
 

+ 2 - 2
src/materials/nodes/NodeMaterial.js

@@ -18,7 +18,7 @@ import { float, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
 import AONode from '../../nodes/lighting/AONode.js';
 import { lightingContext } from '../../nodes/lighting/LightingContextNode.js';
 import IrradianceNode from '../../nodes/lighting/IrradianceNode.js';
-import { depth, perspectiveDepthToLogarithmicDepth, viewZToOrthographicDepth } from '../../nodes/display/ViewportDepthNode.js';
+import { depth, viewZToLogarithmicDepth, viewZToOrthographicDepth } from '../../nodes/display/ViewportDepthNode.js';
 import { cameraFar, cameraNear } from '../../nodes/accessors/Camera.js';
 import { clipping, clippingAlpha, hardwareClipping } from '../../nodes/accessors/ClippingNode.js';
 import NodeMaterialObserver from './manager/NodeMaterialObserver.js';
@@ -285,7 +285,7 @@ class NodeMaterial extends Material {
 
 				if ( camera.isPerspectiveCamera ) {
 
-					depthNode = perspectiveDepthToLogarithmicDepth( modelViewProjection().w, cameraNear, cameraFar );
+					depthNode = viewZToLogarithmicDepth( positionView.z, cameraNear, cameraFar );
 
 				} else {
 

+ 21 - 6
src/nodes/display/ViewportDepthNode.js

@@ -1,5 +1,5 @@
 import Node from '../core/Node.js';
-import { log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
+import { float, log, log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
 import { cameraNear, cameraFar } from '../accessors/Camera.js';
 import { positionView } from '../accessors/Position.js';
 import { viewportDepthTexture } from './ViewportDepthTextureNode.js';
@@ -116,8 +116,10 @@ export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ )
 // maps perspective depth in [ 0, 1 ] to viewZ
 export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) );
 
-export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) => {
+// -near maps to 0; -far maps to 1
+export const viewZToLogarithmicDepth = ( viewZ, near, far ) => {
 
+	// NOTE: viewZ must be negative--see explanation at the end of this comment block.
 	// 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
@@ -139,15 +141,28 @@ export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) =>
 	// 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
+	// 4. To maintain consistency with the functions "viewZToOrthographicDepth" and "viewZToPerspectiveDepth",
+	//    we modify the formula here to use 'viewZ' instead of 'w'. The other functions expect a negative viewZ,
+	//    so we do the same here, hence the 'viewZ.negate()' call.
+	// For visual representation of this depth curve, see https://www.desmos.com/calculator/uyqk0vex1u
 	near = near.max( 1e-6 ).toVar();
-	const numerator = log2( perspectiveW.div( near ).add( 1 ) );
-	const denominator = log2( far.div( near ).add( 1 ) );
+	const numerator = log2( viewZ.negate().div( near ) );
+	const denominator = log2( far.div( near ) );
 	return numerator.div( denominator );
 
 };
 
+// maps logarithmic depth in [ 0, 1 ] to viewZ
+export const logarithmicDepthToViewZ = ( depth, near, far ) => {
+
+	// NOTE: we add a 'negate()' call to the return value here to maintain consistency with
+	// the functions "orthographicDepthToViewZ" and "perspectiveDepthToViewZ" (they return
+	// a negative viewZ).
+	const exponent = depth.mul( log( far.div( near ) ) );
+	return float( Math.E ).pow( exponent ).mul( near ).negate();
+
+};
+
 const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE );
 
 export const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH );

+ 4 - 4
src/nodes/lighting/ShadowNode.js

@@ -15,7 +15,7 @@ import { Loop } from '../utils/LoopNode.js';
 import { screenCoordinate } from '../display/ScreenNode.js';
 import { HalfFloatType, LessCompare, RGFormat, VSMShadowMap, WebGPUCoordinateSystem } from '../../constants.js';
 import { renderGroup } from '../core/UniformGroupNode.js';
-import { perspectiveDepthToLogarithmicDepth } from '../display/ViewportDepthNode.js';
+import { viewZToLogarithmicDepth } from '../display/ViewportDepthNode.js';
 
 const BasicShadowMap = Fn( ( { depthTexture, shadowCoord } ) => {
 
@@ -313,10 +313,10 @@ class ShadowNode extends Node {
 			// 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: 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 );
+			const cameraNearLocal = reference( 'near', 'float', shadow.camera ).setGroup( renderGroup );
+			const cameraFarLocal = reference( 'far', 'float', shadow.camera ).setGroup( renderGroup );
 
-			coordZ = perspectiveDepthToLogarithmicDepth( w, cameraNearLocal, cameraFarLocal );
+			coordZ = viewZToLogarithmicDepth( w.negate(), cameraNearLocal, cameraFarLocal );
 
 		}
 

粤ICP备19079148号