aboutsummaryrefslogtreecommitdiff
path: root/client/shaders/object_shader
diff options
context:
space:
mode:
authorDmitry Kostenko <codeforsmile@gmail.com>2021-11-03 23:39:30 +0100
committerx2048 <codeforsmile@gmail.com>2022-03-07 23:45:26 +0100
commit10be033791dd71af6ba3120eb6a397f27673c2bb (patch)
tree98d79c1081f258f4e6f14d7d51526698c41030e6 /client/shaders/object_shader
parent4e39cdef946e137519551bc77234bae2ee35a7f3 (diff)
downloadminetest-10be033791dd71af6ba3120eb6a397f27673c2bb.tar.gz
minetest-10be033791dd71af6ba3120eb6a397f27673c2bb.tar.bz2
minetest-10be033791dd71af6ba3120eb6a397f27673c2bb.zip
Copy shadow mapping shader from nodes to objects
Diffstat (limited to 'client/shaders/object_shader')
-rw-r--r--client/shaders/object_shader/opengl_fragment.glsl302
-rw-r--r--client/shaders/object_shader/opengl_vertex.glsl15
2 files changed, 235 insertions, 82 deletions
diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl
index 3390e7227..0b9dbc996 100644
--- a/client/shaders/object_shader/opengl_fragment.glsl
+++ b/client/shaders/object_shader/opengl_fragment.glsl
@@ -1,6 +1,7 @@
uniform sampler2D baseTexture;
uniform vec4 emissiveColor;
+uniform vec3 dayLight;
uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;
@@ -16,6 +17,8 @@ centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
+varying float nightRatio;
+
varying float vIDiff;
const float e = 2.718281828459;
@@ -31,53 +34,23 @@ const float fogShadingParameter = 1.0 / (1.0 - fogStart);
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
- uniform float f_timeofday;
varying float normalOffsetScale;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
#endif
-#if ENABLE_TONE_MAPPING
-/* Hable's UC2 Tone mapping parameters
- A = 0.22;
- B = 0.30;
- C = 0.10;
- D = 0.20;
- E = 0.01;
- F = 0.30;
- W = 11.2;
- equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
-*/
-
-vec3 uncharted2Tonemap(vec3 x)
-{
- return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
-}
-
-vec4 applyToneMapping(vec4 color)
-{
- color = vec4(pow(color.rgb, vec3(2.2)), color.a);
- const float gamma = 1.6;
- const float exposureBias = 5.5;
- color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
- // Precalculated white_scale from
- //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
- vec3 whiteScale = vec3(1.036015346);
- color.rgb *= whiteScale;
- return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
-}
-#endif
-
#ifdef ENABLE_DYNAMIC_SHADOWS
const float bias0 = 0.9;
const float zPersFactor = 0.5;
-const float bias1 = 1.0 - bias0;
+const float bias1 = 1.0 - bias0 + 1e-6;
vec4 getPerspectiveFactor(in vec4 shadowPosition)
{
+
float pDistance = length(shadowPosition.xy);
float pFactor = pDistance * bias0 + bias1;
+
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPersFactor);
return shadowPosition;
@@ -92,11 +65,23 @@ float getLinearDepth()
vec3 getLightSpacePosition()
{
vec4 pLightSpace;
- float normalBias = 0.0005 * getLinearDepth() * cosLight + normalOffsetScale;
- pLightSpace = m_ShadowViewProj * vec4(worldPosition + normalBias * normalize(vNormal), 1.0);
+ // some drawtypes have zero normals, so we need to handle it :(
+ #if DRAW_TYPE == NDT_PLANTLIKE
+ pLightSpace = m_ShadowViewProj * vec4(worldPosition, 1.0);
+ #else
+ float offsetScale = (0.0057 * getLinearDepth() + normalOffsetScale);
+ pLightSpace = m_ShadowViewProj * vec4(worldPosition + offsetScale * normalize(vNormal), 1.0);
+ #endif
pLightSpace = getPerspectiveFactor(pLightSpace);
return pLightSpace.xyz * 0.5 + 0.5;
}
+// custom smoothstep implementation because it's not defined in glsl1.2
+// https://docs.gl/sl4/smoothstep
+float mtsmoothstep(in float edge0, in float edge1, in float x)
+{
+ float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+ return t * t * (3.0 - 2.0 * t);
+}
#ifdef COLORED_SHADOWS
@@ -124,10 +109,10 @@ vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDist
{
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
- float visibility = step(0.0, (realDistance-2e-5) - texDepth.r);
+ float visibility = step(0.0, realDistance - texDepth.r);
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
if (visibility < 0.1) {
- visibility = step(0.0, (realDistance-2e-5) - texDepth.r);
+ visibility = step(0.0, realDistance - texDepth.b);
result = vec4(visibility, unpackColor(texDepth.a));
}
return result;
@@ -138,13 +123,13 @@ vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDist
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
- float visibility = step(0.0, (realDistance-2e-5) - texDepth);
-
+ float visibility = step(0.0, realDistance - texDepth);
return visibility;
}
#endif
+
#if SHADOW_FILTER == 2
#define PCFBOUND 3.5
#define PCFSAMPLES 64.0
@@ -163,6 +148,73 @@ float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
#define PCFSAMPLES 1.0
#endif
#endif
+#ifdef COLORED_SHADOWS
+float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
+{
+ vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
+ float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
+ return depth;
+}
+#else
+float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
+{
+ float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
+ float depth = realDistance - texDepth;
+ return depth;
+}
+#endif
+
+float getBaseLength(vec2 smTexCoord)
+{
+ float l = length(2.0 * smTexCoord.xy - 1.0); // length in texture coords
+ return bias1 / (1.0 / l - bias0); // return to undistorted coords
+}
+
+float getDeltaPerspectiveFactor(float l)
+{
+ return 0.1 / (bias0 * l + bias1); // original distortion factor, divided by 10
+}
+
+float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
+{
+ float baseLength = getBaseLength(smTexCoord);
+ float perspectiveFactor;
+
+ // Return fast if sharp shadows are requested
+ if (SOFTSHADOWRADIUS <= 1.0) {
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
+ return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
+ }
+
+ vec2 clampedpos;
+ float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
+ float y, x;
+ float depth = 0.0;
+ float pointDepth;
+ float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
+
+ float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
+ int n = 0;
+
+ for (y = -bound; y <= bound; y += 1.0)
+ for (x = -bound; x <= bound; x += 1.0) {
+ clampedpos = vec2(x,y);
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
+ clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
+
+ pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
+ if (pointDepth > -0.01) {
+ depth += pointDepth;
+ n += 1;
+ }
+ }
+
+ depth = depth / n;
+ depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
+
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
+ return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
+}
#ifdef POISSON_FILTER
const vec2[64] poissonDisk = vec2[64](
@@ -238,17 +290,28 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
{
vec2 clampedpos;
vec4 visibility = vec4(0.0);
+ float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
+ if (radius < 0.1) {
+ // we are in the middle of even brightness, no need for filtering
+ return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
+ }
+
+ float baseLength = getBaseLength(smTexCoord);
+ float perspectiveFactor;
float texture_size = 1.0 / (f_textureresolution * 0.5);
- int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-PCFSAMPLES)));
- int end_offset = int(PCFSAMPLES) + init_offset;
+ int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
+ int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
+ int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
- clampedpos = poissonDisk[x] * texture_size * SOFTSHADOWRADIUS + smTexCoord.xy;
+ clampedpos = poissonDisk[x];
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
+ clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
}
- return visibility / PCFSAMPLES;
+ return visibility / samples;
}
#else
@@ -257,17 +320,28 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec2 clampedpos;
float visibility = 0.0;
+ float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
+ if (radius < 0.1) {
+ // we are in the middle of even brightness, no need for filtering
+ return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
+ }
+
+ float baseLength = getBaseLength(smTexCoord);
+ float perspectiveFactor;
float texture_size = 1.0 / (f_textureresolution * 0.5);
- int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-PCFSAMPLES)));
- int end_offset = int(PCFSAMPLES) + init_offset;
+ int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
+ int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
+ int end_offset = int(samples) + init_offset;
for (int x = init_offset; x < end_offset; x++) {
- clampedpos = poissonDisk[x] * texture_size * SOFTSHADOWRADIUS + smTexCoord.xy;
+ clampedpos = poissonDisk[x];
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
+ clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
}
- return visibility / PCFSAMPLES;
+ return visibility / samples;
}
#endif
@@ -281,19 +355,31 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
{
vec2 clampedpos;
vec4 visibility = vec4(0.0);
- float sradius=0.0;
- if( PCFBOUND>0)
- sradius = SOFTSHADOWRADIUS / PCFBOUND;
+ float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
+ if (radius < 0.1) {
+ // we are in the middle of even brightness, no need for filtering
+ return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
+ }
+
+ float baseLength = getBaseLength(smTexCoord);
+ float perspectiveFactor;
+
float texture_size = 1.0 / (f_textureresolution * 0.5);
float y, x;
+ float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
+ int n = 0;
+
// basic PCF filter
- for (y = -PCFBOUND; y <= PCFBOUND; y += 1.0)
- for (x = -PCFBOUND; x <= PCFBOUND; x += 1.0) {
- clampedpos = vec2(x,y) * texture_size* sradius + smTexCoord.xy;
+ for (y = -bound; y <= bound; y += 1.0)
+ for (x = -bound; x <= bound; x += 1.0) {
+ clampedpos = vec2(x,y); // screen offset
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
+ clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
+ n += 1;
}
- return visibility / PCFSAMPLES;
+ return visibility / n;
}
#else
@@ -301,20 +387,31 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
{
vec2 clampedpos;
float visibility = 0.0;
- float sradius=0.0;
- if( PCFBOUND>0)
- sradius = SOFTSHADOWRADIUS / PCFBOUND;
-
+ float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
+ if (radius < 0.1) {
+ // we are in the middle of even brightness, no need for filtering
+ return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
+ }
+
+ float baseLength = getBaseLength(smTexCoord);
+ float perspectiveFactor;
+
float texture_size = 1.0 / (f_textureresolution * 0.5);
float y, x;
+ float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
+ int n = 0;
+
// basic PCF filter
- for (y = -PCFBOUND; y <= PCFBOUND; y += 1.0)
- for (x = -PCFBOUND; x <= PCFBOUND; x += 1.0) {
- clampedpos = vec2(x,y) * texture_size * sradius + smTexCoord.xy;
+ for (y = -bound; y <= bound; y += 1.0)
+ for (x = -bound; x <= bound; x += 1.0) {
+ clampedpos = vec2(x,y); // screen offset
+ perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
+ clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
+ n += 1;
}
- return visibility / PCFSAMPLES;
+ return visibility / n;
}
#endif
@@ -322,6 +419,37 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
#endif
#endif
+#if ENABLE_TONE_MAPPING
+/* Hable's UC2 Tone mapping parameters
+ A = 0.22;
+ B = 0.30;
+ C = 0.10;
+ D = 0.20;
+ E = 0.01;
+ F = 0.30;
+ W = 11.2;
+ equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
+*/
+
+vec3 uncharted2Tonemap(vec3 x)
+{
+ return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
+}
+
+vec4 applyToneMapping(vec4 color)
+{
+ color = vec4(pow(color.rgb, vec3(2.2)), color.a);
+ const float gamma = 1.6;
+ const float exposureBias = 5.5;
+ color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
+ // Precalculated white_scale from
+ //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
+ vec3 whiteScale = vec3(1.036015346);
+ color.rgb *= whiteScale;
+ return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
+}
+#endif
+
void main(void)
{
vec3 color;
@@ -350,28 +478,50 @@ void main(void)
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();
+ float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 20.0));
+ float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z ),0.0);
+
+ if (distance_rate > 1e-7) {
+
#ifdef COLORED_SHADOWS
- vec4 visibility;
- if (cosLight > 0.0)
- visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
- else
- visibility = vec4(1.0, 0.0, 0.0, 0.0);
- shadow_int = visibility.r;
- shadow_color = visibility.gba;
+ vec4 visibility;
+ if (cosLight > 0.0)
+ visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
+ else
+ visibility = vec4(1.0, 0.0, 0.0, 0.0);
+ shadow_int = visibility.r;
+ shadow_color = visibility.gba;
#else
- shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
+ if (cosLight > 0.0)
+ shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
+ else
+ shadow_int = 1.0;
#endif
+ shadow_int *= distance_rate;
+ shadow_int = clamp(shadow_int, 0.0, 1.0);
- if (f_normal_length != 0 && cosLight <= 0.001) {
- shadow_int = clamp(shadow_int + 0.5 * abs(cosLight), 0.0, 1.0);
}
- shadow_int = 1.0 - (shadow_int * adj_shadow_strength);
-
- col.rgb = mix(shadow_color, col.rgb, shadow_int) * shadow_int;
-#endif
+ // turns out that nightRatio falls off much faster than
+ // actual brightness of artificial light in relation to natual light.
+ // Power ratio was measured on torches in MTG (brightness = 14).
+ float adjusted_night_ratio = pow(nightRatio, 0.6);
+ if (f_normal_length != 0 && cosLight < 0.035) {
+ shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, 0.035)/0.035);
+ }
+ shadow_int *= f_adj_shadow_strength;
+
+ // calculate fragment color from components:
+ col.rgb =
+ adjusted_night_ratio * col.rgb + // artificial light
+ (1.0 - adjusted_night_ratio) * ( // natural light
+ col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
+ dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
+ // col.r = 0.5 * clamp(getPenumbraRadius(ShadowMapSampler, posLightSpace.xy, posLightSpace.z, 1.0) / SOFTSHADOWRADIUS, 0.0, 1.0) + 0.5 * col.r;
+ // col.r = adjusted_night_ratio; // debug night ratio adjustment
+#endif
#if ENABLE_TONE_MAPPING
col = applyToneMapping(col);
diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl
index f135ab9dc..922fba62b 100644
--- a/client/shaders/object_shader/opengl_vertex.glsl
+++ b/client/shaders/object_shader/opengl_vertex.glsl
@@ -28,6 +28,8 @@ centroid varying vec2 varTexCoord;
#endif
varying vec3 eyeVec;
+varying float nightRatio;
+
varying float vIDiff;
const float e = 2.718281828459;
@@ -60,7 +62,7 @@ void main(void)
gl_Position = mWorldViewProj * inVertexPosition;
vPosition = gl_Position.xyz;
- vNormal = inVertexNormal;
+ vNormal = (mWorld * vec4(inVertexNormal, 0.0)).xyz;
worldPosition = (mWorld * inVertexPosition).xyz;
eyeVec = -(mWorldView * inVertexPosition).xyz;
@@ -73,6 +75,7 @@ void main(void)
? 1.0
: directional_ambient(normalize(inVertexNormal));
#endif
+ nightRatio = 0.0;
#ifdef GL_ES
varColor = inVertexColor.bgra;
@@ -81,11 +84,12 @@ void main(void)
#endif
#ifdef ENABLE_DYNAMIC_SHADOWS
-
- cosLight = max(0.0, dot(vNormal, -v_LightDirection));
- float texelSize = 0.51;
- float slopeScale = clamp(1.0 - cosLight, 0.0, 1.0);
+ vec3 nNormal = normalize(vNormal);
+ cosLight = dot(nNormal, -v_LightDirection);
+ float texelSize = 767.0 / f_textureresolution;
+ float slopeScale = clamp(1.0 - abs(cosLight), 0.0, 1.0);
normalOffsetScale = texelSize * slopeScale;
+
if (f_timeofday < 0.2) {
adj_shadow_strength = f_shadow_strength * 0.5 *
(1.0 - mtsmoothstep(0.18, 0.2, f_timeofday));
@@ -98,6 +102,5 @@ void main(void)
(1.0 - mtsmoothstep(0.7, 0.8, f_timeofday));
}
f_normal_length = length(vNormal);
-
#endif
}