Jelajahi Sumber

SSRNode: Performance optimizations. (#32637)

mrdoob 4 bulan lalu
induk
melakukan
48f8bdee95
2 mengubah file dengan 22 tambahan dan 20 penghapusan
  1. 6 5
      examples/jsm/shaders/SSRShader.js
  2. 16 15
      examples/jsm/tsl/display/SSRNode.js

+ 6 - 5
examples/jsm/shaders/SSRShader.js

@@ -96,7 +96,7 @@ const SSRShader = {
 			float x0=point.x,y0=point.y,z0=point.z;
 			float x=planePoint.x,y=planePoint.y,z=planePoint.z;
 			float d=-(a*x+b*y+c*z);
-			float distance=(a*x0+b*y0+c*z0+d)/sqrt(a*a+b*b+c*c);
+			float distance=a*x0+b*y0+c*z0+d;
 			return distance;
 		}
 		float getDepth( const in vec2 uv ) {
@@ -170,17 +170,17 @@ const SSRShader = {
 			#endif
 			d1=viewPositionToXY(d1viewPosition);
 
-			float totalLen=length(d1-d0);
 			float xLen=d1.x-d0.x;
 			float yLen=d1.y-d0.y;
 			float totalStep=max(abs(xLen),abs(yLen));
 			float xSpan=xLen/totalStep;
 			float ySpan=yLen/totalStep;
-			for(float i=0.;i<float(MAX_STEP);i++){
+			float sStep=1./totalStep;
+			float s=sStep; // start at sStep since loop starts at i=1
+			for(float i=1.;i<float(MAX_STEP);i++){
 				if(i>=totalStep) break;
 				vec2 xy=vec2(d0.x+i*xSpan,d0.y+i*ySpan);
 				if(xy.x<0.||xy.x>resolution.x||xy.y<0.||xy.y>resolution.y) break;
-				float s=length(xy-d0)/totalLen;
 				vec2 uv=xy/resolution;
 
 				float d = getDepth(uv);
@@ -221,7 +221,7 @@ const SSRShader = {
 
 					if(hit){
 						vec3 vN=getViewNormal( uv );
-						if(dot(viewReflectDir,vN)>=0.) continue;
+						if(dot(viewReflectDir,vN)>=0.) break; // treat backfaces as opaque
 						float distance=pointPlaneDistance(vP,viewPosition,viewNormal);
 						if(distance>maxDistance) break;
 						float op=opacity;
@@ -240,6 +240,7 @@ const SSRShader = {
 						break;
 					}
 				}
+				s+=sStep;
 			}
 		}
 	`

+ 16 - 15
examples/jsm/tsl/display/SSRNode.js

@@ -1,5 +1,5 @@
 import { HalfFloatType, RenderTarget, Vector2, RendererUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType, LinearFilter, LinearMipmapLinearFilter } from 'three/webgpu';
-import { texture, reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl';
+import { texture, reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, mul, div, cross, float, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl';
 import { boxBlur } from './boxBlur.js';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
@@ -400,9 +400,7 @@ class SSRNode extends TempNode {
 			// http://paulbourke.net/geometry/pointlineplane/
 
 			const d = mul( planeNormal.x, planePoint.x ).add( mul( planeNormal.y, planePoint.y ) ).add( mul( planeNormal.z, planePoint.z ) ).negate().toVar();
-
-			const denominator = sqrt( mul( planeNormal.x, planeNormal.x, ).add( mul( planeNormal.y, planeNormal.y ) ).add( mul( planeNormal.z, planeNormal.z ) ) ).toVar();
-			const distance = div( mul( planeNormal.x, point.x ).add( mul( planeNormal.y, point.y ) ).add( mul( planeNormal.z, point.z ) ).add( d ), denominator );
+			const distance = mul( planeNormal.x, point.x ).add( mul( planeNormal.y, point.y ) ).add( mul( planeNormal.z, point.z ) ).add( d );
 			return distance;
 
 		} );
@@ -481,9 +479,6 @@ class SSRNode extends TempNode {
 
 			// below variables are used to control the raymarching process
 
-			// total length of the ray
-			const totalLen = d1.sub( d0 ).length().toVar();
-
 			// offset in x and y direction
 			const xLen = d1.x.sub( d0.x ).toVar();
 			const yLen = d1.y.sub( d0.y ).toVar();
@@ -491,7 +486,9 @@ class SSRNode extends TempNode {
 			// determine the larger delta
 			// The larger difference will help to determine how much to travel in the X and Y direction each iteration and
 			// how many iterations are needed to travel the entire ray
-			const totalStep = int( max( abs( xLen ), abs( yLen ) ).mul( this.quality.clamp() ) ).toConst();
+			// scale step count by distance - distant surfaces need less precision (0.5 to 1.0 multiplier)
+			const distanceFactor = float( 1 ).sub( depth.mul( 0.5 ) ).clamp( 0.5, 1 );
+			const totalStep = int( max( abs( xLen ), abs( yLen ) ).mul( this.quality.clamp() ).mul( distanceFactor ) ).toConst();
 
 			// step sizes in the x and y directions
 			const xSpan = xLen.div( totalStep ).toVar();
@@ -499,10 +496,14 @@ class SSRNode extends TempNode {
 
 			const output = vec4( 0 ).toVar();
 
+			// incremental interpolation factor
+			const sStep = float( 1 ).div( float( totalStep ) );
+			const s = sStep.toVar(); // start at sStep since loop starts at i=1
+
 			// the actual ray marching loop
 			// starting from d0, the code gradually travels along the ray and looks for an intersection with the geometry.
 			// it does not exceed d1 (the maximum ray extend)
-			Loop( totalStep, ( { i } ) => {
+			Loop( { start: int( 1 ), end: totalStep }, ( { i } ) => {
 
 				// advance on the ray by computing a new position in screen coordinates
 				const xy = vec2( d0.x.add( xSpan.mul( float( i ) ) ), d0.y.add( ySpan.mul( float( i ) ) ) ).toVar();
@@ -521,9 +522,6 @@ class SSRNode extends TempNode {
 
 				const viewReflectRayZ = float( 0 ).toVar();
 
-				// normalized distance between the current position xy and the starting point d0
-				const s = xy.sub( d0 ).length().div( totalLen );
-
 				// depending on the camera type, we now compute the z-coordinate of the reflected ray at the current step in view space
 				If( this._isPerspectiveCamera, () => {
 
@@ -559,9 +557,9 @@ class SSRNode extends TempNode {
 
 						If( dot( viewReflectDir, vN ).greaterThanEqual( 0 ), () => {
 
-							// the reflected ray is pointing towards the same side as the fragment's normal (current ray position),
-							// which means it wouldn't reflect off the surface. The loop continues to the next step for the next ray sample.
-							Continue();
+							// the reflected ray is hitting a backface (normal pointing away from ray),
+							// treat as opaque surface that blocks the ray
+							Break();
 
 						} );
 
@@ -596,6 +594,9 @@ class SSRNode extends TempNode {
 
 				} );
 
+				// advance interpolation factor
+				s.addAssign( sStep );
+
 			} );
 
 			return output;

粤ICP备19079148号