From f6e17b020fe04faa1470f00f1bfceb3f8b0bcd00 Mon Sep 17 00:00:00 2001 From: WestLangley Date: Fri, 14 Jul 2017 00:14:36 -0400 Subject: [PATCH] Fix PointLight shadowmapping DistanceRGBA shader --- examples/webgl_shadowmap_pointlight.html | 5 +++-- src/renderers/WebGLRenderer.js | 2 ++ src/renderers/shaders/ShaderChunk/lights_pars.glsl | 2 ++ src/renderers/shaders/ShaderChunk/lights_template.glsl | 2 +- .../shaders/ShaderChunk/shadowmap_pars_fragment.glsl | 10 ++++++---- .../shaders/ShaderChunk/shadowmask_pars_fragment.glsl | 2 +- src/renderers/shaders/ShaderLib.js | 4 +++- src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl | 8 +++++++- src/renderers/shaders/UniformsLib.js | 4 +++- src/renderers/webgl/WebGLLights.js | 4 +++- src/renderers/webgl/WebGLShadowMap.js | 8 +++++--- 11 files changed, 36 insertions(+), 15 deletions(-) diff --git a/examples/webgl_shadowmap_pointlight.html b/examples/webgl_shadowmap_pointlight.html index b2cb24a060..a7e5afd49d 100644 --- a/examples/webgl_shadowmap_pointlight.html +++ b/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 diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 89154d87a3..efd5ebb855 100644 --- a/src/renderers/WebGLRenderer.js +++ b/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; } diff --git a/src/renderers/shaders/ShaderChunk/lights_pars.glsl b/src/renderers/shaders/ShaderChunk/lights_pars.glsl index aa6fbffe23..697649dd80 100644 --- a/src/renderers/shaders/ShaderChunk/lights_pars.glsl +++ b/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 ]; diff --git a/src/renderers/shaders/ShaderChunk/lights_template.glsl b/src/renderers/shaders/ShaderChunk/lights_template.glsl index 219e7956e4..154483c4bb 100644 --- a/src/renderers/shaders/ShaderChunk/lights_template.glsl +++ b/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 ); diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl index 5714016f08..5f0c598ae1 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl +++ b/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 ) diff --git a/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl index ba5c2d1125..d2a49ee331 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl +++ b/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; } diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index db357ddae4..ad1df57a92 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/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 } } ] ), diff --git a/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl b/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl index a7e92ac9bf..07a4a95b93 100644 --- a/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl +++ b/src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl @@ -1,4 +1,6 @@ uniform vec3 lightPos; +uniform float shadowCameraNear; +uniform float shadowCameraFar; varying vec4 vWorldPosition; #include @@ -18,6 +20,10 @@ void main () { #include #include - 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 ); } diff --git a/src/renderers/shaders/UniformsLib.js b/src/renderers/shaders/UniformsLib.js index 3dc12e2a53..0089bd3803 100644 --- a/src/renderers/shaders/UniformsLib.js +++ b/src/renderers/shaders/UniformsLib.js @@ -140,7 +140,9 @@ var UniformsLib = { shadow: {}, shadowBias: {}, shadowRadius: {}, - shadowMapSize: {} + shadowMapSize: {}, + shadowCameraNear: {}, + shadowCameraFar: {} } }, pointShadowMap: { value: [] }, diff --git a/src/renderers/webgl/WebGLLights.js b/src/renderers/webgl/WebGLLights.js index 1ef4095785..dc67f7c66a 100644 --- a/src/renderers/webgl/WebGLLights.js +++ b/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; diff --git a/src/renderers/webgl/WebGLShadowMap.js b/src/renderers/webgl/WebGLShadowMap.js index 15a513bb45..fc5613616b 100644 --- a/src/renderers/webgl/WebGLShadowMap.js +++ b/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 ); } -- GitLab