1
0
Fork 0

HDR: Organize shadow-related files and add screen space shadows

This commit is contained in:
Fernando García Liñán 2021-08-24 23:31:03 +02:00
parent 249d5b6fcd
commit eea955168e
15 changed files with 304 additions and 209 deletions

View file

@ -776,6 +776,16 @@
<use-shadow-pass>csm1</use-shadow-pass>
<use-shadow-pass>csm2</use-shadow-pass>
<use-shadow-pass>csm3</use-shadow-pass>
<!--
We should not be binding and attaching the depth buffer as that usually
implies reading and writing to it at the same time, which will result in
undefined behaviour. However, in the forward pass we don't write to the
depth buffer (all Effects that use hdr-forward have write-mask=false).
-->
<binding>
<unit>7</unit>
<buffer>depth-stencil</buffer>
</binding>
<binding>
<unit>9</unit>
<buffer>prefiltered-envmap</buffer>

View file

@ -17,6 +17,10 @@
<blend>
<active>false</active>
</blend>
<polygon-offset>
<factor>1.1</factor>
<units>4.0</units>
</polygon-offset>
<program>
<vertex-shader>Shaders/HDR/geometry-shadow.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-shadow.frag</fragment-shader>

View file

@ -32,6 +32,7 @@
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
<fragment-shader>Shaders/HDR/lighting.frag</fragment-shader>
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
</program>
@ -60,6 +61,12 @@
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Lighting include -->
<uniform>
<name>dfg_lut</name>
@ -71,11 +78,6 @@
<type>sampler-cube</type>
<value type="int">9</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Aerial perspective include -->
<uniform>
<name>aerial_perspective_lut</name>

View file

@ -537,6 +537,7 @@
<function>gequal</function>
<near>1.0</near>
<far>0.0</far>
<write-mask>false</write-mask>
</depth>
<texture-unit>
<unit>0</unit>
@ -564,6 +565,7 @@
<vertex-shader>Shaders/HDR/geometry-transparent.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-transparent.frag</fragment-shader>
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
</program>
@ -582,6 +584,17 @@
<type>float-vec4</type>
<value><use>material/diffuse</use></value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Lighting include -->
<uniform>
<name>dfg_lut</name>
@ -593,11 +606,6 @@
<type>sampler-cube</type>
<value type="int">9</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Aerial perspective include -->
<uniform>
<name>aerial_perspective_lut</name>

View file

@ -30,6 +30,7 @@ and fallback to plain transparency when the model shader is disabled.
<function>gequal</function>
<near>1.0</near>
<far>0.0</far>
<write-mask>false</write-mask>
</depth>
<texture-unit>
<unit>0</unit>
@ -57,6 +58,7 @@ and fallback to plain transparency when the model shader is disabled.
<vertex-shader>Shaders/HDR/geometry-transparent.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-transparent.frag</fragment-shader>
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
</program>
@ -75,6 +77,17 @@ and fallback to plain transparency when the model shader is disabled.
<type>float-vec4</type>
<value><use>material/diffuse</use></value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Lighting include -->
<uniform>
<name>dfg_lut</name>
@ -86,11 +99,6 @@ and fallback to plain transparency when the model shader is disabled.
<type>sampler-cube</type>
<value type="int">9</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Aerial perspective include -->
<uniform>
<name>aerial_perspective_lut</name>

View file

@ -30,6 +30,7 @@
<function>gequal</function>
<near>1.0</near>
<far>0.0</far>
<write-mask>false</write-mask>
</depth>
<texture-unit>
<unit>0</unit>
@ -93,6 +94,7 @@
<vertex-shader>Shaders/HDR/geometry-pbr-transparent.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-pbr-transparent.frag</fragment-shader>
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
<attribute>
@ -159,6 +161,17 @@
<type>float</type>
<value><use>alpha-cutoff</use></value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Lighting include -->
<uniform>
<name>dfg_lut</name>
@ -170,11 +183,6 @@
<type>sampler-cube</type>
<value type="int">9</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Aerial perspective include -->
<uniform>
<name>aerial_perspective_lut</name>

View file

@ -138,6 +138,7 @@
<function>gequal</function>
<near>1.0</near>
<far>0.0</far>
<write-mask>false</write-mask>
</depth>
<texture-unit>
<unit>0</unit>
@ -165,6 +166,7 @@
<vertex-shader>Shaders/HDR/geometry-transparent.vert</vertex-shader>
<fragment-shader>Shaders/HDR/geometry-transparent.frag</fragment-shader>
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/shadows-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/lighting-include.frag</fragment-shader>
<fragment-shader>Shaders/HDR/aerial-perspective-include.frag</fragment-shader>
</program>
@ -183,6 +185,17 @@
<type>float-vec4</type>
<value><use>material/diffuse</use></value>
</uniform>
<!-- Shadows include -->
<uniform>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">7</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Lighting include -->
<uniform>
<name>dfg_lut</name>
@ -194,11 +207,6 @@
<type>sampler-cube</type>
<value type="int">9</value>
</uniform>
<uniform>
<name>shadow_tex</name>
<type>sampler-2d-shadow</type>
<value type="int">10</value>
</uniform>
<!-- Aerial perspective include -->
<uniform>
<name>aerial_perspective_lut</name>

View file

@ -308,6 +308,7 @@
<function>greater</function>
<near>1.0</near>
<far>0.0</far>
<write-mask>false</write-mask>
</depth>
<cull-face>back</cull-face>
<program>
@ -334,6 +335,9 @@
<technique n="139">
<scheme>hdr-envmap</scheme>
<pass>
<depth>
<write-mask>false</write-mask>
</depth>
<cull-face>back</cull-face>
<program>
<vertex-shader>Shaders/HDR/skydome.vert</vertex-shader>

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

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

View file

@ -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,

View file

@ -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;
}

View file

@ -384,14 +384,14 @@ Started September 2000 by David Megginson, david@megginson.com
<enabled type="bool" userarchive="y">true</enabled>
</pilot-model>
<hdr>
<antialiasing-technique type="int" userarchive="y">2</antialiasing-technique>
<exposure-compensation type="float">0.0</exposure-compensation>
<bloom-magnitude type="float">1.0</bloom-magnitude>
<bloom-threshold type="float">6.0</bloom-threshold>
<debug>
<show-gbuffer type="bool">false</show-gbuffer>
<display-ev100 type="bool">false</display-ev100>
</debug>
<exposure-compensation type="float">0.0</exposure-compensation>
<bloom-magnitude type="float">1.0</bloom-magnitude>
<bloom-threshold type="float">6.0</bloom-threshold>
<antialiasing-technique type="int" userarchive="y">2</antialiasing-technique>
</hdr>
<composite-viewer-enabled type="bool">true</composite-viewer-enabled>
</rendering>