diff --git a/examples/webgl_shadowmap_pointlight.html b/examples/webgl_shadowmap_pointlight.html index b2cb24a060bca9957aeea90426d80d164f66b383..a7e5afd49ded71aaa1a61bb7d23f027fcae729c3 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 89154d87a3031b45b933ebf8a488b0a0a2188322..efd5ebb855ab9fb271725bf508b722093c3b74c9 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 aa6fbffe23a99ebcd48517b657995495e2bb017c..697649dd80355dfd0af67fb8be8e39a6eb4526c1 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 219e7956e43b5570b5169a803e1e482ab434eab9..154483c4bb4209326917b17c8c2f450772bfdfdf 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 5714016f08b839e2a7e1aab897323fa51a162dd1..5f0c598ae1f7fbf349aadce3af50c327db75e670 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 ba5c2d11255ec071c58f570db0ecde864a6a54ff..d2a49ee331ba5736a1082caa8b711bcb344be6a7 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 db357ddae4f070bb75bcdfb8ff515202db396346..ad1df57a921d4b88a3a77350e8dc748ff22256e2 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 a7e92ac9bf74cb766ef284155f3a261c5fc5f9f9..07a4a95b93cc652f37514d3b4c064b7f90671e20 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 3dc12e2a530262b157860e8d6089b79c8ec31fbe..0089bd3803c044cacad1581357d512a13eed8b99 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 1ef40957855e22845798600f74c9d8f33369178a..dc67f7c66aadb48507af561bda1eef6a5a09f6cd 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 15a513bb45a11a26cde8007d100dde30d0062145..fc5613616b7e066d8c3a5a10fb635246a3370d45 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 ); }