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
+
+
+ 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
+
+
+ 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
+
+
+ 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
+
+
+ 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