Explorar o código

Fix PointLight shadowmapping DistanceRGBA shader

WestLangley %!s(int64=8) %!d(string=hai) anos
pai
achega
f6e17b020f

+ 3 - 2
examples/webgl_shadowmap_pointlight.html

@@ -58,8 +58,8 @@
 					var pointLight = new THREE.PointLight( color, 1, 30 );
 					pointLight.castShadow = true;
 					pointLight.shadow.camera.near = 1;
-					pointLight.shadow.camera.far = 30;
-					pointLight.shadow.bias = 0.01;
+					pointLight.shadow.camera.far = 60;
+					pointLight.shadow.bias = - 0.005; // reduces self-shadowing on double-sided objects
 
 					var geometry = new THREE.SphereGeometry( 0.3, 12, 6 );
 					var material = new THREE.MeshBasicMaterial( { color: color } );
@@ -97,6 +97,7 @@
 				torusKnot = new THREE.Mesh( geometry, material );
 				torusKnot.position.set( 0, 5, 0 );
 				torusKnot.castShadow = true;
+				torusKnot.receiveShadow = true;
 				scene.add( torusKnot );
 
 				// custom distance material

+ 2 - 0
src/renderers/WebGLRenderer.js

@@ -2418,6 +2418,8 @@ function WebGLRenderer( parameters ) {
 					uniforms.shadowBias = shadow.bias;
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowMapSize = shadow.mapSize;
+					uniforms.shadowCameraNear = shadow.camera.near;
+					uniforms.shadowCameraFar = shadow.camera.far;
 
 				}
 

+ 2 - 0
src/renderers/shaders/ShaderChunk/lights_pars.glsl

@@ -51,6 +51,8 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 		float shadowBias;
 		float shadowRadius;
 		vec2 shadowMapSize;
+		float shadowCameraNear;
+		float shadowCameraFar;
 	};
 
 	uniform PointLight pointLights[ NUM_POINT_LIGHTS ];

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_template.glsl

@@ -32,7 +32,7 @@ IncidentLight directLight;
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 
 		#ifdef USE_SHADOWMAP
-		directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;
+		directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 		#endif
 
 		RE_Direct( directLight, geometry, material, reflectedLight );

+ 6 - 4
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl

@@ -201,18 +201,20 @@
 
 	}
 
-	float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {
+	float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {
 
 		vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );
 
 		// for point lights, the uniform @vShadowCoord is re-purposed to hold
-		// the distance from the light to the world-space position of the fragment.
+		// the vector from the light to the world-space position of the fragment.
 		vec3 lightToPosition = shadowCoord.xyz;
 
+		// dp = normalized distance from light to fragment position
+		float dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); // need to clamp?
+		dp += shadowBias;
+
 		// bd3D = base direction 3D
 		vec3 bd3D = normalize( lightToPosition );
-		// dp = distance from light to fragment position
-		float dp = ( length( lightToPosition ) - shadowBias ) / 1000.0;
 
 		#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl

@@ -37,7 +37,7 @@ float getShadowMask() {
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 
 		pointLight = pointLights[ i ];
-		shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ] ) : 1.0;
+		shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 
 	}
 

+ 3 - 1
src/renderers/shaders/ShaderLib.js

@@ -194,7 +194,9 @@ var ShaderLib = {
 			UniformsLib.common,
 			UniformsLib.displacementmap,
 			{
-				lightPos: { value: new Vector3() }
+				lightPos: { value: new Vector3() },
+				shadowCameraNear: { value: 1 },
+				shadowCameraFar: { value: 1000 }
 			}
 		] ),
 

+ 7 - 1
src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl

@@ -1,4 +1,6 @@
 uniform vec3 lightPos;
+uniform float shadowCameraNear;
+uniform float shadowCameraFar;
 varying vec4 vWorldPosition;
 
 #include <common>
@@ -18,6 +20,10 @@ void main () {
 	#include <alphamap_fragment>
 	#include <alphatest_fragment>
 
-	gl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );
+	float dist = length( vWorldPosition.xyz - lightPos.xyz );
+	dist = ( dist - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );
+	dist = saturate( dist ); // clamp to [ 0, 1 ]
+
+	gl_FragColor = packDepthToRGBA( dist );
 
 }

+ 3 - 1
src/renderers/shaders/UniformsLib.js

@@ -140,7 +140,9 @@ var UniformsLib = {
 			shadow: {},
 			shadowBias: {},
 			shadowRadius: {},
-			shadowMapSize: {}
+			shadowMapSize: {},
+			shadowCameraNear: {},
+			shadowCameraFar: {}
 		} },
 
 		pointShadowMap: { value: [] },

+ 3 - 1
src/renderers/webgl/WebGLLights.js

@@ -63,7 +63,9 @@ function WebGLLights() {
 						shadow: false,
 						shadowBias: 0,
 						shadowRadius: 1,
-						shadowMapSize: new Vector2()
+						shadowMapSize: new Vector2(),
+						shadowCameraNear: 1,
+						shadowCameraFar: 1000
 					};
 					break;
 

+ 5 - 3
src/renderers/webgl/WebGLShadowMap.js

@@ -273,7 +273,7 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 	};
 
-	function getDepthMaterial( object, material, isPointLight, lightPositionWorld ) {
+	function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {
 
 		var geometry = object.geometry;
 
@@ -389,6 +389,8 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 		if ( isPointLight && result.uniforms.lightPos !== undefined ) {
 
 			result.uniforms.lightPos.value.copy( lightPositionWorld );
+			result.uniforms.shadowCameraNear.value = shadowCameraNear;
+			result.uniforms.shadowCameraFar.value = shadowCameraFar;
 
 		}
 
@@ -422,7 +424,7 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 						if ( groupMaterial && groupMaterial.visible ) {
 
-							var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld );
+							var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
 							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
 
 						}
@@ -431,7 +433,7 @@ function WebGLShadowMap( _renderer, _lights, _objects, capabilities ) {
 
 				} else if ( material.visible ) {
 
-					var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld );
+					var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
 					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
 
 				}