Skip to content

Commit

Permalink
Backport DirectionalLight fade_start property to 3.x
Browse files Browse the repository at this point in the history
- Implement shadow fading when using the Orthogonal shadow mode
  (like in `master`).

This allows customizing the distance at which directional shadows
start to fade away. Shadow fading will also always start at the same
distance now, regardless of the current shadow mode in use.

This is useful for enclosed levels to prevent shadows from fading
at all with a well-tuned maximum distance.

The default fade start value (0.8) results in fading happening later
in the distance compared to the previous behavior, where fading started
from the last shadow split distance (0.6 in PSSM 4 Splits and
0.1 in PSSM 2 Splits).
  • Loading branch information
Calinou authored and Relintai committed Jul 16, 2024
1 parent 0dfebc9 commit 769c33a
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 12 deletions.
3 changes: 3 additions & 0 deletions doc/classes/DirectionalLight.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight.ShadowDepthRange" default="0">
Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange].
</member>
<member name="directional_shadow_fade_start" type="float" setter="set_param" getter="get_param" default="0.8">
Proportion of [member directional_shadow_max_distance] at which point the shadow starts to fade. At [member directional_shadow_max_distance], the shadow will disappear. The default value is a balance between smooth fading and distant shadow visibility. If the camera moves fast and the [member directional_shadow_max_distance] is low, consider lowering [member directional_shadow_fade_start] below [code]0.8[/code] to make shadow transitions less noticeable. On the other hand, if you tuned [member directional_shadow_max_distance] to cover the entire scene, you can set [member directional_shadow_fade_start] to [code]1.0[/code] to prevent the shadow from fading in the distance (it will suddenly cut off instead).
</member>
<member name="directional_shadow_max_distance" type="float" setter="set_param" getter="get_param" default="100.0">
The maximum distance for shadow splits. Increasing this value will make directional shadows visible from further away, at the cost of lower overall shadow detail and performance (since more objects need to be included in the directional shadow rendering).
</member>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/Light.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@
<constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="Param">
Constant for accessing [member DirectionalLight.directional_shadow_bias_split_scale].
</constant>
<constant name="PARAM_SHADOW_FADE_START" value="16" enum="Param">
Constant for accessing [member DirectionalLight.directional_shadow_fade_start].
</constant>
<constant name="PARAM_MAX" value="17" enum="Param">
Represents the size of the [enum Param] enum.
</constant>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3542,6 +3542,9 @@
<constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="LightParam">
Increases bias on further splits to fix self-shadowing that only occurs far away from the camera.
</constant>
<constant name="LIGHT_PARAM_SHADOW_FADE_START" value="16" enum="LightParam">
Proportion of [constant LIGHT_PARAM_SHADOW_MAX_DISTANCE] at which point the shadow starts to fade. At [constant LIGHT_PARAM_SHADOW_MAX_DISTANCE], the shadow will disappear. The default value is a balance between smooth fading and distant shadow visibility. If the camera moves fast and the [constant LIGHT_PARAM_SHADOW_MAX_DISTANCE] is low, consider lowering [constant LIGHT_PARAM_SHADOW_FADE_START] below [code]0.8[/code] to make shadow transitions less noticeable. On the other hand, if you tuned [constant LIGHT_PARAM_SHADOW_MAX_DISTANCE] to cover the entire scene, you can set [constant LIGHT_PARAM_SHADOW_FADE_START] to [code]1.0[/code] to prevent the shadow from fading in the distance (it will suddenly cut off instead).
</constant>
<constant name="LIGHT_PARAM_MAX" value="17" enum="LightParam">
Represents the size of the [enum LightParam] enum.
</constant>
Expand Down
6 changes: 6 additions & 0 deletions drivers/gles2/rasterizer_scene_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2079,6 +2079,12 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
// state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp);
state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / directional_shadow.size, 1.0 / directional_shadow.size));
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets);

const float fade_start = light_ptr->param[RS::LIGHT_PARAM_SHADOW_FADE_START];
// Using 1.0 would break `smoothstep()` in the shader.
state.scene_shader.set_uniform(SceneShaderGLES2::FADE_FROM, -split_offsets[shadow_count - 1] * MIN(fade_start, 0.999));
state.scene_shader.set_uniform(SceneShaderGLES2::FADE_TO, -split_offsets[shadow_count - 1]);

