diff --git a/Compositor/HDR/hdr.xml b/Compositor/HDR/hdr.xml index b88d69751..51390c204 100644 --- a/Compositor/HDR/hdr.xml +++ b/Compositor/HDR/hdr.xml @@ -776,6 +776,16 @@ csm1 csm2 csm3 + + + 7 + depth-stencil + 9 prefiltered-envmap diff --git a/Effects/Fallback/hdr-shadow.eff b/Effects/Fallback/hdr-shadow.eff index 8107ae4b7..a8667b927 100644 --- a/Effects/Fallback/hdr-shadow.eff +++ b/Effects/Fallback/hdr-shadow.eff @@ -17,6 +17,10 @@ false + + 1.1 + 4.0 + Shaders/HDR/geometry-shadow.vert Shaders/HDR/geometry-shadow.frag diff --git a/Effects/HDR/lighting.eff b/Effects/HDR/lighting.eff index be1df5ed7..7f37913fa 100644 --- a/Effects/HDR/lighting.eff +++ b/Effects/HDR/lighting.eff @@ -32,6 +32,7 @@ Shaders/HDR/trivial.vert Shaders/HDR/lighting.frag Shaders/HDR/gbuffer-include.frag + Shaders/HDR/shadows-include.frag Shaders/HDR/lighting-include.frag Shaders/HDR/aerial-perspective-include.frag @@ -60,6 +61,12 @@ sampler-2d 7 + + + shadow_tex + sampler-2d-shadow + 10 + dfg_lut @@ -71,11 +78,6 @@ sampler-cube 9 - - shadow_tex - sampler-2d-shadow - 10 - aerial_perspective_lut diff --git a/Effects/glass.eff b/Effects/glass.eff index 8e58a8a39..b6ee1d06e 100644 --- a/Effects/glass.eff +++ b/Effects/glass.eff @@ -537,6 +537,7 @@ gequal 1.0 0.0 + false 0 @@ -564,6 +565,7 @@ Shaders/HDR/geometry-transparent.vert Shaders/HDR/geometry-transparent.frag Shaders/HDR/gbuffer-include.frag + Shaders/HDR/shadows-include.frag Shaders/HDR/lighting-include.frag Shaders/HDR/aerial-perspective-include.frag @@ -582,6 +584,17 @@ float-vec4 material/diffuse + + + depth_tex + sampler-2d + 7 + + + shadow_tex + sampler-2d-shadow + 10 + dfg_lut @@ -593,11 +606,6 @@ sampler-cube 9 - - shadow_tex - sampler-2d-shadow - 10 - aerial_perspective_lut diff --git a/Effects/model-combined-transparent.eff b/Effects/model-combined-transparent.eff index c369166ef..d234ba2ba 100644 --- a/Effects/model-combined-transparent.eff +++ b/Effects/model-combined-transparent.eff @@ -30,6 +30,7 @@ and fallback to plain transparency when the model shader is disabled. gequal 1.0 0.0 + false 0 @@ -57,6 +58,7 @@ and fallback to plain transparency when the model shader is disabled. Shaders/HDR/geometry-transparent.vert Shaders/HDR/geometry-transparent.frag Shaders/HDR/gbuffer-include.frag + Shaders/HDR/shadows-include.frag Shaders/HDR/lighting-include.frag Shaders/HDR/aerial-perspective-include.frag @@ -75,6 +77,17 @@ and fallback to plain transparency when the model shader is disabled. float-vec4 material/diffuse + + + depth_tex + sampler-2d + 7 + + + shadow_tex + sampler-2d-shadow + 10 + dfg_lut @@ -86,11 +99,6 @@ and fallback to plain transparency when the model shader is disabled. sampler-cube 9 - - shadow_tex - sampler-2d-shadow - 10 - aerial_perspective_lut diff --git a/Effects/model-pbr-transparent.eff b/Effects/model-pbr-transparent.eff index 225552fa3..dde0e6068 100644 --- a/Effects/model-pbr-transparent.eff +++ b/Effects/model-pbr-transparent.eff @@ -30,6 +30,7 @@ gequal 1.0 0.0 + false 0 @@ -93,6 +94,7 @@ Shaders/HDR/geometry-pbr-transparent.vert Shaders/HDR/geometry-pbr-transparent.frag Shaders/HDR/gbuffer-include.frag + Shaders/HDR/shadows-include.frag Shaders/HDR/lighting-include.frag Shaders/HDR/aerial-perspective-include.frag @@ -159,6 +161,17 @@ float alpha-cutoff + + + depth_tex + sampler-2d + 7 + + + shadow_tex + sampler-2d-shadow + 10 + dfg_lut @@ -170,11 +183,6 @@ sampler-cube 9 - - shadow_tex - sampler-2d-shadow - 10 - aerial_perspective_lut diff --git a/Effects/model-transparent.eff b/Effects/model-transparent.eff index 1f9c26590..3d0c2dc03 100644 --- a/Effects/model-transparent.eff +++ b/Effects/model-transparent.eff @@ -138,6 +138,7 @@ gequal 1.0 0.0 + false 0 @@ -165,6 +166,7 @@ Shaders/HDR/geometry-transparent.vert Shaders/HDR/geometry-transparent.frag Shaders/HDR/gbuffer-include.frag + Shaders/HDR/shadows-include.frag Shaders/HDR/lighting-include.frag Shaders/HDR/aerial-perspective-include.frag @@ -183,6 +185,17 @@ float-vec4 material/diffuse + + + depth_tex + sampler-2d + 7 + + + shadow_tex + sampler-2d-shadow + 10 + dfg_lut @@ -194,11 +207,6 @@ sampler-cube 9 - - shadow_tex - sampler-2d-shadow - 10 - aerial_perspective_lut diff --git a/Effects/skydome.eff b/Effects/skydome.eff index 03de89cc0..f3adc3d83 100644 --- a/Effects/skydome.eff +++ b/Effects/skydome.eff @@ -308,6 +308,7 @@ greater 1.0 0.0 + false back @@ -334,6 +335,9 @@ hdr-envmap + + false + back Shaders/HDR/skydome.vert diff --git a/Shaders/HDR/geometry-combined.frag b/Shaders/HDR/geometry-combined.frag index b6593c01b..16780474f 100644 --- a/Shaders/HDR/geometry-combined.frag +++ b/Shaders/HDR/geometry-combined.frag @@ -14,7 +14,7 @@ uniform int normalmap_dds; uniform float normalmap_tiling; const float DEFAULT_COMBINED_METALNESS = 0.0; -const float DEFAULT_COMBINED_ROUGHNESS = 0.1; +const float DEFAULT_COMBINED_ROUGHNESS = 0.2; vec2 encodeNormal(vec3 n); vec3 decodeSRGB(vec3 screenRGB); diff --git a/Shaders/HDR/geometry-pbr-transparent.frag b/Shaders/HDR/geometry-pbr-transparent.frag index 0de99bbe3..418150ff0 100644 --- a/Shaders/HDR/geometry-pbr-transparent.frag +++ b/Shaders/HDR/geometry-pbr-transparent.frag @@ -18,13 +18,13 @@ uniform vec3 emissive_factor; uniform float alpha_cutoff; uniform mat4 osg_ViewMatrixInverse; - +uniform mat4 osg_ProjectionMatrix; uniform vec4 fg_Viewport; uniform vec3 fg_SunDirection; vec3 decodeSRGB(vec3 screenRGB); +float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip); vec3 getF0Reflectance(vec3 baseColor, float metallic); -float getShadowing(vec3 p, vec3 n, float NdotL); vec3 evaluateLight( vec3 baseColor, float metallic, @@ -78,7 +78,7 @@ void main() vec3 f0 = getF0Reflectance(baseColor.rgb, metallic); vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0); - float shadowFactor = getShadowing(ecPos, n, NdotL); + float shadowFactor = getShadowing(ecPos, n, l, osg_ProjectionMatrix); vec3 color = evaluateLight(baseColor.rgb, metallic, diff --git a/Shaders/HDR/geometry-transparent.frag b/Shaders/HDR/geometry-transparent.frag index 556d35263..d7d993fe3 100644 --- a/Shaders/HDR/geometry-transparent.frag +++ b/Shaders/HDR/geometry-transparent.frag @@ -10,14 +10,15 @@ in vec3 ecPos; uniform sampler2D color_tex; uniform mat4 osg_ViewMatrixInverse; +uniform mat4 osg_ProjectionMatrix; uniform vec4 fg_Viewport; uniform vec3 fg_SunDirection; const float DEFAULT_TRANSPARENT_ROUGHNESS = 0.1; vec3 decodeSRGB(vec3 screenRGB); +float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip); vec3 getF0Reflectance(vec3 baseColor, float metallic); -float getShadowing(vec3 p, vec3 n, float NdotL); vec3 evaluateLight( vec3 baseColor, float metallic, @@ -60,7 +61,7 @@ void main() vec3 f0 = getF0Reflectance(baseColor.rgb, 0.0); vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0); - float shadowFactor = getShadowing(ecPos, n, NdotL); + float shadowFactor = getShadowing(ecPos, n, l, osg_ProjectionMatrix); vec3 color = evaluateLight(baseColor, 0.0, diff --git a/Shaders/HDR/lighting-include.frag b/Shaders/HDR/lighting-include.frag index 24f85bb7c..09e62bbdd 100644 --- a/Shaders/HDR/lighting-include.frag +++ b/Shaders/HDR/lighting-include.frag @@ -2,184 +2,12 @@ uniform sampler2D dfg_lut; uniform samplerCube prefiltered_envmap; -uniform sampler2DShadow shadow_tex; -uniform mat4 fg_LightMatrix_csm0; -uniform mat4 fg_LightMatrix_csm1; -uniform mat4 fg_LightMatrix_csm2; -uniform mat4 fg_LightMatrix_csm3; - -// Shadow mapping constants -const int sun_atlas_size = 8192; -const float DEPTH_BIAS = 2.0; -const float BAND_SIZE = 0.1; -const vec2 BAND_BOTTOM_LEFT = vec2(BAND_SIZE); -const vec2 BAND_TOP_RIGHT = vec2(1.0 - BAND_SIZE); -// Ideally these should be passed as an uniform, but we don't support uniform -// arrays yet -const vec2 uv_shifts[4] = vec2[4]( - vec2(0.0, 0.0), vec2(0.5, 0.0), - vec2(0.0, 0.5), vec2(0.5, 0.5)); -const vec2 uv_factor = vec2(0.5, 0.5); - -// BRDF constants const float PI = 3.14159265359; const float RECIPROCAL_PI = 0.31830988618; const float DIELECTRIC_SPECULAR = 0.04; const float MAX_PREFILTERED_LOD = 4.0; -//------------------------------------------------------------------------------ -// Shadow mapping related stuff - -float sampleOffset(vec4 pos, vec2 offset, vec2 invTexelSize) -{ - return texture( - shadow_tex, vec3( - pos.xy + offset * invTexelSize, - pos.z - DEPTH_BIAS * invTexelSize)); -} - -// OptimizedPCF from https://github.com/TheRealMJP/Shadows -// Original by Ignacio Castaño for The Witness -// Released under The MIT License -float sampleOptimizedPCF(vec4 pos) -{ - vec2 invTexSize = vec2(1.0 / float(sun_atlas_size)); - - vec2 uv = pos.xy * sun_atlas_size; - vec2 base_uv = floor(uv + 0.5); - float s = (uv.x + 0.5 - base_uv.x); - float t = (uv.y + 0.5 - base_uv.y); - base_uv -= vec2(0.5); - base_uv *= invTexSize; - pos.xy = base_uv.xy; - - float sum = 0.0; - - float uw0 = (4.0 - 3.0 * s); - float uw1 = 7.0; - float uw2 = (1.0 + 3.0 * s); - - float u0 = (3.0 - 2.0 * s) / uw0 - 2.0; - float u1 = (3.0 + s) / uw1; - float u2 = s / uw2 + 2.0; - - float vw0 = (4.0 - 3.0 * t); - float vw1 = 7.0; - float vw2 = (1.0 + 3.0 * t); - - float v0 = (3.0 - 2.0 * t) / vw0 - 2.0; - float v1 = (3.0 + t) / vw1; - float v2 = t / vw2 + 2.0; - - sum += uw0 * vw0 * sampleOffset(pos, vec2(u0, v0), invTexSize); - sum += uw1 * vw0 * sampleOffset(pos, vec2(u1, v0), invTexSize); - sum += uw2 * vw0 * sampleOffset(pos, vec2(u2, v0), invTexSize); - - sum += uw0 * vw1 * sampleOffset(pos, vec2(u0, v1), invTexSize); - sum += uw1 * vw1 * sampleOffset(pos, vec2(u1, v1), invTexSize); - sum += uw2 * vw1 * sampleOffset(pos, vec2(u2, v1), invTexSize); - - sum += uw0 * vw2 * sampleOffset(pos, vec2(u0, v2), invTexSize); - sum += uw1 * vw2 * sampleOffset(pos, vec2(u1, v2), invTexSize); - sum += uw2 * vw2 * sampleOffset(pos, vec2(u2, v2), invTexSize); - - return sum / 144.0; -} - -float sampleCascade(vec4 p, vec2 shift) -{ - vec4 pos = p; - pos.xy *= uv_factor; - pos.xy += shift; - return sampleOptimizedPCF(pos); -} - -float sampleAndBlendBand(vec4 p1, vec4 p2, vec2 s1, vec2 s2) -{ - vec2 s = smoothstep(vec2(0.0), BAND_BOTTOM_LEFT, p1.xy) - - smoothstep(BAND_TOP_RIGHT, vec2(1.0), p1.xy); - float blend = 1.0 - s.x * s.y; - return mix(sampleCascade(p1, s1), - sampleCascade(p2, s2), - blend); -} - -bool checkWithinBounds(vec2 coords, vec2 bottomLeft, vec2 topRight) -{ - vec2 r = step(bottomLeft, coords) - step(topRight, coords); - return bool(r.x * r.y); -} - -bool isInsideCascade(vec4 p) -{ - return checkWithinBounds(p.xy, vec2(0.0), vec2(1.0)) && ((p.z / p.w) <= 1.0); -} - -bool isInsideBand(vec4 p) -{ - return !checkWithinBounds(p.xy, BAND_BOTTOM_LEFT, BAND_TOP_RIGHT); -} - -/** - * Get the light space position of point p. - * Both p and n must be in view space. The light matrix is also assumed to - * transform from view space to light space. - */ -vec4 getLightSpacePosition(vec3 p, vec3 n, float NdotL, float bias, - mat4 lightMatrix) -{ - float sinTheta = sqrt(1.0 - NdotL * NdotL); - vec3 offset = p + n * (sinTheta * bias); - return lightMatrix * vec4(offset, 1.0); -} - -/** - * Get shadowing factor for a given position. 1.0 corresponds to a fragment - * being completely lit, and 0.0 to a fragment being completely in shadow. - * Both p and n must be in view space. - */ -float getShadowing(vec3 p, vec3 n, float NdotL) -{ - // Ignore fragments that don't face the light - if (NdotL <= 0.0) - return 0.0; - - float shadow = 1.0; - - vec4 lightSpacePos[4]; - lightSpacePos[0] = getLightSpacePosition(p, n, NdotL, 0.05, fg_LightMatrix_csm0); - lightSpacePos[1] = getLightSpacePosition(p, n, NdotL, 0.1, fg_LightMatrix_csm1); - lightSpacePos[2] = getLightSpacePosition(p, n, NdotL, 0.5, fg_LightMatrix_csm2); - lightSpacePos[3] = getLightSpacePosition(p, n, NdotL, 1.0, fg_LightMatrix_csm3); - - for (int i = 0; i < 4; ++i) { - // Map-based cascade selection - // We test if we are inside the cascade bounds to find the tightest - // map that contains the fragment. - if (isInsideCascade(lightSpacePos[i])) { - if (isInsideBand(lightSpacePos[i]) && ((i+1) < 4)) { - // Blend between cascades if the fragment is near the - // next cascade to avoid abrupt transitions. - shadow = clamp(sampleAndBlendBand(lightSpacePos[i], - lightSpacePos[i+1], - uv_shifts[i], - uv_shifts[i+1]), - 0.0, 1.0); - } else { - // We are far away from the borders of the cascade, so - // we skip the blending to avoid the performance cost - // of sampling the shadow map twice. - shadow = clamp(sampleCascade(lightSpacePos[i], uv_shifts[i]), - 0.0, 1.0); - } - break; - } - } - - return shadow; -} - //------------------------------------------------------------------------------ // BRDF utility functions diff --git a/Shaders/HDR/lighting.frag b/Shaders/HDR/lighting.frag index ae23d1d35..c83619b5a 100644 --- a/Shaders/HDR/lighting.frag +++ b/Shaders/HDR/lighting.frag @@ -11,12 +11,13 @@ uniform sampler2D depth_tex; uniform sampler2D ao_tex; uniform mat4 fg_ViewMatrixInverse; +uniform mat4 fg_ProjectionMatrix; uniform vec3 fg_SunDirection; vec3 decodeNormal(vec2 enc); vec3 positionFromDepth(vec2 pos, float depth); +float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip); vec3 getF0Reflectance(vec3 baseColor, float metallic); -float getShadowing(vec3 p, vec3 n, float NdotL); vec3 evaluateLight( vec3 baseColor, float metallic, @@ -69,7 +70,7 @@ void main() vec3 f0 = getF0Reflectance(baseColor, metallic); vec3 sunIlluminance = getSunIntensity() * clamp(NdotL, 0.0, 1.0); - float shadowFactor = getShadowing(pos, n, NdotL); + float shadowFactor = getShadowing(pos, n, l, fg_ProjectionMatrix); vec3 color = evaluateLight(baseColor, metallic, diff --git a/Shaders/HDR/shadows-include.frag b/Shaders/HDR/shadows-include.frag new file mode 100644 index 000000000..c43911dc2 --- /dev/null +++ b/Shaders/HDR/shadows-include.frag @@ -0,0 +1,213 @@ +#version 330 core + +uniform sampler2D depth_tex; // For Screen Space Shadows +uniform sampler2DShadow shadow_tex; + +uniform mat4 fg_LightMatrix_csm0; +uniform mat4 fg_LightMatrix_csm1; +uniform mat4 fg_LightMatrix_csm2; +uniform mat4 fg_LightMatrix_csm3; + +const float NORMAL_BIAS = 0.02; +const float BAND_SIZE = 0.1; +const vec2 BAND_BOTTOM_LEFT = vec2(BAND_SIZE); +const vec2 BAND_TOP_RIGHT = vec2(1.0 - BAND_SIZE); +// Ideally these should be passed as an uniform, but we don't support uniform +// arrays yet +const vec2 uv_shifts[4] = vec2[4]( + vec2(0.0, 0.0), vec2(0.5, 0.0), + vec2(0.0, 0.5), vec2(0.5, 0.5)); +const vec2 uv_factor = vec2(0.5, 0.5); + +const float SSS_THICKNESS = 0.1; +const uint SSS_NUM_STEPS = 32u; +const float SSS_MAX_DISTANCE = 0.05; +const vec3 DITHER_MAGIC = vec3(0.06711056, 0.00583715, 52.9829189); + +float sampleMap(vec2 coord, vec2 offset, float depth) +{ + return texture(shadow_tex, vec3(coord + offset, depth)); +} + +// OptimizedPCF from https://github.com/TheRealMJP/Shadows +// Original by Ignacio Castaño for The Witness +// Released under The MIT License +float sampleOptimizedPCF(vec4 pos, vec2 mapSize) +{ + vec2 texelSize = vec2(1.0) / mapSize; + + vec2 offset = vec2(0.5); + vec2 uv = (pos.xy * mapSize) + offset; + vec2 base = (floor(uv) - offset) * texelSize; + vec2 st = fract(uv); + + vec3 uw = vec3(4.0 - 3.0 * st.x, 7.0, 1.0 + 3.0 * st.x); + vec3 vw = vec3(4.0 - 3.0 * st.y, 7.0, 1.0 + 3.0 * st.y); + + vec3 u = vec3((3.0 - 2.0 * st.x) / uw.x - 2.0, (3.0 + st.x) / uw.y, st.x / uw.z + 2.0); + vec3 v = vec3((3.0 - 2.0 * st.y) / vw.x - 2.0, (3.0 + st.y) / vw.y, st.y / vw.z + 2.0); + + u *= texelSize.x; + v *= texelSize.y; + + float depth = pos.z; + float sum = 0.0; + + sum += uw.x * vw.x * sampleMap(base, vec2(u.x, v.x), depth); + sum += uw.y * vw.x * sampleMap(base, vec2(u.y, v.x), depth); + sum += uw.z * vw.x * sampleMap(base, vec2(u.z, v.x), depth); + + sum += uw.x * vw.y * sampleMap(base, vec2(u.x, v.y), depth); + sum += uw.y * vw.y * sampleMap(base, vec2(u.y, v.y), depth); + sum += uw.z * vw.y * sampleMap(base, vec2(u.z, v.y), depth); + + sum += uw.x * vw.z * sampleMap(base, vec2(u.x, v.z), depth); + sum += uw.y * vw.z * sampleMap(base, vec2(u.y, v.z), depth); + sum += uw.z * vw.z * sampleMap(base, vec2(u.z, v.z), depth); + + return sum / 144.0; +} + +float sampleCascade(vec4 p, vec2 shift, vec2 mapSize) +{ + vec4 pos = p; + pos.xy *= uv_factor; + pos.xy += shift; + return sampleOptimizedPCF(pos, mapSize); +} + +float sampleAndBlendBand(vec4 p1, vec4 p2, vec2 s1, vec2 s2, vec2 mapSize) +{ + vec2 s = smoothstep(vec2(0.0), BAND_BOTTOM_LEFT, p1.xy) + - smoothstep(BAND_TOP_RIGHT, vec2(1.0), p1.xy); + float blend = 1.0 - s.x * s.y; + return mix(sampleCascade(p1, s1, mapSize), + sampleCascade(p2, s2, mapSize), + blend); +} + +bool checkWithinBounds(vec2 coords, vec2 bottomLeft, vec2 topRight) +{ + vec2 r = step(bottomLeft, coords) - step(topRight, coords); + return bool(r.x * r.y); +} + +bool isInsideCascade(vec4 p) +{ + return checkWithinBounds(p.xy, vec2(0.0), vec2(1.0)) && ((p.z / p.w) <= 1.0); +} + +bool isInsideBand(vec4 p) +{ + return !checkWithinBounds(p.xy, BAND_BOTTOM_LEFT, BAND_TOP_RIGHT); +} + +/** + * Get the light space position of point p. + * Both p and n must be in view space. The light matrix is also assumed to + * transform from view space to light space. + */ +vec4 getLightSpacePosition(vec3 p, vec3 n, float NdotL, mat4 lightMatrix) +{ + float sinTheta = sqrt(1.0 - NdotL * NdotL); + vec3 offsetPos = p + n * (sinTheta * NORMAL_BIAS); + return lightMatrix * vec4(offsetPos, 1.0); +} + +/** + * Screen Space Shadows + * Implementation mostly from: + * https://panoskarabelas.com/posts/screen_space_shadows/ + * Marching done in screen space instead of in view space. + */ +float getContactShadow(vec3 p, vec3 l, mat4 viewToClip) +{ + // Ray start and end points in view space + vec3 viewRayStart = p; + vec3 viewRayEnd = viewRayStart + l * SSS_MAX_DISTANCE; + // To clip space + vec4 clipRayStart = viewToClip * vec4(viewRayStart, 1.0); + vec4 clipRayEnd = viewToClip * vec4(viewRayEnd, 1.0); + // Perspective divide + vec3 rayStart = clipRayStart.xyz / clipRayStart.w; + vec3 rayEnd = clipRayEnd.xyz / clipRayEnd.w; + // From [-1,1] to [0,1] to sample directly from textures + rayStart = rayStart * 0.5 + 0.5; + rayEnd = rayEnd * 0.5 + 0.5; + + vec3 ray = rayEnd - rayStart; + + float dither = fract(DITHER_MAGIC.z * fract(dot(gl_FragCoord.xy, DITHER_MAGIC.xy))); + + float dt = 1.0 / float(SSS_NUM_STEPS); + float t = dt * dither + dt; + + float shadow = 0.0; + + for (uint i = 0u; i < SSS_NUM_STEPS; ++i) { + vec3 samplePos = rayStart + ray * t; + // Reversed depth buffer, invert it + float sampleDepth = 1.0 - texture(depth_tex, samplePos.xy).r; + float dz = samplePos.z - sampleDepth; + if (dz > 0.00001 && dz < SSS_THICKNESS) { + shadow = 1.0; + // TODO: Add screen fading + break; + } + t += dt; + } + + return 1.0 - shadow; +} + +/** + * Get shadowing factor for a given position. 1.0 corresponds to a fragment + * being completely lit, and 0.0 to a fragment being completely in shadow. + * Both p and n must be in view space. + * viewToClip transforms a point from view space to clip space. Used for SSS. + */ +float getShadowing(vec3 p, vec3 n, vec3 l, mat4 viewToClip) +{ + float NdotL = clamp(dot(n, l), 0.0, 1.0); + + vec4 lightSpacePos[4]; + lightSpacePos[0] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm0); + lightSpacePos[1] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm1); + lightSpacePos[2] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm2); + lightSpacePos[3] = getLightSpacePosition(p, n, NdotL, fg_LightMatrix_csm3); + + vec2 mapSize = vec2(textureSize(shadow_tex, 0)); + float visibility = 1.0; + + for (int i = 0; i < 4; ++i) { + // Map-based cascade selection + // We test if we are inside the cascade bounds to find the tightest + // map that contains the fragment. + if (isInsideCascade(lightSpacePos[i])) { + if (isInsideBand(lightSpacePos[i]) && ((i+1) < 4)) { + // Blend between cascades if the fragment is near the + // next cascade to avoid abrupt transitions. + visibility = clamp(sampleAndBlendBand(lightSpacePos[i], + lightSpacePos[i+1], + uv_shifts[i], + uv_shifts[i+1], + mapSize), + 0.0, 1.0); + } else { + // We are far away from the borders of the cascade, so + // we skip the blending to avoid the performance cost + // of sampling the shadow map twice. + visibility = clamp(sampleCascade(lightSpacePos[i], + uv_shifts[i], + mapSize), + 0.0, 1.0); + } + break; + } + } + + if (visibility > 0.0) + visibility *= getContactShadow(p, l, viewToClip); + + return visibility; +} diff --git a/defaults.xml b/defaults.xml index be2a51139..e9bfbc92d 100644 --- a/defaults.xml +++ b/defaults.xml @@ -384,14 +384,14 @@ Started September 2000 by David Megginson, david@megginson.com true + 2 + 0.0 + 1.0 + 6.0 false false - 0.0 - 1.0 - 6.0 - 2 true