2
0
Эх сурвалжийг харах

SSRPass: Correct Reflector depth. (#21403)

* SSRPassCorrectReflectorDepth

* Fix? or bypass? large groundReflector edge viewing problem.

* Renaming & some clean up.

* Rename all words prefixed with `is`.
Make `defines` all uppercase.

* Resolve Conflicts.
Vis 4 жил өмнө
parent
commit
07e58027cd

+ 103 - 66
examples/jsm/objects/ReflectorForSSRPass.js

@@ -9,6 +9,7 @@ import {
 	RGBFormat,
 	ShaderMaterial,
 	UniformsUtils,
+	Vector2,
 	Vector3,
 	Vector4,
 	WebGLRenderTarget,
@@ -17,11 +18,11 @@ import {
 	NearestFilter
 } from '../../../build/three.module.js';
 
-var Reflector = function ( geometry, options ) {
+var ReflectorForSSRPass = function ( geometry, options ) {
 
 	Mesh.call( this, geometry );
 
-	this.type = 'Reflector';
+	this.type = 'ReflectorForSSRPass';
 
 	var scope = this;
 
@@ -31,7 +32,7 @@ var Reflector = function ( geometry, options ) {
 	var textureWidth = options.textureWidth || 512;
 	var textureHeight = options.textureHeight || 512;
 	var clipBias = options.clipBias || 0;
-	var shader = options.shader || Reflector.ReflectorShader;
+	var shader = options.shader || ReflectorForSSRPass.ReflectorShader;
 	var useDepthTexture = options.useDepthTexture === true;
 	var yAxis = new Vector3( 0, 1, 0 );
 	var vecTemp0 = new Vector3();
@@ -40,41 +41,36 @@ var Reflector = function ( geometry, options ) {
 	//
 
 	scope.needsUpdate = false;
-	scope.maxDistance = Reflector.ReflectorShader.uniforms.maxDistance.value;
-	scope.opacity = Reflector.ReflectorShader.uniforms.opacity.value;
+	scope.maxDistance = ReflectorForSSRPass.ReflectorShader.uniforms.maxDistance.value;
+	scope.opacity = ReflectorForSSRPass.ReflectorShader.uniforms.opacity.value;
 	scope.color = color;
+	scope.worldYBias = options.worldYBias || 0;
+	scope.resolution = options.resolution || new Vector2( window.innerWidth, window.innerHeight );
 
-	scope._isDistanceAttenuation = Reflector.ReflectorShader.defines.isDistanceAttenuation;
-	Object.defineProperty( scope, 'isDistanceAttenuation', {
-		get() {
-
-			return scope._isDistanceAttenuation;
 
+	scope._distanceAttenuation = ReflectorForSSRPass.ReflectorShader.defines.DISTANCE_ATTENUATION;
+	Object.defineProperty( scope, 'distanceAttenuation', {
+		get() {
+			return scope._distanceAttenuation;
 		},
 		set( val ) {
-
-			if ( scope._isDistanceAttenuation === val ) return;
-			scope._isDistanceAttenuation = val;
-			scope.material.defines.isDistanceAttenuation = val;
+			if ( scope._distanceAttenuation === val ) return;
+			scope._distanceAttenuation = val;
+			scope.material.defines.DISTANCE_ATTENUATION = val;
 			scope.material.needsUpdate = true;
-
 		}
 	} );
 
-	scope._isFresnel = Reflector.ReflectorShader.defines.isFresnel;
-	Object.defineProperty( scope, 'isFresnel', {
+	scope._fresnel = ReflectorForSSRPass.ReflectorShader.defines.FRESNEL;
+	Object.defineProperty( scope, 'fresnel', {
 		get() {
-
-			return scope._isFresnel;
-
+			return scope._fresnel;
 		},
 		set( val ) {
-
-			if ( scope._isFresnel === val ) return;
-			scope._isFresnel = val;
-			scope.material.defines.isFresnel = val;
+			if ( scope._fresnel === val ) return;
+			scope._fresnel = val;
+			scope.material.defines.FRESNEL = val;
 			scope.material.needsUpdate = true;
-
 		}
 	} );
 
@@ -98,7 +94,7 @@ var Reflector = function ( geometry, options ) {
 		var depthTexture = new DepthTexture();
 		depthTexture.type = UnsignedShortType;
 		depthTexture.minFilter = NearestFilter;
-		depthTexture.maxFilter = NearestFilter;
+		depthTexture.magFilter = NearestFilter;
 
 	}
 
@@ -119,7 +115,7 @@ var Reflector = function ( geometry, options ) {
 
 	var material = new ShaderMaterial( {
 		transparent: useDepthTexture,
-		defines: Object.assign( {}, Reflector.ReflectorShader.defines, {
+		defines: Object.assign( {}, ReflectorForSSRPass.ReflectorShader.defines, {
 			useDepthTexture
 		} ),
 		uniforms: UniformsUtils.clone( shader.uniforms ),
@@ -140,18 +136,14 @@ var Reflector = function ( geometry, options ) {
 
 	this.doRender = function ( renderer, scene, camera ) {
 
-		material.uniforms[ 'maxDistance' ].value = scope.maxDistance * ( camera.position.length() / camera.position.y );
-		///todo: Temporary hack,
-		// need precise calculation like this https://github.com/mrdoob/three.js/pull/20156/commits/8181946068e386d14a283cbd4f8877bc7ae066d3 ,
-		// after fully understand http://www.terathon.com/lengyel/Lengyel-Oblique.pdf .
-
+		material.uniforms[ 'maxDistance' ].value = scope.maxDistance;
 		material.uniforms[ 'color' ].value = scope.color;
 		material.uniforms[ 'opacity' ].value = scope.opacity;
+		material.uniforms[ 'worldYBias' ].value = scope.worldYBias;
 
 		vecTemp0.copy( camera.position ).normalize();
 		vecTemp1.copy( vecTemp0 ).reflect( yAxis );
-		material.uniforms[ 'fresnel' ].value = ( vecTemp0.dot( vecTemp1 ) + 1. ) / 2.; ///todo: Also need to use glsl viewPosition and viewNormal per pixel.
-		// console.log(material.uniforms['fresnel'].value)
+		material.uniforms[ 'fresnelCoe' ].value = ( vecTemp0.dot( vecTemp1 ) + 1. ) / 2.; // TODO: Also need to use glsl viewPosition and viewNormal per pixel.
 
 		reflectorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
 		cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
@@ -191,6 +183,13 @@ var Reflector = function ( geometry, options ) {
 		virtualCamera.updateMatrixWorld();
 		virtualCamera.projectionMatrix.copy( camera.projectionMatrix );
 
+		material.uniforms[ 'virtualCameraNear' ].value = virtualCamera.near;
+		material.uniforms[ 'virtualCameraFar' ].value = virtualCamera.far;
+		material.uniforms[ 'virtualCameraMatrixWorld' ].value= virtualCamera.matrixWorld;
+		material.uniforms[ 'virtualCameraProjectionMatrix' ].value= virtualCamera.projectionMatrix;
+		material.uniforms[ 'virtualCameraInverseProjectionMatrix' ].value= virtualCamera.projectionMatrixInverse;
+		material.uniforms[ 'resolution' ].value = scope.resolution;
+
 		// Update the texture matrix
 		textureMatrix.set(
 			0.5, 0.0, 0.0, 0.5,
@@ -202,28 +201,32 @@ var Reflector = function ( geometry, options ) {
 		textureMatrix.multiply( virtualCamera.matrixWorldInverse );
 		textureMatrix.multiply( scope.matrixWorld );
 
-		// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
-		// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
-		reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition );
-		reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );
+		/* Note: For the sake of accurate tDepth, temporarily turned off this Oblique Near-Plane Clipping feature. https://github.com/mrdoob/three.js/pull/21403
+
+			// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
+			// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
+			reflectorPlane.setFromNormalAndCoplanarPoint( normal, reflectorWorldPosition );
+			reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );
 
-		clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant );
+			clipPlane.set( reflectorPlane.normal.x, reflectorPlane.normal.y, reflectorPlane.normal.z, reflectorPlane.constant );
 
-		var projectionMatrix = virtualCamera.projectionMatrix;
+			var projectionMatrix = virtualCamera.projectionMatrix;
 
-		q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
-		q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
-		q.z = - 1.0;
-		q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
+			q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
+			q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
+			q.z = - 1.0;
+			q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
 
-		// Calculate the scaled plane vector
-		clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
+			// Calculate the scaled plane vector
+			clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
 
-		// Replacing the third row of the projection matrix
-		projectionMatrix.elements[ 2 ] = clipPlane.x;
-		projectionMatrix.elements[ 6 ] = clipPlane.y;
-		projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
-		projectionMatrix.elements[ 14 ] = clipPlane.w;
+			// Replacing the third row of the projection matrix
+			projectionMatrix.elements[ 2 ] = clipPlane.x;
+			projectionMatrix.elements[ 6 ] = clipPlane.y;
+			projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
+			projectionMatrix.elements[ 14 ] = clipPlane.w;
+
+		*/
 
 		// Render
 
@@ -273,14 +276,14 @@ var Reflector = function ( geometry, options ) {
 
 };
 
-Reflector.prototype = Object.create( Mesh.prototype );
-Reflector.prototype.constructor = Reflector;
+ReflectorForSSRPass.prototype = Object.create( Mesh.prototype );
+ReflectorForSSRPass.prototype.constructor = ReflectorForSSRPass;
 
-Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?
+ReflectorForSSRPass.ReflectorShader = {
 
 	defines: {
-		isDistanceAttenuation: true,
-		isFresnel: true,
+		DISTANCE_ATTENUATION: true,
+		FRESNEL: true,
 	},
 
 	uniforms: {
@@ -288,10 +291,17 @@ Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?
 		color: { value: null },
 		tDiffuse: { value: null },
 		tDepth: { value: null },
-		textureMatrix: { value: null },
+		textureMatrix: { value: new Matrix4() },
 		maxDistance: { value: 180 },
 		opacity: { value: 0.5 },
-		fresnel: { value: null },
+		fresnelCoe: { value: null },
+		worldYBias: { value: null },
+		virtualCameraNear: { value: null },
+		virtualCameraFar: { value: null },
+		virtualCameraProjectionMatrix: { value: new Matrix4() },
+		virtualCameraMatrixWorld: { value: new Matrix4() },
+		virtualCameraInverseProjectionMatrix: { value: new Matrix4() },
+		resolution: { value: new Vector2() },
 
 	},
 
@@ -314,27 +324,54 @@ Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?
 		uniform sampler2D tDepth;
 		uniform float maxDistance;
 		uniform float opacity;
-		uniform float fresnel;
+		uniform float fresnelCoe;
+		uniform float worldYBias;
+		uniform float virtualCameraNear;
+		uniform float virtualCameraFar;
+		uniform mat4 virtualCameraProjectionMatrix;
+		uniform mat4 virtualCameraInverseProjectionMatrix;
+		uniform mat4 virtualCameraMatrixWorld;
+		uniform vec2 resolution;
 		varying vec4 vUv;
+		#include <packing>
 		float blendOverlay( float base, float blend ) {
 			return( base < 0.5 ? ( 2.0 * base * blend ) : ( 1.0 - 2.0 * ( 1.0 - base ) * ( 1.0 - blend ) ) );
 		}
 		vec3 blendOverlay( vec3 base, vec3 blend ) {
 			return vec3( blendOverlay( base.r, blend.r ), blendOverlay( base.g, blend.g ), blendOverlay( base.b, blend.b ) );
 		}
+		float getDepth( const in vec2 uv ) {
+			return texture2D( tDepth, uv ).x;
+		}
+		float getViewZ( const in float depth ) {
+			return perspectiveDepthToViewZ( depth, virtualCameraNear, virtualCameraFar );
+		}
+		vec3 getViewPosition( const in vec2 uv, const in float depth/*clip space*/, const in float clipW ) {
+			vec4 clipPosition = vec4( ( vec3( uv, depth ) - 0.5 ) * 2.0, 1.0 );//ndc
+			clipPosition *= clipW; //clip
+			return ( virtualCameraInverseProjectionMatrix * clipPosition ).xyz;//view
+		}
 		void main() {
 			vec4 base = texture2DProj( tDiffuse, vUv );
 			#ifdef useDepthTexture
-				float op=opacity;
+				vec2 uv=(gl_FragCoord.xy-.5)/resolution.xy;
+				uv.x=1.-uv.x;
 				float depth = texture2DProj( tDepth, vUv ).r;
-				if(depth>maxDistance) discard;
-				#ifdef isDistanceAttenuation
-					float ratio=1.-(depth/maxDistance);
+				float viewZ = getViewZ( depth );
+				float clipW = virtualCameraProjectionMatrix[2][3] * viewZ+virtualCameraProjectionMatrix[3][3];
+				vec3 viewPosition=getViewPosition( uv, depth, clipW );
+				vec3 worldPosition=(virtualCameraMatrixWorld*vec4(viewPosition,1)).xyz;
+				worldPosition.y+=worldYBias; // TODO: Don't know why not start from zero, temporarily use manually defined bias, need fix afterwards.
+				worldPosition.y=max(0.,worldPosition.y);
+				if(worldPosition.y>maxDistance) discard;
+				float op=opacity;
+				#ifdef DISTANCE_ATTENUATION
+					float ratio=1.-(worldPosition.y/maxDistance);
 					float attenuation=ratio*ratio;
 					op=opacity*attenuation;
 				#endif
-				#ifdef isFresnel
-					op*=fresnel;
+				#ifdef FRESNEL
+					op*=fresnelCoe;
 				#endif
 				gl_FragColor = vec4( blendOverlay( base.rgb, color ), op );
 			#else
@@ -344,4 +381,4 @@ Reflector.ReflectorShader = { ///todo: Will conflict with Reflector.js?
 	`,
 };
 
-export { Reflector };
+export { ReflectorForSSRPass };

+ 42 - 58
examples/jsm/postprocessing/SSRPass.js

@@ -23,7 +23,7 @@ import { SSRBlurShader } from '../shaders/SSRShader.js';
 import { SSRDepthShader } from '../shaders/SSRShader.js';
 import { CopyShader } from '../shaders/CopyShader.js';
 
-var SSRPass = function ( { renderer, scene, camera, width, height, selects, encoding, isPerspectiveCamera = true, isBouncing = false, morphTargets = false, groundReflector } ) {
+var SSRPass = function ( { renderer, scene, camera, width, height, selects, encoding, bouncing = false, morphTargets = false, groundReflector } ) {
 
 	Pass.call( this );
 
@@ -48,7 +48,7 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 	this.tempColor = new Color();
 
 	this._selects = selects;
-	this.isSelective = Array.isArray( this._selects );
+	this.selective = Array.isArray( this._selects );
 	Object.defineProperty( this, 'selects', {
 		get() {
 
@@ -61,14 +61,14 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 			this._selects = val;
 			if ( Array.isArray( val ) ) {
 
-				this.isSelective = true;
-				this.ssrMaterial.defines.isSelective = true;
+				this.selective = true;
+				this.ssrMaterial.defines.SELECTIVE = true;
 				this.ssrMaterial.needsUpdate = true;
 
 			} else {
 
-				this.isSelective = false;
-				this.ssrMaterial.defines.isSelective = false;
+				this.selective = false;
+				this.ssrMaterial.defines.SELECTIVE = false;
 				this.ssrMaterial.needsUpdate = true;
 
 			}
@@ -76,17 +76,17 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 		}
 	} );
 
-	this._isBouncing = isBouncing; ///todo: don't need defineProperty
-	Object.defineProperty( this, 'isBouncing', {
+	this._bouncing = bouncing;
+	Object.defineProperty( this, 'bouncing', {
 		get() {
 
-			return this._isBouncing;
+			return this._bouncing;
 
 		},
 		set( val ) {
 
-			if ( this._isBouncing === val ) return;
-			this._isBouncing = val;
+			if ( this._bouncing === val ) return;
+			this._bouncing = val;
 			if ( val ) {
 
 				this.ssrMaterial.uniforms[ 'tDiffuse' ].value = this.prevRenderTarget.texture;
@@ -100,55 +100,55 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 		}
 	} );
 
-	this.isBlur = true;
+	this.blur = true;
 
-	this._isDistanceAttenuation = SSRShader.defines.isDistanceAttenuation;
-	Object.defineProperty( this, 'isDistanceAttenuation', {
+	this._distanceAttenuation = SSRShader.defines.DISTANCE_ATTENUATION;
+	Object.defineProperty( this, 'distanceAttenuation', {
 		get() {
 
-			return this._isDistanceAttenuation;
+			return this._distanceAttenuation;
 
 		},
 		set( val ) {
 
-			if ( this._isDistanceAttenuation === val ) return;
-			this._isDistanceAttenuation = val;
-			this.ssrMaterial.defines.isDistanceAttenuation = val;
+			if ( this._distanceAttenuation === val ) return;
+			this._distanceAttenuation = val;
+			this.ssrMaterial.defines.DISTANCE_ATTENUATION = val;
 			this.ssrMaterial.needsUpdate = true;
 
 		}
 	} );
 
 
-	this._isFresnel = SSRShader.defines.isFresnel;
-	Object.defineProperty( this, 'isFresnel', {
+	this._fresnel = SSRShader.defines.FRESNEL;
+	Object.defineProperty( this, 'fresnel', {
 		get() {
 
-			return this._isFresnel;
+			return this._fresnel;
 
 		},
 		set( val ) {
 
-			if ( this._isFresnel === val ) return;
-			this._isFresnel = val;
-			this.ssrMaterial.defines.isFresnel = val;
+			if ( this._fresnel === val ) return;
+			this._fresnel = val;
+			this.ssrMaterial.defines.FRESNEL = val;
 			this.ssrMaterial.needsUpdate = true;
 
 		}
 	} );
 
-	this._isInfiniteThick = SSRShader.defines.isInfiniteThick;
-	Object.defineProperty( this, 'isInfiniteThick', {
+	this._infiniteThick = SSRShader.defines.INFINITE_THICK;
+	Object.defineProperty( this, 'infiniteThick', {
 		get() {
 
-			return this._isInfiniteThick;
+			return this._infiniteThick;
 
 		},
 		set( val ) {
 
-			if ( this._isInfiniteThick === val ) return;
-			this._isInfiniteThick = val;
-			this.ssrMaterial.defines.isInfiniteThick = val;
+			if ( this._infiniteThick === val ) return;
+			this._infiniteThick = val;
+			this.ssrMaterial.defines.INFINITE_THICK = val;
 			this.ssrMaterial.needsUpdate = true;
 
 		}
@@ -160,7 +160,7 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 	var depthTexture = new DepthTexture();
 	depthTexture.type = UnsignedShortType;
 	depthTexture.minFilter = NearestFilter;
-	depthTexture.maxFilter = NearestFilter;
+	depthTexture.magFilter = NearestFilter;
 
 	this.beautyRenderTarget = new WebGLRenderTarget( this.width, this.height, {
 		minFilter: LinearFilter,
@@ -188,13 +188,11 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 
 	// metalness render target
 
-	// if (this.isSelective) {
 	this.metalnessRenderTarget = new WebGLRenderTarget( this.width, this.height, {
 		minFilter: NearestFilter,
 		magFilter: NearestFilter,
 		format: RGBAFormat
 	} );
-	// }
 
 
 
@@ -227,20 +225,12 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 		fragmentShader: SSRShader.fragmentShader,
 		blending: NoBlending
 	} );
-	if ( ! isPerspectiveCamera ) {
-
-		this.ssrMaterial.defines.isPerspectiveCamera = isPerspectiveCamera;
-		this.ssrMaterial.needsUpdate = true;
-
-	}
 
 	this.ssrMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
 	this.ssrMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
-	// if (this.isSelective) {
-	this.ssrMaterial.defines.isSelective = this.isSelective;
+	this.ssrMaterial.defines.SELECTIVE = this.selective;
 	this.ssrMaterial.needsUpdate = true;
 	this.ssrMaterial.uniforms[ 'tMetalness' ].value = this.metalnessRenderTarget.texture;
-	// }
 	this.ssrMaterial.uniforms[ 'tDepth' ].value = this.beautyRenderTarget.depthTexture;
 	this.ssrMaterial.uniforms[ 'cameraNear' ].value = this.camera.near;
 	this.ssrMaterial.uniforms[ 'cameraFar' ].value = this.camera.far;
@@ -254,7 +244,6 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 	this.normalMaterial = new MeshNormalMaterial( { morphTargets } );
 	this.normalMaterial.blending = NoBlending;
 
-	// if (this.isSelective) {
 	// metalnessOn material
 
 	this.metalnessOnMaterial = new MeshBasicMaterial( {
@@ -266,7 +255,6 @@ var SSRPass = function ( { renderer, scene, camera, width, height, selects, enco
 	this.metalnessOffMaterial = new MeshBasicMaterial( {
 		color: 'black'
 	} );
-	// }
 
 	// blur material
 
@@ -349,7 +337,6 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		this.beautyRenderTarget.dispose();
 		this.prevRenderTarget.dispose();
 		this.normalRenderTarget.dispose();
-		// if (this.isSelective)
 		this.metalnessRenderTarget.dispose();
 		this.ssrRenderTarget.dispose();
 		this.blurRenderTarget.dispose();
@@ -359,10 +346,8 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		// dispose materials
 
 		this.normalMaterial.dispose();
-		// if (this.isSelective) {
 		this.metalnessOnMaterial.dispose();
 		this.metalnessOffMaterial.dispose();
-		// }
 		this.blurMaterial.dispose();
 		this.blurMaterial2.dispose();
 		this.copyMaterial.dispose();
@@ -398,7 +383,7 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 
 		// render metalnesses
 
-		if ( this.isSelective ) {
+		if ( this.selective ) {
 
 			this.renderMetalness( renderer, this.metalnessOnMaterial, this.metalnessRenderTarget, 0, 0 );
 
@@ -415,7 +400,7 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 
 		// render blur
 
-		if ( this.isBlur ) {
+		if ( this.blur ) {
 
 			this.renderPass( renderer, this.blurMaterial, this.blurRenderTarget );
 			this.renderPass( renderer, this.blurMaterial2, this.blurRenderTarget2 );
@@ -429,13 +414,13 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 
 			case SSRPass.OUTPUT.Default:
 
-				if ( this.isBouncing ) {
+				if ( this.bouncing ) {
 
 					this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
 					this.copyMaterial.blending = NoBlending;
 					this.renderPass( renderer, this.copyMaterial, this.prevRenderTarget );
 
-					if ( this.isBlur )
+					if ( this.blur )
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget2.texture;
 					else
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssrRenderTarget.texture;
@@ -452,7 +437,7 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 					this.copyMaterial.blending = NoBlending;
 					this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
 
-					if ( this.isBlur )
+					if ( this.blur )
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget2.texture;
 					else
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssrRenderTarget.texture;
@@ -464,16 +449,16 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 				break;
 			case SSRPass.OUTPUT.SSR:
 
-				if ( this.isBlur )
+				if ( this.blur )
 					this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget2.texture;
 				else
 					this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.ssrRenderTarget.texture;
 				this.copyMaterial.blending = NoBlending;
 				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
 
-				if ( this.isBouncing ) {
+				if ( this.bouncing ) {
 
-					if ( this.isBlur )
+					if ( this.blur )
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.blurRenderTarget2.texture;
 					else
 						this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
@@ -608,7 +593,7 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 
 		this.scene.traverseVisible( child => {
 
-			child._SSRPassMaterialBack = child.material;
+			child._SSRPassBackupMaterial = child.material;
 			if ( this._selects.includes( child ) ) {
 
 				child.material = this.metalnessOnMaterial;
@@ -623,7 +608,7 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		renderer.render( this.scene, this.camera );
 		this.scene.traverseVisible( child => {
 
-			child.material = child._SSRPassMaterialBack;
+			child.material = child._SSRPassBackupMaterial;
 
 		} );
 
@@ -646,7 +631,6 @@ SSRPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		this.prevRenderTarget.setSize( width, height );
 		this.ssrRenderTarget.setSize( width, height );
 		this.normalRenderTarget.setSize( width, height );
-		// if (this.isSelective)
 		this.metalnessRenderTarget.setSize( width, height );
 		this.blurRenderTarget.setSize( width, height );
 		this.blurRenderTarget2.setSize( width, height );

+ 20 - 20
examples/jsm/shaders/SSRShader.js

@@ -11,11 +11,11 @@ var SSRShader = {
 
   defines: {
     MAX_STEP: 0,
-    isPerspectiveCamera: true,
-    isDistanceAttenuation: true,
-    isFresnel: true,
-    isInfiniteThick: false,
-    isSelective: false,
+    PERSPECTIVE_CAMERA: true,
+    DISTANCE_ATTENUATION: true,
+    FRESNEL: true,
+    INFINITE_THICK: false,
+    SELECTIVE: false,
   },
 
   uniforms: {
@@ -90,7 +90,7 @@ var SSRShader = {
 			return texture2D( tDepth, uv ).x;
 		}
 		float getViewZ( const in float depth ) {
-			#ifdef isPerspectiveCamera
+			#ifdef PERSPECTIVE_CAMERA
 				return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
 			#else
 				return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
@@ -115,7 +115,7 @@ var SSRShader = {
 			return xy;
 		}
 		void main(){
-			#ifdef isSelective
+			#ifdef SELECTIVE
 				float metalness=texture2D(tMetalness,vUv).r;
 				if(metalness==0.) return;
 			#endif
@@ -132,15 +132,15 @@ var SSRShader = {
 
 			vec3 viewNormal=getViewNormal( vUv );
 
-			#ifdef isPerspectiveCamera
-				vec3 viewIncidenceDir=normalize(viewPosition);
-				vec3 viewReflectDir=reflect(viewIncidenceDir,viewNormal);
+			#ifdef PERSPECTIVE_CAMERA
+				vec3 viewIncidentDir=normalize(viewPosition);
+				vec3 viewReflectDir=reflect(viewIncidentDir,viewNormal);
 			#else
-				vec3 viewIncidenceDir=vec3(0,0,-1);
-				vec3 viewReflectDir=reflect(viewIncidenceDir,viewNormal);
+				vec3 viewIncidentDir=vec3(0,0,-1);
+				vec3 viewReflectDir=reflect(viewIncidentDir,viewNormal);
 			#endif
 
-			float maxReflectRayLen=maxDistance/dot(-viewIncidenceDir,viewNormal);
+			float maxReflectRayLen=maxDistance/dot(-viewIncidentDir,viewNormal);
 			// dot(a,b)==length(a)*length(b)*cos(theta) // https://www.mathsisfun.com/algebra/vectors-dot-product.html
 			// if(a.isNormalized&&b.isNormalized) dot(a,b)==cos(theta)
 			// maxDistance/maxReflectRayLen=cos(theta)
@@ -148,7 +148,7 @@ var SSRShader = {
 			// maxReflectRayLen==maxDistance/dot(a,b)
 
 			vec3 d1viewPosition=viewPosition+viewReflectDir*maxReflectRayLen;
-			#ifdef isPerspectiveCamera
+			#ifdef PERSPECTIVE_CAMERA
 				if(d1viewPosition.z>-cameraNear){
 					//https://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfLines.aspx
 					float t=(-cameraNear-viewPosition.z)/viewReflectDir.z;
@@ -176,7 +176,7 @@ var SSRShader = {
 				float cW = cameraProjectionMatrix[2][3] * vZ+cameraProjectionMatrix[3][3];
 				vec3 vP=getViewPosition( uv, d, cW );
 
-				#ifdef isPerspectiveCamera
+				#ifdef PERSPECTIVE_CAMERA
 					// https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
 					float recipVPZ=1./viewPosition.z;
 					float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ));
@@ -187,7 +187,7 @@ var SSRShader = {
 				#endif
 				if(viewReflectRayZ-sD>vZ) continue;
 
-				#ifdef isInfiniteThick
+				#ifdef INFINITE_THICK
 					if(viewReflectRayZ+thickTolerance*clipW<vP.z) break;
 				#endif
 				float away=pointToLineDistance(vP,viewPosition,d1viewPosition);
@@ -199,14 +199,14 @@ var SSRShader = {
 					if(dot(viewReflectDir,vN)>=0.) continue;
 					float distance=pointPlaneDistance(vP,viewPosition,viewNormal);
 					if(distance>maxDistance) break;
-					#ifdef isDistanceAttenuation
+					#ifdef DISTANCE_ATTENUATION
 						float ratio=1.-(distance/maxDistance);
 						float attenuation=ratio*ratio;
 						op=opacity*attenuation;
 					#endif
-					#ifdef isFresnel
-						float fresnel=(dot(viewIncidenceDir,viewReflectDir)+1.)/2.;
-						op*=fresnel;
+					#ifdef FRESNEL
+						float fresnelCoe=(dot(viewIncidentDir,viewReflectDir)+1.)/2.;
+						op*=fresnelCoe;
 					#endif
 					vec4 reflectColor=texture2D(tDiffuse,uv);
 					gl_FragColor.xyz=reflectColor.xyz;

+ 34 - 45
examples/webgl_postprocessing_ssr.html

@@ -27,20 +27,19 @@
 		import { GUI } from './jsm/libs/dat.gui.module.js';
 		import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
 		import { SSRPass } from './jsm/postprocessing/SSRPass.js';
-		import { Reflector } from './jsm/objects/ReflectorForSSRPass.js';
+		import { ReflectorForSSRPass } from './jsm/objects/ReflectorForSSRPass.js';
 
 		import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
 
 		const params = {
 			enableSSR: true,
 			autoRotate: true,
-			isOtherMeshes: true,
-			isGroundReflector: true,
+			otherMeshes: true,
+			groundReflector: true,
 		};
 		let composer;
 		let ssrPass;
 		let gui;
-		const isPerspectiveCamera = true;
 		let stats;
 		let controls;
 		let camera, scene, renderer;
@@ -73,7 +72,7 @@
 				new THREE.MeshPhongMaterial( { color: 0x999999, specular: 0x101010 } )
 			);
 			plane.rotation.x = - Math.PI / 2;
-			plane.position.y = 0.0365;
+			plane.position.y = - 0.0001;
 			// plane.receiveShadow = true;
 			scene.add( plane );
 
@@ -94,6 +93,7 @@
 
 				const material = new THREE.MeshStandardMaterial( { color: 0x606060 } );
 				const mesh = new THREE.Mesh( geometry, material );
+				mesh.position.y = - 0.0365;
 				scene.add( mesh );
 				selects.push( mesh );
 
@@ -107,7 +107,7 @@
 			geometry = new THREE.BoxBufferGeometry( .05, .05, .05 );
 			material = new THREE.MeshStandardMaterial( { color: 'green' } );
 			mesh = new THREE.Mesh( geometry, material );
-			mesh.position.set( - .12, plane.position.y + .025, .015 );
+			mesh.position.set( - .12, .025, .015 );
 			scene.add( mesh );
 			otherMeshes.push( mesh );
 			selects.push( mesh );
@@ -115,7 +115,7 @@
 			geometry = new THREE.IcosahedronBufferGeometry( .025, 4 );
 			material = new THREE.MeshStandardMaterial( { color: 'cyan' } );
 			mesh = new THREE.Mesh( geometry, material );
-			mesh.position.set( - .05, plane.position.y + .025, .08 );
+			mesh.position.set( - .05, .025, .08 );
 			scene.add( mesh );
 			otherMeshes.push( mesh );
 			selects.push( mesh );
@@ -123,21 +123,21 @@
 			geometry = new THREE.ConeBufferGeometry( .025, .05, 64 );
 			material = new THREE.MeshStandardMaterial( { color: 'yellow' } );
 			mesh = new THREE.Mesh( geometry, material );
-			mesh.position.set( - .05, plane.position.y + .025, - .055 );
+			mesh.position.set( - .05, .025, - .055 );
 			scene.add( mesh );
 			otherMeshes.push( mesh );
 			selects.push( mesh );
 
-			geometry = new THREE.PlaneBufferGeometry( 8, 8 );
-			groundReflector = new Reflector( geometry, {
-				clipBias: 0.003,
+			geometry = new THREE.PlaneBufferGeometry( 1, 1 );
+			groundReflector = new ReflectorForSSRPass( geometry, {
+				clipBias: 0,
+				worldYBias: - 0.027450980392156862,
 				textureWidth: window.innerWidth,
 				textureHeight: window.innerHeight,
 				color: 0x888888,
 				useDepthTexture: true,
 			} );
 			groundReflector.material.depthWrite = false;
-			groundReflector.position.y = plane.position.y + .0001;
 			groundReflector.rotation.x = - Math.PI / 2;
 			groundReflector.visible = false;
 			scene.add( groundReflector );
@@ -152,7 +152,7 @@
 
 			controls = new OrbitControls( camera, renderer.domElement );
 			controls.enableDamping = true;
-			controls.target.set( 0, 0.1, 0 );
+			controls.target.set( 0, 0.0635, 0 );
 			controls.update();
 			controls.enabled = ! params.autoRotate;
 
@@ -173,20 +173,19 @@
 				width: innerWidth,
 				height: innerHeight,
 				encoding: THREE.sRGBEncoding,
-				isPerspectiveCamera: isPerspectiveCamera,
-				groundReflector: params.isGroundReflector ? groundReflector : null,
-				selects: params.isGroundReflector ? selects : null
+				groundReflector: params.groundReflector ? groundReflector : null,
+				selects: params.groundReflector ? selects : null
 			} );
 
 			composer.addPass( ssrPass );
 
 			// GUI
 
-			gui = new GUI();
+			gui = new GUI( { width: 260 } );
 			gui.add( params, 'enableSSR' ).name( 'Enable SSR' );
-			gui.add( params, 'isGroundReflector' ).onChange( () => {
+			gui.add( params, 'groundReflector' ).onChange( () => {
 
-				if ( params.isGroundReflector ) {
+				if ( params.groundReflector ) {
 
 					ssrPass.groundReflector = groundReflector,
 					ssrPass.selects = selects;
@@ -206,14 +205,14 @@
 			} );
 
 			const folder = gui.addFolder( 'more settings' );
-			folder.add( ssrPass, 'isFresnel' ).onChange( ()=>{
+			folder.add( ssrPass, 'fresnel' ).onChange( ()=>{
 
-				groundReflector.isFresnel = ssrPass.isFresnel;
+				groundReflector.fresnel = ssrPass.fresnel;
 
 			} );
-			folder.add( ssrPass, 'isDistanceAttenuation' ).onChange( ()=>{
+			folder.add( ssrPass, 'distanceAttenuation' ).onChange( ()=>{
 
-				groundReflector.isDistanceAttenuation = ssrPass.isDistanceAttenuation;
+				groundReflector.distanceAttenuation = ssrPass.distanceAttenuation;
 
 			} );
 			ssrPass.maxDistance = .1;
@@ -223,9 +222,9 @@
 				groundReflector.maxDistance = ssrPass.maxDistance;
 
 			} );
-			folder.add( params, 'isOtherMeshes' ).onChange( () => {
+			folder.add( params, 'otherMeshes' ).onChange( () => {
 
-				if ( params.isOtherMeshes ) {
+				if ( params.otherMeshes ) {
 
 					otherMeshes.forEach( mesh => mesh.visible = true );
 
@@ -236,7 +235,7 @@
 				}
 
 			} );
-			folder.add( ssrPass, 'isBouncing' );
+			folder.add( ssrPass, 'bouncing' );
 			folder.add( ssrPass, 'output', {
 				'Default': SSRPass.OUTPUT.Default,
 				'SSR Only': SSRPass.OUTPUT.SSR,
@@ -256,22 +255,11 @@
 				groundReflector.opacity = ssrPass.opacity;
 
 			} );
-
-			if ( isPerspectiveCamera ) {
-
-				ssrPass.surfDist = 0.0015;
-				folder.add( ssrPass, 'surfDist' ).min( 0 ).max( .005 ).step( .0001 );
-
-			} else {
-
-				ssrPass.surfDist = 2;
-				folder.add( ssrPass, 'surfDist' ).min( 0 ).max( 7 ).step( .01 );
-
-			}
-
-			folder.add( ssrPass, 'isInfiniteThick' );
+			ssrPass.surfDist = 0.0015;
+			folder.add( ssrPass, 'surfDist' ).min( 0 ).max( .005 ).step( .0001 );
+			folder.add( ssrPass, 'infiniteThick' );
 			folder.add( ssrPass, 'thickTolerance' ).min( 0 ).max( .05 ).step( .0001 );
-			folder.add( ssrPass, 'isBlur' );
+			folder.add( ssrPass, 'blur' );
 			// gui.close()
 
 		}
@@ -285,6 +273,7 @@
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			composer.setSize( window.innerWidth, window.innerHeight );
 			groundReflector.getRenderTarget().setSize( window.innerWidth, window.innerHeight );
+			groundReflector.resolution.set( window.innerWidth, window.innerHeight );
 
 		}
 
@@ -305,9 +294,9 @@
 				const timer = Date.now() * 0.0003;
 
 				camera.position.x = Math.sin( timer ) * 0.5;
-				camera.position.y = 0.25;
+				camera.position.y = 0.2135;
 				camera.position.z = Math.cos( timer ) * 0.5;
-				camera.lookAt( 0, 0.1, 0 );
+				camera.lookAt( 0, 0.0635, 0 );
 
 			} else {
 
@@ -317,8 +306,8 @@
 
 			if ( params.enableSSR ) {
 
-				///todo: groundReflector has full ground info, need use it to solve reflection gaps problem on objects when camera near ground.
-				///todo: the normal info where groundReflector reflected need to be changed.
+				// TODO: groundReflector has full ground info, need use it to solve reflection gaps problem on objects when camera near ground.
+				// TODO: the normal and depth info where groundReflector reflected need to be changed.
 				composer.render();
 
 			} else {