diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl new file mode 100644 index 00000000000..67b0fc2bdfc --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/shadow_copy_frag.glsl @@ -0,0 +1,210 @@ +/* Copy the depth only shadowmap into another texture while converting + * to linear depth (or other storage method) and doing a 3x3 box filter. */ + +layout(std140) uniform shadow_render_block { + mat4 ShadowMatrix[6]; + mat4 FaceViewMatrix[6]; + vec4 lampPosition; + float cubeTexelSize; + float storedTexelSize; + float nearClip; + float farClip; + int shadowSampleCount; + float shadowInvSampleCount; +}; + +#ifdef CSM +uniform sampler2DArray shadowTexture; +uniform int cascadeId; +#else +uniform samplerCube shadowTexture; +uniform int faceId; +#endif +uniform float shadowFilterSize; + +out vec4 FragColor; + +float linear_depth(float z) +{ + return (nearClip * farClip) / (z * (nearClip - farClip) + farClip); +} + +vec4 linear_depth(vec4 z) +{ + return (nearClip * farClip) / (z * (nearClip - farClip) + farClip); +} + +#ifdef CSM +vec4 get_world_distance(vec4 depths, vec3 cos[4]) +{ + /* Background case */ + vec4 is_background = step(vec4(0.99999), depths); + depths *= abs(farClip - nearClip); /* Same factor as in shadow_cascade(). */ + depths += 1e1 * is_background; + return depths; +} + +float get_world_distance(float depth, vec3 cos) +{ + /* Background case */ + float is_background = step(0.9999, depth); + depth *= abs(farClip - nearClip); /* Same factor as in shadow_cascade(). */ + depth += 1e1 * is_background; + return depth; +} +#else /* CUBEMAP */ +vec4 get_world_distance(vec4 depths, vec3 cos[4]) +{ + vec4 is_background = step(vec4(1.0), depths); + depths = linear_depth(depths); + depths += vec4(1e1) * is_background; + cos[0] = normalize(abs(cos[0])); + cos[1] = normalize(abs(cos[1])); + cos[2] = normalize(abs(cos[2])); + cos[3] = normalize(abs(cos[3])); + vec4 cos_vec; + cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z)); + cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z)); + cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z)); + cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z)); + return depths / cos_vec; +} + +float get_world_distance(float depth, vec3 cos) +{ + float is_background = step(1.0, depth); + depth = linear_depth(depth); + depth += 1e1 * is_background; + cos = normalize(abs(cos)); + float cos_vec = max(cos.x, max(cos.y, cos.z)); + return depth / cos_vec; +} +#endif + +/* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */ +float ln_space_prefilter(float w0, float x, float w1, float y) +{ + return x + log(w0 + w1 * exp(y - x)); +} + +#define SAMPLE_WEIGHT 0.11111 + +#ifdef ESM +void prefilter(vec4 depths, inout float accum) +{ + accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.x); + accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.y); + accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.z); + accum = ln_space_prefilter(1.0, accum, SAMPLE_WEIGHT, depths.w); +} +#else /* VSM */ +void prefilter(vec4 depths, inout vec2 accum) +{ + vec4 depths_sqr = depths * depths; + accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT; +} +#endif + +#ifdef CSM +vec3 get_texco(vec2 uvs, vec2 ofs) +{ + return vec3(uvs + ofs, float(cascadeId)); +} +#else /* CUBEMAP */ +const vec3 minorAxisX[6] = vec3[6]( + vec3(0.0f, 0.0f, -1.0f), + vec3(0.0f, 0.0f, 1.0f), + vec3(1.0f, 0.0f, 0.0f), + vec3(1.0f, 0.0f, 0.0f), + vec3(1.0f, 0.0f, 0.0f), + vec3(-1.0f, 0.0f, 0.0f) +); + +const vec3 minorAxisY[6] = vec3[6]( + vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), + vec3(0.0f, 0.0f, -1.0f), + vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, -1.0f, 0.0f) +); + +const vec3 majorAxis[6] = vec3[6]( + vec3(1.0f, 0.0f, 0.0f), + vec3(-1.0f, 0.0f, 0.0f), + vec3(0.0f, 1.0f, 0.0f), + vec3(0.0f, -1.0f, 0.0f), + vec3(0.0f, 0.0f, 1.0f), + vec3(0.0f, 0.0f, -1.0f) +); + +vec3 get_texco(vec2 uvs, vec2 ofs) +{ + uvs += ofs; + return majorAxis[faceId] + uvs.x * minorAxisX[faceId] + uvs.y * minorAxisY[faceId]; +} +#endif + +void main() { + /* Copy the depth only shadowmap into another texture while converting + * to linear depth and do a 3x3 box blur. */ + +#ifdef CSM + vec2 uvs = gl_FragCoord.xy * storedTexelSize; +#else /* CUBEMAP */ + vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0; +#endif + + /* Center texel */ + vec3 co = get_texco(uvs, vec2(0.0)); + float depth = texture(shadowTexture, co).r; + depth = get_world_distance(depth, co); + + if (shadowFilterSize == 0.0) { +#ifdef ESM + FragColor = vec4(depth); +#else /* VSM */ + FragColor = vec2(depth, depth * depth).xyxy; +#endif + return; + } + +#ifdef ESM + float accum = ln_space_prefilter(0.0, 0.0, SAMPLE_WEIGHT, depth); +#else /* VSM */ + vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT; +#endif + +#ifdef CSM + vec3 ofs = vec3(1.0, 0.0, -1.0) * shadowFilterSize; +#else /* CUBEMAP */ + vec3 ofs = vec3(1.0, 0.0, -1.0) * shadowFilterSize; +#endif + + vec3 cos[4]; + cos[0] = get_texco(uvs, ofs.zz); + cos[1] = get_texco(uvs, ofs.yz); + cos[2] = get_texco(uvs, ofs.xz); + cos[3] = get_texco(uvs, ofs.zy); + + vec4 depths; + depths.x = texture(shadowTexture, cos[0]).r; + depths.y = texture(shadowTexture, cos[1]).r; + depths.z = texture(shadowTexture, cos[2]).r; + depths.w = texture(shadowTexture, cos[3]).r; + depths = get_world_distance(depths, cos); + prefilter(depths, accum); + + cos[0] = get_texco(uvs, ofs.xy); + cos[1] = get_texco(uvs, ofs.zx); + cos[2] = get_texco(uvs, ofs.yx); + cos[3] = get_texco(uvs, ofs.xx); + depths.x = texture(shadowTexture, cos[0]).r; + depths.y = texture(shadowTexture, cos[1]).r; + depths.z = texture(shadowTexture, cos[2]).r; + depths.w = texture(shadowTexture, cos[3]).r; + depths = get_world_distance(depths, cos); + prefilter(depths, accum); + + FragColor = vec2(accum).xyxy; +} |