#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 #ifdef SHADOWMAP_CASCADE int inFrustumCount = 0; #endif float fDepth; vec3 shadowColor = vec3( 1.0 ); <% parameters[:max_shadows].times do |i| %> vec3 shadowCoord = vShadowCoord[ <%= i %> ].xyz / vShadowCoord[ <%= i %> ].w; // if ( something && something ) breaks ATI OpenGL shader compiler // if ( all( something, something ) ) using this instead bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); bool inFrustum = all( inFrustumVec ); // don't shadow pixels outside of light frustum // use just first frustum (for cascades) // don't shadow pixels behind far plane of light frustum #ifdef SHADOWMAP_CASCADE inFrustumCount += int( inFrustum ); bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 ); #else bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); #endif bool frustumTest = all( frustumTestVec ); if ( frustumTest ) { shadowCoord.z += shadowBias[ <%= i %> ]; #if defined( SHADOWMAP_TYPE_PCF ) // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ float shadow = 0.0; /* // 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 = texture( shadowMap[ <%= i %> ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ); // doesn't seem to produce any noticeable visual difference compared to simple texture lookup //vec4 rgbaDepth = textureProj( 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; */ const float shadowDelta = 1.0 / 9.0; float xPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].x; float yPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].y; float dx0 = -1.25 * xPixelOffset; float dy0 = -1.25 * yPixelOffset; float dx1 = 1.25 * xPixelOffset; float dy1 = 1.25 * yPixelOffset; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; fDepth = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); if ( fDepth < shadowCoord.z ) shadow += shadowDelta; shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ <%= i %> ] * shadow ) ); #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ float shadow = 0.0; float xPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].x; float yPixelOffset = 1.0 / shadowMapSize[ <%= i %> ].y; float dx0 = -1.0 * xPixelOffset; float dy0 = -1.0 * yPixelOffset; float dx1 = 1.0 * xPixelOffset; float dy1 = 1.0 * yPixelOffset; mat3 shadowKernel; mat3 depthKernel; depthKernel[0][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy0 ) ) ); depthKernel[0][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, 0.0 ) ) ); depthKernel[0][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx0, dy1 ) ) ); depthKernel[1][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy0 ) ) ); depthKernel[1][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy ) ); depthKernel[1][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( 0.0, dy1 ) ) ); depthKernel[2][0] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy0 ) ) ); depthKernel[2][1] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, 0.0 ) ) ); depthKernel[2][2] = unpackDepth( texture( shadowMap[ <%= i %> ], shadowCoord.xy + vec2( dx1, dy1 ) ) ); vec3 shadowZ = vec3( shadowCoord.z ); shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ )); shadowKernel[0] *= vec3(0.25); shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ )); shadowKernel[1] *= vec3(0.25); shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ )); shadowKernel[2] *= vec3(0.25); vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[<%= i %>].xy ); shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x ); shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x ); 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 ) ); shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ <%= i %> ] * shadow ) ); #else vec4 rgbaDepth = texture( shadowMap[ <%= i %> ], shadowCoord.xy ); float fDepth = unpackDepth( rgbaDepth ); if ( fDepth < shadowCoord.z ) // spot with multiple shadows is darker shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ <%= i %> ] ); // spot with multiple shadows has the same color as single shadow spot // shadowColor = min( shadowColor, vec3( shadowDarkness[ <%= i %> ] ) ); #endif } #ifdef SHADOWMAP_DEBUG #ifdef SHADOWMAP_CASCADE if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ <%= i %> ]; #else if ( inFrustum ) outgoingLight *= frustumColors[ <%= i %> ]; #endif #endif <% end %> // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014 shadowColor = inputToLinear( shadowColor ); outgoingLight = outgoingLight * shadowColor; #endif