From cef016d393959e989df259aeacd055fc702a55ca Mon Sep 17 00:00:00 2001 From: x2048 Date: Sun, 31 Oct 2021 19:18:30 +0100 Subject: [PATCH] Apply shadow only to the naturally lit part of the fragment color (#11722) Fragment color for nodes is now calculated from: * Texture color, highlighted by artificial light if present (light color conveyed via vertex color). * Texture color highlighted by natural light (conveyed via vertex color) filtered by shadow. * Reflected day/moonlight filtered by shadow (color and intensity), assuming some portion of the light is directly reflected from the materials. --- .../shaders/nodes_shader/opengl_fragment.glsl | 27 ++++++++++++++----- .../shadow_shaders/pass1_trans_fragment.glsl | 5 ++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index e21890710..b4a605b28 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -1,5 +1,6 @@ uniform sampler2D baseTexture; +uniform vec3 dayLight; uniform vec4 skyBgColor; uniform float fogDistance; uniform vec3 eyePosition; @@ -497,23 +498,35 @@ void main(void) 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 *= 1.0 - nightRatio; - + shadow_int = clamp(shadow_int, 0.0, 1.0); } + // 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, min(clamp(1.0-nightRatio, 0.0, 1.0), 1 - clamp(cosLight, 0.0, 0.035)/0.035)); + shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, 0.035)/0.035); } - shadow_int = 1.0 - (shadow_int * f_adj_shadow_strength); + shadow_int *= f_adj_shadow_strength; - // apply shadow (+color) as a factor to the material color - col.rgb = col.rgb * (1.0 - (1.0 - shadow_color) * (1.0 - pow(shadow_int, 2.0))); + // 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 diff --git a/client/shaders/shadow_shaders/pass1_trans_fragment.glsl b/client/shaders/shadow_shaders/pass1_trans_fragment.glsl index 032cd9379..b267c2214 100644 --- a/client/shaders/shadow_shaders/pass1_trans_fragment.glsl +++ b/client/shaders/shadow_shaders/pass1_trans_fragment.glsl @@ -33,9 +33,8 @@ void main() //col.rgb = col.a == 1.0 ? vec3(1.0) : col.rgb; #ifdef COLORED_SHADOWS col.rgb *= varColor.rgb; - // alpha 0.0 results in all-white, 0.5 means full color, 1.0 means all black - // resulting color is used as a factor in the final shader - float packedColor = packColor(mix(mix(vec3(1.0), col.rgb, 2.0 * clamp(col.a, 0.0, 0.5)), black, 2.0 * clamp(col.a - 0.5, 0.0, 0.5))); + // premultiply color alpha (see-through side) + float packedColor = packColor(col.rgb * (1.0 - col.a)); gl_FragColor = vec4(depth, packedColor, 0.0,1.0); #else gl_FragColor = vec4(depth, 0.0, 0.0, 1.0);