244 lines
7.7 KiB
GLSL
244 lines
7.7 KiB
GLSL
#ifdef USE_SHADOWMAP
|
|
|
|
#if NUM_DIR_LIGHTS > 0
|
|
|
|
uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
|
|
varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
|
|
|
|
#endif
|
|
|
|
#if NUM_SPOT_LIGHTS > 0
|
|
|
|
uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];
|
|
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];
|
|
|
|
#endif
|
|
|
|
#if NUM_POINT_LIGHTS > 0
|
|
|
|
uniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];
|
|
varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];
|
|
|
|
#endif
|
|
|
|
/*
|
|
#if NUM_RECT_AREA_LIGHTS > 0
|
|
|
|
// TODO (abelnation): create uniforms for area light shadows
|
|
|
|
#endif
|
|
*/
|
|
|
|
float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {
|
|
|
|
return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );
|
|
|
|
}
|
|
|
|
float texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {
|
|
|
|
const vec2 offset = vec2( 0.0, 1.0 );
|
|
|
|
vec2 texelSize = vec2( 1.0 ) / size;
|
|
vec2 centroidUV = floor( uv * size + 0.5 ) / size;
|
|
|
|
float lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );
|
|
float lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );
|
|
float rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );
|
|
float rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );
|
|
|
|
vec2 f = fract( uv * size + 0.5 );
|
|
|
|
float a = mix( lb, lt, f.y );
|
|
float b = mix( rb, rt, f.y );
|
|
float c = mix( a, b, f.x );
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {
|
|
|
|
float shadow = 1.0;
|
|
|
|
shadowCoord.xyz /= shadowCoord.w;
|
|
shadowCoord.z += shadowBias;
|
|
|
|
// 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 );
|
|
|
|
bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
|
|
|
|
bool frustumTest = all( frustumTestVec );
|
|
|
|
if ( frustumTest ) {
|
|
|
|
#if defined( SHADOWMAP_TYPE_PCF )
|
|
|
|
vec2 texelSize = vec2( 1.0 ) / shadowMapSize;
|
|
|
|
float dx0 = - texelSize.x * shadowRadius;
|
|
float dy0 = - texelSize.y * shadowRadius;
|
|
float dx1 = + texelSize.x * shadowRadius;
|
|
float dy1 = + texelSize.y * shadowRadius;
|
|
|
|
shadow = (
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
|
|
texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
|
|
) * ( 1.0 / 9.0 );
|
|
|
|
#elif defined( SHADOWMAP_TYPE_PCF_SOFT )
|
|
|
|
vec2 texelSize = vec2( 1.0 ) / shadowMapSize;
|
|
|
|
float dx0 = - texelSize.x * shadowRadius;
|
|
float dy0 = - texelSize.y * shadowRadius;
|
|
float dx1 = + texelSize.x * shadowRadius;
|
|
float dy1 = + texelSize.y * shadowRadius;
|
|
|
|
shadow = (
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
|
|
texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
|
|
) * ( 1.0 / 9.0 );
|
|
|
|
#else // no percentage-closer filtering:
|
|
|
|
shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return shadow;
|
|
|
|
}
|
|
|
|
// cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D
|
|
// vector suitable for 2D texture mapping. This code uses the following layout for the
|
|
// 2D texture:
|
|
//
|
|
// xzXZ
|
|
// y Y
|
|
//
|
|
// Y - Positive y direction
|
|
// y - Negative y direction
|
|
// X - Positive x direction
|
|
// x - Negative x direction
|
|
// Z - Positive z direction
|
|
// z - Negative z direction
|
|
//
|
|
// Source and test bed:
|
|
// https://gist.github.com/tschw/da10c43c467ce8afd0c4
|
|
|
|
vec2 cubeToUV( vec3 v, float texelSizeY ) {
|
|
|
|
// Number of texels to avoid at the edge of each square
|
|
|
|
vec3 absV = abs( v );
|
|
|
|
// Intersect unit cube
|
|
|
|
float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );
|
|
absV *= scaleToCube;
|
|
|
|
// Apply scale to avoid seams
|
|
|
|
// two texels less per square (one texel will do for NEAREST)
|
|
v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );
|
|
|
|
// Unwrap
|
|
|
|
// space: -1 ... 1 range for each square
|
|
//
|
|
// #X## dim := ( 4 , 2 )
|
|
// # # center := ( 1 , 1 )
|
|
|
|
vec2 planar = v.xy;
|
|
|
|
float almostATexel = 1.5 * texelSizeY;
|
|
float almostOne = 1.0 - almostATexel;
|
|
|
|
if ( absV.z >= almostOne ) {
|
|
|
|
if ( v.z > 0.0 )
|
|
planar.x = 4.0 - v.x;
|
|
|
|
} else if ( absV.x >= almostOne ) {
|
|
|
|
float signX = sign( v.x );
|
|
planar.x = v.z * signX + 2.0 * signX;
|
|
|
|
} else if ( absV.y >= almostOne ) {
|
|
|
|
float signY = sign( v.y );
|
|
planar.x = v.x + 2.0 * signY + 2.0;
|
|
planar.y = v.z * signY - 2.0;
|
|
|
|
}
|
|
|
|
// Transform to UV space
|
|
|
|
// scale := 0.5 / dim
|
|
// translate := ( center + 0.5 ) / dim
|
|
return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );
|
|
|
|
}
|
|
|
|
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 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 );
|
|
|
|
#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )
|
|
|
|
vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;
|
|
|
|
return (
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +
|
|
texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )
|
|
) * ( 1.0 / 9.0 );
|
|
|
|
#else // no percentage-closer filtering
|
|
|
|
return texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|