state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, matrices[0]);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]);
Expand Down
4 changes: 3 additions & 1 deletion drivers/gles2/rasterizer_storage_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4244,6 +4244,7 @@ RID RasterizerStorageGLES2::light_create(RS::LightType p_type) {
light->param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
light->param[RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
light->param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;

light->color = Color(1, 1, 1, 1);
light->shadow = false;
Expand Down Expand Up @@ -4281,7 +4282,8 @@ void RasterizerStorageGLES2::light_set_param(RID p_light, RS::LightParam p_param
case RS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
case RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
case RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
case RS::LIGHT_PARAM_SHADOW_BIAS: {
case RS::LIGHT_PARAM_SHADOW_BIAS:
case RS::LIGHT_PARAM_SHADOW_FADE_START: {
light->version++;
light->instance_change_notify(true, false);
} break;
Expand Down
15 changes: 4 additions & 11 deletions drivers/gles2/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,8 @@ uniform highp sampler2D light_shadow_atlas; //texunit:-3
#ifdef LIGHT_MODE_DIRECTIONAL
uniform highp sampler2D light_directional_shadow; // texunit:-3
uniform highp vec4 light_split_offsets;
uniform mediump float fade_from;
uniform mediump float fade_to;
#endif

varying highp vec4 shadow_coord;
Expand Down Expand Up @@ -1983,7 +1985,6 @@ FRAGMENT_SHADER_CODE
float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4);

if (depth_z < light_split_offsets.w) {
float pssm_fade = 0.0;
float shadow_att = 1.0;
#ifdef LIGHT_USE_PSSM_BLEND
float shadow_att2 = 1.0;
Expand Down Expand Up @@ -2019,7 +2020,6 @@ FRAGMENT_SHADER_CODE

} else {
shadow_att = shadow4;
pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z);

#if defined(LIGHT_USE_PSSM_BLEND)
use_blend = false;
Expand All @@ -2043,7 +2043,6 @@ FRAGMENT_SHADER_CODE
float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3);

if (depth_z < light_split_offsets.z) {
float pssm_fade = 0.0;
float shadow_att = 1.0;
#ifdef LIGHT_USE_PSSM_BLEND
float shadow_att2 = 1.0;
Expand Down Expand Up @@ -2093,15 +2092,13 @@ FRAGMENT_SHADER_CODE

if (depth_z < light_split_offsets.y) {
float shadow_att = 1.0;
float pssm_fade = 0.0;

#ifdef LIGHT_USE_PSSM_BLEND
float shadow_att2 = 1.0;
float pssm_blend = 0.0;
bool use_blend = true;
#endif
if (depth_z < light_split_offsets.x) {
float pssm_fade = 0.0;
shadow_att = shadow1;

#ifdef LIGHT_USE_PSSM_BLEND
Expand All @@ -2110,7 +2107,6 @@ FRAGMENT_SHADER_CODE
#endif
} else {
shadow_att = shadow2;
pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
#ifdef LIGHT_USE_PSSM_BLEND
use_blend = false;
#endif
Expand Down Expand Up @@ -2144,7 +2140,6 @@ FRAGMENT_SHADER_CODE
#endif //pssm2

highp vec4 pssm_coord;
float pssm_fade = 0.0;

#ifdef LIGHT_USE_PSSM_BLEND
float pssm_blend;
Expand Down Expand Up @@ -2183,7 +2178,6 @@ FRAGMENT_SHADER_CODE

} else {
pssm_coord = shadow_coord4;
pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z);

#if defined(LIGHT_USE_PSSM_BLEND)
use_blend = false;
Expand Down Expand Up @@ -2213,7 +2207,6 @@ FRAGMENT_SHADER_CODE
}
} else {
pssm_coord = shadow_coord3;
pssm_fade = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z);

#if defined(LIGHT_USE_PSSM_BLEND)
use_blend = false;
Expand All @@ -2232,7 +2225,6 @@ FRAGMENT_SHADER_CODE
#endif
} else {
pssm_coord = shadow_coord2;
pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
#ifdef LIGHT_USE_PSSM_BLEND
use_blend = false;
#endif
Expand All @@ -2254,7 +2246,8 @@ FRAGMENT_SHADER_CODE
}
#endif

light_att *= mix(shadow_color.rgb, vec3(1.0), shadow);
float pssm_fade = smoothstep(fade_from, fade_to, vertex.z);
light_att *= mix(mix(shadow_color.rgb, vec3(1.0), shadow), vec3(1.0), pssm_fade);
}
}
#endif //use vertex lighting
Expand Down
4 changes: 4 additions & 0 deletions scene/3d/light.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ void Light::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE);
BIND_ENUM_CONSTANT(PARAM_SHADOW_FADE_START);
BIND_ENUM_CONSTANT(PARAM_MAX);

BIND_ENUM_CONSTANT(BAKE_DISABLED);
Expand Down Expand Up @@ -315,6 +316,7 @@ Light::Light(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1);
set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2);
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0);
set_param(PARAM_SHADOW_BIAS, 0.15);
set_disable_scale(true);
Expand Down Expand Up @@ -392,6 +394,7 @@ void DirectionalLight::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
Expand All @@ -412,6 +415,7 @@ DirectionalLight::DirectionalLight() :
set_param(PARAM_SHADOW_BIAS, 0.1);
set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);

Expand Down
1 change: 1 addition & 0 deletions scene/3d/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Light : public VisualInstance {
PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_BIAS_SPLIT_SCALE = RS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
PARAM_SHADOW_FADE_START = RS::LIGHT_PARAM_SHADOW_FADE_START,
PARAM_MAX = RS::LIGHT_PARAM_MAX
};

Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2405,6 +2405,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START);
BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX);

BIND_ENUM_CONSTANT(LIGHT_BAKE_DISABLED);
Expand Down

0 comments on commit 769c33a

Please sign in to comment.