HDR: Organize shadow-related files and add screen space shadows
This commit is contained in:
parent
249d5b6fcd
commit
eea955168e
15 changed files with 304 additions and 209 deletions
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
213
Shaders/HDR/shadows-include.frag
Normal file
213
Shaders/HDR/shadows-include.frag
Normal 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;
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue