diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml index d05a98bcd..a0880f545 100644 --- a/doc/classes/DirectionalLight.xml +++ b/doc/classes/DirectionalLight.xml @@ -21,6 +21,9 @@ Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange]. + + 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). + 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). diff --git a/doc/classes/Light.xml b/doc/classes/Light.xml index 302324795..95507af6c 100644 --- a/doc/classes/Light.xml +++ b/doc/classes/Light.xml @@ -121,6 +121,9 @@ Constant for accessing [member DirectionalLight.directional_shadow_bias_split_scale]. + + Constant for accessing [member DirectionalLight.directional_shadow_fade_start]. + Represents the size of the [enum Param] enum. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index f6f666b69..33096978a 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3542,6 +3542,9 @@ Increases bias on further splits to fix self-shadowing that only occurs far away from the camera. + + 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). + Represents the size of the [enum LightParam] enum. diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 1528c47a6..5a15efcc1 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -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]); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index aa63dce20..663fd9e54 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -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; @@ -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; diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 4019340b6..6455f7e64 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -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; @@ -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; @@ -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; @@ -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; @@ -2093,7 +2092,6 @@ 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; @@ -2101,7 +2099,6 @@ FRAGMENT_SHADER_CODE 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 @@ -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 @@ -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; @@ -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; @@ -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; @@ -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 @@ -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 diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 7c3076010..b7462fd7e 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -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); @@ -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); @@ -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"); @@ -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); diff --git a/scene/3d/light.h b/scene/3d/light.h index 2d9d53c2f..df0ae123d 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -57,6 +57,7 @@ public: 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 }; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 7ac873b75..3e88e89ff 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -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);