diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 7014267035bf9469bba95e951b73e7e1a96c9819..ef800830f898e11504c7aa1fd794511838334256 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1989,6 +1989,11 @@ THREE.WebGLRenderer = function ( parameters ) { if ( light instanceof THREE.PointLight ) { + // for point lights we set the shadow matrix to be a translation-only matrix + // equal to inverse of the light's position + _vector3.setFromMatrixPosition( light.matrixWorld ).negate(); + light.shadowMatrix.identity().setPosition( _vector3 ); + // for point lights we set the sign of the shadowDarkness uniform to be negative uniforms.shadowDarkness.value[ j ] = - light.shadowDarkness; diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl index 1dfe79e5d506b1d20e842b9ce8a524c4e8a8983a..e8df080aef67c6aa0d49781b7408796d57fc6d24 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl @@ -1,322 +1,266 @@ #ifdef USE_SHADOWMAP - #ifdef SHADOWMAP_DEBUG - - vec3 frustumColors[3]; - frustumColors[0] = vec3( 1.0, 0.5, 0.0 ); - frustumColors[1] = vec3( 0.0, 1.0, 0.8 ); - frustumColors[2] = vec3( 0.0, 0.5, 1.0 ); - - #endif - - float fDepth; - vec3 shadowColor = vec3( 1.0 ); + vec3 shadowMask = vec3( 1.0 ); for( int i = 0; i < MAX_SHADOWS; i ++ ) { - - // to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine - // whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light) - bool isPointLight = shadowDarkness[ i ] < 0.0; - - // get the real shadow darkness - float realShadowDarkness = abs( shadowDarkness[ i ] ); - - // for point lights, the uniform @vShadowCoord is re-purposed to hold - // the distance from the light to the world-space position of the fragment. - vec3 lightToPosition = vShadowCoord[ i ].xyz; - - float texelSizeX = 1.0 / shadowMapSize[ i ].x; + float texelSizeY = 1.0 / shadowMapSize[ i ].y; - vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w; - float shadow = 0.0; - - // if ( something && something ) breaks ATI OpenGL shader compiler - // if ( all( something, something ) ) using this instead + float shadow = 0.0; - bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); - bool inFrustum = all( inFrustumVec ); +#if defined( POINT_LIGHT_SHADOWS ) - bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); - - bool frustumTest = all( frustumTestVec ); + // to save on uniform space, we use the sign of @shadowDarkness[ i ] to determine + // whether or not this light is a point light ( shadowDarkness[ i ] < 0 == point light) + bool isPointLight = shadowDarkness[ i ] < 0.0; - if ( frustumTest || isPointLight ) { + if( isPointLight ) { - #if defined( SHADOWMAP_TYPE_PCF ) + // get the real shadow darkness + float realShadowDarkness = abs( shadowDarkness[ i ] ); - #if defined(POINT_LIGHT_SHADOWS) + // for point lights, the uniform @vShadowCoord is re-purposed to hold + // the distance from the light to the world-space position of the fragment. + vec3 lightToPosition = vShadowCoord[ i ].xyz; - if( isPointLight ) { + #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) - // bd3D = base direction 3D - vec3 bd3D = normalize( lightToPosition ); - // dp = distance from light to fragment position - float dp = length( lightToPosition ); + // bd3D = base direction 3D + vec3 bd3D = normalize( lightToPosition ); + // dp = distance from light to fragment position + float dp = length( lightToPosition ); - shadow = 0.0; + // base measurement + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); - // base measurement - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); + // Dr = disk radius - // dr = disk radius - const float dr = 1.25; - // os = offset scale - float os = dr * 2.0 * texelSizeY; + #if defined( SHADOWMAP_TYPE_PCF ) + const float Dr = 1.25; + #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) + const float Dr = 2.25; + #endif - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd0 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd1 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd2 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd3 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd4 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd5 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd6 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd7 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd8 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd9 * os, texelSizeY ) ), shadowBias[ i ], shadow ); + // os = offset scale + float os = Dr * 2.0 * texelSizeY; - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd10 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd11 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd12 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd13 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd14 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd15 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd16 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd17 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd18 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd19 * os, texelSizeY ) ), shadowBias[ i ], shadow ); + const vec3 Gsd = vec3( - 1, 0, 1 ); - shadow /= 21.0; + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zzy * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zxy * os, texelSizeY ) ), shadowBias[ i ], shadow ); - } else { + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xxy * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xzy * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.zyx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.xyx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxz * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yxx * os, texelSizeY ) ), shadowBias[ i ], shadow ); + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + Gsd.yzx * os, texelSizeY ) ), shadowBias[ i ], shadow ); - #endif + shadow *= realShadowDarkness * ( 1.0 / 21.0 ); - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ - - /* - // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL - // must enroll loop manually - for ( float y = -1.25; y <= 1.25; y += 1.25 ) - for ( float x = -1.25; x <= 1.25; x += 1.25 ) { - vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ); - // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup - //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) ); - float fDepth = unpackDepth( rgbaDepth ); - if ( fDepth < shadowCoord.z ) - shadow += 1.0; - } - shadow /= 9.0; - */ + #else // no percentage-closer filtering: - shadowCoord.z += shadowBias[ i ]; + vec3 bd3D = normalize( lightToPosition ); + float dp = length( lightToPosition ); - const float shadowDelta = 1.0 / 9.0; + adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); - float xPixelOffset = texelSizeX; - float yPixelOffset = texelSizeY; + shadow *= realShadowDarkness; - float dx0 = -1.25 * xPixelOffset; - float dy0 = -1.25 * yPixelOffset; - float dx1 = 1.25 * xPixelOffset; - float dy1 = 1.25 * yPixelOffset; + #endif - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + } else { - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; +#endif // POINT_LIGHT_SHADOWS - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + float texelSizeX = 1.0 / shadowMapSize[ i ].x; - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w; - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + // if ( something && something ) breaks ATI OpenGL shader compiler + // if ( all( something, something ) ) using this instead - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); + bool inFrustum = all( inFrustumVec ); - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; + bool frustumTest = all( frustumTestVec ); - fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); - if ( fDepth < shadowCoord.z ) shadow += shadowDelta; - - #if defined(POINT_LIGHT_SHADOWS) + if( frustumTest ) { + #if defined( SHADOWMAP_TYPE_PCF ) + + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ + + /* + // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL + // must enroll loop manually + for ( float y = -1.25; y <= 1.25; y += 1.25 ) + for ( float x = -1.25; x <= 1.25; x += 1.25 ) { + vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ); + // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup + //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) ); + float fDepth = unpackDepth( rgbaDepth ); + if ( fDepth < shadowCoord.z ) + shadow += 1.0; } + shadow /= 9.0; + */ - #endif - - shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) ); - - #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) + shadowCoord.z += shadowBias[ i ]; - #if defined(POINT_LIGHT_SHADOWS) + const float ShadowDelta = 1.0 / 9.0; - if( isPointLight ) { + float xPixelOffset = texelSizeX; + float yPixelOffset = texelSizeY; - // bd3D = base direction 3D - vec3 bd3D = normalize( lightToPosition ); - // dp = distance from light to fragment position - float dp = length( lightToPosition ); + float dx0 = - 1.25 * xPixelOffset; + float dy0 = - 1.25 * yPixelOffset; + float dx1 = 1.25 * xPixelOffset; + float dy1 = 1.25 * yPixelOffset; - shadow = 0.0; + float fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - // base measurement - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - // dr = disk radius - const float dr = 2.25; - // os = offset scale - float os = dr * 2.0 * texelSizeY; + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd0 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd1 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd2 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd3 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd4 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd5 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd6 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd7 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd8 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd9 * os, texelSizeY ) ), shadowBias[ i ], shadow ); + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd10 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd11 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd12 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd13 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd14 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd15 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd16 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd17 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd18 * os, texelSizeY ) ), shadowBias[ i ], shadow ); - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D + gsd19 * os, texelSizeY ) ), shadowBias[ i ], shadow ); + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - shadow /= 21.0; + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - } else { + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - #endif + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - // Percentage-close filtering - // (9 pixel kernel) - // http://fabiensanglard.net/shadowmappingPCF/ + fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); + if ( fDepth < shadowCoord.z ) shadow += ShadowDelta; - shadowCoord.z += shadowBias[ i ]; + shadow *= shadowDarkness[ i ]; - float xPixelOffset = texelSizeX; - float yPixelOffset = texelSizeY; + #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) - float dx0 = -1.0 * xPixelOffset; - float dy0 = -1.0 * yPixelOffset; - float dx1 = 1.0 * xPixelOffset; - float dy1 = 1.0 * yPixelOffset; + // Percentage-close filtering + // (9 pixel kernel) + // http://fabiensanglard.net/shadowmappingPCF/ - mat3 shadowKernel; - mat3 depthKernel; + shadowCoord.z += shadowBias[ i ]; - depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); - depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); - depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); - depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); - depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); - depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); - depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); - depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); - depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); + float xPixelOffset = texelSizeX; + float yPixelOffset = texelSizeY; - vec3 shadowZ = vec3( shadowCoord.z ); - shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ )); - shadowKernel[0] *= vec3(0.25); + float dx0 = - 1.0 * xPixelOffset; + float dy0 = - 1.0 * yPixelOffset; + float dx1 = 1.0 * xPixelOffset; + float dy1 = 1.0 * yPixelOffset; - shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ )); - shadowKernel[1] *= vec3(0.25); + mat3 shadowKernel; + mat3 depthKernel; - shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ )); - shadowKernel[2] *= vec3(0.25); + depthKernel[ 0 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); + depthKernel[ 0 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); + depthKernel[ 0 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); + depthKernel[ 1 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); + depthKernel[ 1 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) ); + depthKernel[ 1 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); + depthKernel[ 2 ][ 0 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); + depthKernel[ 2 ][ 1 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); + depthKernel[ 2 ][ 2 ] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); - vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy ); + vec3 shadowZ = vec3( shadowCoord.z ); + shadowKernel[ 0 ] = vec3( lessThan( depthKernel[ 0 ], shadowZ ) ); + shadowKernel[ 0 ] *= vec3( 0.25 ); - shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x ); - shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x ); + shadowKernel[ 1 ] = vec3( lessThan( depthKernel[ 1 ], shadowZ ) ); + shadowKernel[ 1 ] *= vec3( 0.25 ); - vec4 shadowValues; - shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y ); - shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y ); - shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y ); - shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y ); - - shadow = dot( shadowValues, vec4( 1.0 ) ); - - #if defined(POINT_LIGHT_SHADOWS) - - } + shadowKernel[ 2 ] = vec3( lessThan( depthKernel[ 2 ], shadowZ ) ); + shadowKernel[ 2 ] *= vec3( 0.25 ); - #endif + vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[ i ].xy ); - shadowColor = shadowColor * vec3( ( 1.0 - realShadowDarkness * shadow ) ); + shadowKernel[ 0 ] = mix( shadowKernel[ 1 ], shadowKernel[ 0 ], fractionalCoord.x ); + shadowKernel[ 1 ] = mix( shadowKernel[ 2 ], shadowKernel[ 1 ], fractionalCoord.x ); - #else + vec4 shadowValues; + shadowValues.x = mix( shadowKernel[ 0 ][ 1 ], shadowKernel[ 0 ][ 0 ], fractionalCoord.y ); + shadowValues.y = mix( shadowKernel[ 0 ][ 2 ], shadowKernel[ 0 ][ 1 ], fractionalCoord.y ); + shadowValues.z = mix( shadowKernel[ 1 ][ 1 ], shadowKernel[ 1 ][ 0 ], fractionalCoord.y ); + shadowValues.w = mix( shadowKernel[ 1 ][ 2 ], shadowKernel[ 1 ][ 1 ], fractionalCoord.y ); - #if defined(POINT_LIGHT_SHADOWS) + shadow = dot( shadowValues, vec4( 1.0 ) ) * shadowDarkness[ i ]; - if( isPointLight ) { + #else // no percentage-closer filtering: + + shadowCoord.z += shadowBias[ i ]; - vec3 bd3D = normalize( lightToPosition ); - float dp = length( lightToPosition ); + vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy ); + float fDepth = unpackDepth( rgbaDepth ); - float shadow = 0.0; + if ( fDepth < shadowCoord.z ) + shadow = shadowDarkness[ i ]; - adjustShadowValue1K( dp, texture2D( shadowMap[ i ], cubeToUV( bd3D, texelSizeY ) ), shadowBias[ i ], shadow ); + #endif - shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness * shadow ); + } - } else { +#ifdef SHADOWMAP_DEBUG - #endif - shadowCoord.z += shadowBias[ i ]; + if ( inFrustum ) { - vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy ); - float fDepth = unpackDepth( rgbaDepth ); + if ( i == 0 ) { - if ( fDepth < shadowCoord.z ) + outgoingLight *= vec3( 1.0, 0.5, 0.0 ); - // spot with multiple shadows is darker + } else if ( i == 1 ) { - shadowColor = shadowColor * vec3( 1.0 - realShadowDarkness ); + outgoingLight *= vec3( 0.0, 1.0, 0.8 ); - // spot with multiple shadows has the same color as single shadow spot + } else { - // shadowColor = min( shadowColor, vec3( realShadowDarkness ) ); + outgoingLight *= vec3( 0.0, 0.5, 1.0 ); - #if defined(POINT_LIGHT_SHADOWS) + } - } + } - #endif +#endif - #endif +#if defined( POINT_LIGHT_SHADOWS ) } +#endif - #ifdef SHADOWMAP_DEBUG - - if ( inFrustum ) outgoingLight *= frustumColors[ i ]; - - #endif + shadowMask = shadowMask * vec3( 1.0 - shadow ); } - outgoingLight = outgoingLight * shadowColor; + outgoingLight = outgoingLight * shadowMask; #endif diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl index 2cb0034d948b7c191c851027d269d13beb53dfa1..167997be67e566729475eb48f4eca3318eeab69e 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl @@ -101,30 +101,6 @@ } - // gsdXX = grid sampling disk XX - // these values are used when rendering PCF shadow maps for point lights - - const vec3 gsd0 = vec3( 1, 1, 1 ); - const vec3 gsd1 = vec3( 1, - 1, 1 ); - const vec3 gsd2 = vec3( - 1, - 1, 1 ); - const vec3 gsd3 = vec3( - 1, 1, 1 ); - const vec3 gsd4 = vec3( 1, 1, - 1 ); - const vec3 gsd5 = vec3( 1, - 1, - 1 ); - const vec3 gsd6 = vec3( - 1, - 1, - 1 ); - const vec3 gsd7 = vec3( -1, 1, - 1 ); - const vec3 gsd8 = vec3( 1, 1, 0 ); - const vec3 gsd9 = vec3( 1, - 1, 0 ); - const vec3 gsd10 = vec3( - 1, - 1, 0 ); - const vec3 gsd11 = vec3( - 1, 1, 0 ); - const vec3 gsd12 = vec3( 1, 0, 1 ); - const vec3 gsd13 = vec3( - 1, 0, 1 ); - const vec3 gsd14 = vec3( 1, 0, - 1 ); - const vec3 gsd15 = vec3( - 1, 0, - 1 ); - const vec3 gsd16 = vec3( 0, 1, 1 ); - const vec3 gsd17 = vec3( 0, - 1, 1 ); - const vec3 gsd18 = vec3( 0, - 1, - 1 ); - const vec3 gsd19 = vec3( 0, 1, - 1 ); - #endif #endif diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl index 6328c60dfb696f6c351d7e37eeb1da5ea4f9935a..32d612c08fe47ac5bf0192b174af29cd05891a38 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl +++ b/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl @@ -2,40 +2,8 @@ for( int i = 0; i < MAX_SHADOWS; i ++ ) { - #if defined(POINT_LIGHT_SHADOWS) - - // if shadowDarkness[ i ] < 0.0, that means we have a point light with a cube - // shadow map - if( shadowDarkness[ i ] < 0.0 ) { - - // calculate vector from light to vertex in view space - - vec3 fromLight = mvPosition.xyz - pointLightPosition[ i ]; - - // Transform 'fromLight' into world space by multiplying it on the left - // side of 'viewMatrix'. This is equivalent to multiplying it on the right - // side of the transpose of 'viewMatrix'. Since 'viewMatrix' is orthogonal, - // its transpose is the same as its inverse. - - fromLight = fromLight * mat3( viewMatrix ); - - // We repurpose vShadowCoord to hold the distance in world space from the - // light to the vertex. This value will be interpolated correctly in the fragment shader. - - vShadowCoord[ i ] = vec4( fromLight, 1.0 ); - - } else { - - vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; - - } - - #else - vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition; - #endif - } #endif \ No newline at end of file diff --git a/src/renderers/webgl/WebGLShadowMap.js b/src/renderers/webgl/WebGLShadowMap.js index 0699aca3bc3dcc0305c4a0c86575085f12f937a9..26431bd7c9c24b9a4c1ea7076808cb61a770a8df 100644 --- a/src/renderers/webgl/WebGLShadowMap.js +++ b/src/renderers/webgl/WebGLShadowMap.js @@ -100,27 +100,15 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var faceCount, isPointLight; if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - - // set GL state for depth map + if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; + // Set GL state for depth map. _gl.clearColor( 1, 1, 1, 1 ); _state.disable( _gl.BLEND ); - _state.enable( _gl.CULL_FACE ); _gl.frontFace( _gl.CCW ); - - if ( scope.cullFace === THREE.CullFaceFront ) { - - _gl.cullFace( _gl.FRONT ); - - } else { - - _gl.cullFace( _gl.BACK ); - - } - - _state.setDepthTest( true ); + _gl.cullFace( scope.cullFace === THREE.CullFaceFront ? _gl.FRONT : _gl.BACK ); + _state.setDepthTest( true ); // save the existing viewport so it can be restored later _renderer.getViewport( _vector4 ); @@ -131,6 +119,8 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { var light = _lights[ i ]; + if ( ! light.castShadow ) continue; + if ( light instanceof THREE.PointLight ) { faceCount = 6; @@ -172,8 +162,6 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { } - if ( ! light.castShadow ) continue; - if ( ! light.shadowMap ) { var shadowFilter = THREE.LinearFilter; @@ -321,15 +309,17 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { } - _renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w ); + //We must call _renderer.resetGLState() at the end of each iteration of + // the light loop in order to force material updates for each light. + _renderer.resetGLState(); } - // restore GL state + _renderer.setViewport( _vector4.x, _vector4.y, _vector4.z, _vector4.w ); + // Restore GL state. var clearColor = _renderer.getClearColor(), clearAlpha = _renderer.getClearAlpha(); - _renderer.setClearColor( clearColor, clearAlpha ); _state.enable( _gl.BLEND ); @@ -339,7 +329,7 @@ THREE.WebGLShadowMap = function ( _renderer, _lights, _objects ) { } - _renderer.resetGLState(); + _renderer.resetGLState(); scope.needsUpdate = false;