diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 26b97edc25be..cbfec3747652 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -112,7 +112,7 @@
Used to adjust shadow appearance. Too small a value results in self-shadowing ("shadow acne"), while too large a value causes shadows to separate from casters ("peter-panning"). Adjust as needed.
- Blurs the edges of the shadow. Can be used to hide pixel artifacts in low-resolution shadow maps. A high value can impact performance, make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible.
+ Blurs the edges of the shadow. This can be used to hide pixel artifacts in low-resolution shadow maps, especially with moving objects. A high value can impact performance, make shadows appear grainy (if [member ProjectSettings.rendering/lights_and_shadows/soft_shadow_use_dithering] is [code]true[/code]) and can cause other unwanted artifacts. Try to keep [member shadow_blur] close to its default value whenever possible.
If [code]true[/code], the light will cast real-time shadows. This has a significant performance cost. Only enable shadow rendering when it makes a noticeable difference in the scene's appearance, and consider using [member distance_fade_enabled] to hide the light when far away from the [Camera3D].
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 0b60f0dbf658..67938d6131c1 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2369,8 +2369,8 @@
Lower-end override for [member rendering/lights_and_shadows/directional_shadow/size] on mobile devices, due to performance concerns or driver support.
- Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
- [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
+ Quality setting for shadows cast by [DirectionalLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy. See [member rendering/lights_and_shadows/soft_shadow_use_dithering] for disabling soft shadow dithering.
+ [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance]. The Soft Very Low setting makes no visual difference compared to Hard if [member rendering/lights_and_shadows/soft_shadow_use_dithering] is [code]false[/code].
[b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply [i]constant[/i] shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
@@ -2398,8 +2398,8 @@
Lower-end override for [member rendering/lights_and_shadows/positional_shadow/atlas_size] on mobile devices, due to performance concerns or driver support.
- Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy.
- [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance].
+ Quality setting for shadows cast by [OmniLight3D]s and [SpotLight3D]s. Higher quality settings use more samples when reading from shadow maps and are thus slower. Low quality settings may result in shadows looking grainy. See [member rendering/lights_and_shadows/soft_shadow_use_dithering] for disabling soft shadow dithering.
+ [b]Note:[/b] The Soft Very Low setting will automatically multiply [i]constant[/i] shadow blur by 0.75x to reduce the amount of noise visible. This automatic blur change only affects the constant blur factor defined in [member Light3D.shadow_blur], not the variable blur performed by [DirectionalLight3D]s' [member Light3D.light_angular_distance]. The Soft Very Low setting makes no visual difference compared to Hard if [member rendering/lights_and_shadows/soft_shadow_use_dithering] is [code]false[/code].
[b]Note:[/b] The Soft High and Soft Ultra settings will automatically multiply shadow blur by 1.5× and 2× respectively to make better use of the increased sample count. This increased blur also improves stability of dynamic object shadows.
@@ -2567,6 +2567,11 @@
[b]Note:[/b] For performance reasons, anisotropic filtering [i]is not enabled by default[/i] on 2D and 3D materials. For this setting to have an effect in 3D, set [member BaseMaterial3D.texture_filter] to [constant BaseMaterial3D.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant BaseMaterial3D.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on materials. For this setting to have an effect in 2D, set [member CanvasItem.texture_filter] to [constant CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant CanvasItem.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on the [CanvasItem] node displaying the texture (or in [CanvasTexture]). However, anisotropic filtering is rarely useful in 2D, so only enable it for textures in 2D if it makes a meaningful visual difference.
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
+
+ If [code]true[/code], enables dithering for soft shadows. Dithering improves overall soft shadow quality, but it has a performance cost and introduces a grainy effect that can be noticeable in scenes with large flat color areas. This dithering effect becomes less noticeable as textures become more complex and as the 3D rendering resolution increases, so it's recommended to leave this enabled in most scenes (especially when using TAA or FXAA antialiasing, which make the dithering pattern less noticeable). [member rendering/lights_and_shadows/soft_shadow_use_dithering] affects both [DirectionalLight3D] and positional light shadows. See also [method RenderingServer.soft_shadow_set_use_dithering].
+ If you disable dithering, you may notice undersampling artifacts in shadows. These can be alleviated by adjusting [Light3D]s' [member Light3D.shadow_blur] property, or increasing [member rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality] and [member rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality] to higher quality settings.
+ [b]Note:[/b] [member rendering/lights_and_shadows/soft_shadow_use_dithering] setting only has an effect if either [member rendering/shadows/shadows/soft_shadow_quality] or [member rendering/shadows/directional_shadow/soft_shadow_quality] is set to [b]Soft Low[/b] or higher.
+
Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close).
Enabling temporal antialiasing ([member rendering/anti_aliasing/quality/use_taa]) will automatically apply a [code]-0.5[/code] offset to this value, while enabling FXAA ([member rendering/anti_aliasing/quality/screen_space_aa]) will automatically apply a [code]-0.25[/code] offset to this value. If both TAA and FXAA are enbled at the same time, an offset of [code]-0.75[/code] is applied to this value.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 59286acccc9d..eb167c04f01d 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -465,6 +465,14 @@
Sets the default texture repeat mode for the canvas item specified by the [param item] RID. Equivalent to [member CanvasItem.texture_repeat].
+
+
+
+
+ If [code]dither[/code] is [code]true[/code], enables dithering for soft shadows. Dithering improves overall soft shadow quality, but it has a performance cost and introduces a grainy effect that can be noticeable in scenes with large flat color areas. This dithering effect becomes less noticeable as textures become more complex and as the 3D rendering resolution increases. [method soft_shadow_set_use_dithering] affects both [DirectionalLight3D] and point light shadows. See also [member ProjectSettings.rendering/lights_and_shadows/soft_shadow_use_dithering].
+ [b]Note:[/b] Shadow dithering only has an effect if either the shadow quality or directional shadow quality are set to [constant SHADOW_QUALITY_SOFT_VERY_LOW] or higher. Shadow dithering also only has an effect on [Light3D]s whose [member Light3D.shadow_blur] is greater than [code]0.0[/code].
+
+
@@ -1024,14 +1032,14 @@
- Sets the [param size] of the directional light shadows in 3D. See also [member ProjectSettings.rendering/lights_and_shadows/directional_shadow/size]. This parameter is global and cannot be set on a per-viewport basis.
+ Sets the [param size] of the directional light shadows in 3D. Higher values result in sharper shadows, at the cost of performance. The value is rounded up to the nearest power of 2. See also [member ProjectSettings.rendering/lights_and_shadows/directional_shadow/size]. This parameter is global and cannot be set on a per-viewport basis.
- Sets the filter [param quality] for directional light shadows in 3D. See also [member ProjectSettings.rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality]. This parameter is global and cannot be set on a per-viewport basis.
+ Sets the filter [param quality] for directional light shadows in 3D. Higher quality settings use more samples when reading from shadow maps and are thus slower. See also [member ProjectSettings.rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality]. This parameter is global and cannot be set on a per-viewport basis.
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 3d8f7924a78b..8bfe9d319671 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1119,6 +1119,9 @@ void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQ
void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
+void RasterizerSceneGLES3::soft_shadow_set_use_dithering(bool p_dither) {
+}
+
RID RasterizerSceneGLES3::fog_volume_instance_create(RID p_fog_volume) {
return RID();
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index b4e787ad857d..7cdac1cafd7e 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -632,6 +632,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender {
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
+ void soft_shadow_set_use_dithering(bool p_dither) override;
RID fog_volume_instance_create(RID p_fog_volume) override;
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 564cdf119283..d8bafc007103 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -466,6 +466,9 @@ void EditorNode::_update_from_settings() {
RS::get_singleton()->positional_soft_shadow_filter_set_quality(shadows_quality);
RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality")));
RS::get_singleton()->directional_soft_shadow_filter_set_quality(directional_shadow_quality);
+ const bool shadows_dither = bool(GLOBAL_GET("rendering/lights_and_shadows/soft_shadow_use_dithering"));
+ RS::get_singleton()->soft_shadow_set_use_dithering(shadows_dither);
+
float probe_update_speed = GLOBAL_GET("rendering/lightmapping/probe_capture/update_speed");
RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
RS::EnvironmentSDFGIFramesToConverge frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(int(GLOBAL_GET("rendering/global_illumination/sdfgi/frames_to_converge")));
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index 965d837ea80e..5c70cac66fa2 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -131,6 +131,7 @@ class RasterizerSceneDummy : public RendererSceneRender {
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
+ void soft_shadow_set_use_dithering(bool p_dither) override {}
RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); }
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 779249c2da58..a1c1ed54235e 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -3897,6 +3897,12 @@ void RenderForwardClustered::_update_shader_quality_settings() {
spec_constants.push_back(sc);
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_SHADOW_DITHER;
+ sc.bool_value = soft_shadow_is_using_dither();
+
+ spec_constants.push_back(sc);
+
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index e07d2f2258bb..0d3aa506ceab 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -68,8 +68,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 7,
SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 8,
SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 9,
- SPEC_CONSTANT_DECAL_FILTER = 10,
- SPEC_CONSTANT_PROJECTOR_FILTER = 11,
+ SPEC_CONSTANT_SHADOW_DITHER = 10,
+ SPEC_CONSTANT_DECAL_FILTER = 11,
+ SPEC_CONSTANT_PROJECTOR_FILTER = 12,
};
enum {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 0b4157c5d63d..e9a817cb22f1 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -2754,6 +2754,12 @@ void RenderForwardMobile::_update_shader_quality_settings() {
spec_constants.push_back(sc);
+ sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+ sc.constant_id = SPEC_CONSTANT_SHADOW_DITHER;
+ sc.bool_value = soft_shadow_is_using_dither();
+
+ spec_constants.push_back(sc);
+
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 214b39c49666..94fae63ea74d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -69,17 +69,18 @@ class RenderForwardMobile : public RendererSceneRenderRD {
SPEC_CONSTANT_PENUMBRA_SHADOW_SAMPLES = 4,
SPEC_CONSTANT_DIRECTIONAL_SOFT_SHADOW_SAMPLES = 5,
SPEC_CONSTANT_DIRECTIONAL_PENUMBRA_SHADOW_SAMPLES = 6,
+ SPEC_CONSTANT_SHADOW_DITHER = 7,
- SPEC_CONSTANT_DECAL_USE_MIPMAPS = 7,
- SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS = 8,
+ SPEC_CONSTANT_DECAL_USE_MIPMAPS = 8,
+ SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS = 9,
- SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 9,
- SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 10,
- SPEC_CONSTANT_DISABLE_REFLECTION_PROBES = 11,
- SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 12,
+ SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 10,
+ SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 11,
+ SPEC_CONSTANT_DISABLE_REFLECTION_PROBES = 12,
+ SPEC_CONSTANT_DISABLE_DIRECTIONAL_LIGHTS = 13,
- SPEC_CONSTANT_DISABLE_DECALS = 13,
- SPEC_CONSTANT_DISABLE_FOG = 14,
+ SPEC_CONSTANT_DISABLE_DECALS = 14,
+ SPEC_CONSTANT_DISABLE_FOG = 15,
};
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index efd961fd8992..5c371e13e58a 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -839,6 +839,14 @@ void RendererSceneRenderRD::directional_soft_shadow_filter_set_quality(RS::Shado
_update_shader_quality_settings();
}
+void RendererSceneRenderRD::soft_shadow_set_use_dithering(bool p_dither) {
+ if (shadows_dither != p_dither) {
+ shadows_dither = p_dither;
+ }
+
+ _update_shader_quality_settings();
+}
+
void RendererSceneRenderRD::decals_set_filter(RenderingServer::DecalFilter p_filter) {
if (decals_filter == p_filter) {
return;
@@ -1275,6 +1283,7 @@ void RendererSceneRenderRD::init() {
soft_shadow_kernel = memnew_arr(float, 128);
positional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality"))));
directional_soft_shadow_filter_set_quality(RS::ShadowQuality(int(GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality"))));
+ soft_shadow_set_use_dithering(bool(GLOBAL_GET("rendering/lights_and_shadows/soft_shadow_use_dithering")));
environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 7c43021eb058..3a4586c4603d 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -166,6 +166,7 @@ class RendererSceneRenderRD : public RendererSceneRender {
/* Shadow atlas */
RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
+ bool shadows_dither = true;
float shadows_quality_radius = 1.0;
float directional_shadow_quality_radius = 1.0;
@@ -300,6 +301,7 @@ class RendererSceneRenderRD : public RendererSceneRender {
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
+ virtual void soft_shadow_set_use_dithering(bool p_dither) override;
virtual void decals_set_filter(RS::DecalFilter p_filter) override;
virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override;
@@ -342,6 +344,9 @@ class RendererSceneRenderRD : public RendererSceneRender {
_FORCE_INLINE_ int soft_shadow_samples_get() const {
return soft_shadow_samples;
}
+ _FORCE_INLINE_ int soft_shadow_is_using_dither() const {
+ return shadows_dither;
+ }
_FORCE_INLINE_ RS::LightProjectorFilter light_projectors_get_filter() const {
return light_projectors_filter;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index cec54a2c5f93..aef53f31dfcb 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -499,8 +499,9 @@ layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4;
layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4;
layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4;
-layout(constant_id = 10) const bool sc_decal_use_mipmaps = true;
-layout(constant_id = 11) const bool sc_projector_use_mipmaps = true;
+layout(constant_id = 10) const bool sc_shadow_dither = true;
+layout(constant_id = 11) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 12) const bool sc_projector_use_mipmaps = true;
// not used in clustered renderer but we share some code with the mobile renderer that requires this.
const float sc_luminance_multiplier = 1.0;
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index bb9216c4fa0d..af9ae49ad94a 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -480,9 +480,10 @@ layout(constant_id = 12) const bool sc_disable_directional_lights = false;
#endif //!MODE_UNSHADED
-layout(constant_id = 7) const bool sc_decal_use_mipmaps = true;
-layout(constant_id = 13) const bool sc_disable_decals = false;
-layout(constant_id = 14) const bool sc_disable_fog = false;
+layout(constant_id = 7) const bool sc_shadow_dither = true;
+layout(constant_id = 8) const bool sc_decal_use_mipmaps = true;
+layout(constant_id = 14) const bool sc_disable_decals = false;
+layout(constant_id = 15) const bool sc_disable_fog = false;
#endif //!MODE_RENDER_DEPTH
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index 41000f7b0e68..11b01079db0b 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -259,11 +259,13 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve
}
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
float avg = 0.0;
@@ -285,11 +287,13 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) {
}
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
float avg = 0.0;
@@ -310,11 +314,13 @@ float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec
}
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
float avg = 0.0;
@@ -350,11 +356,13 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
float blocker_average = 0.0;
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
for (uint i = 0; i < sc_directional_penumbra_shadow_samples; i++) {
@@ -428,11 +436,13 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
float blocker_average = 0.0;
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
vec3 basis_normal = shadow_dir;
@@ -707,11 +717,13 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
float blocker_average = 0.0;
mat2 disk_rotation;
- {
+ if (sc_shadow_dither) {
float r = quick_hash(gl_FragCoord.xy) * 2.0 * M_PI;
float sr = sin(r);
float cr = cos(r);
disk_rotation = mat2(vec2(cr, -sr), vec2(sr, cr));
+ } else {
+ disk_rotation = mat2(1.0);
}
float uv_size = spot_lights.data[idx].soft_shadow_size * z_norm * spot_lights.data[idx].soft_shadow_scale;
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index b3874ee7ae61..d63559fd0912 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -1252,6 +1252,7 @@ class RendererSceneCull : public RenderingMethod {
PASS1(positional_soft_shadow_filter_set_quality, RS::ShadowQuality)
PASS1(directional_soft_shadow_filter_set_quality, RS::ShadowQuality)
+ PASS1(soft_shadow_set_use_dithering, bool)
PASS2(sdfgi_set_debug_probe_select, const Vector3 &, const Vector3 &)
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 900738364194..2aee4e441823 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -227,6 +227,7 @@ class RendererSceneRender {
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
+ virtual void soft_shadow_set_use_dithering(bool p_dither) = 0;
virtual RID fog_volume_instance_create(RID p_fog_volume) = 0;
virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0;
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index f705603a1cbc..54ccb900fd3b 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -281,6 +281,7 @@ class RenderingMethod {
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
+ virtual void soft_shadow_set_use_dithering(bool p_dither) = 0;
/* Render Buffers */
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 797fe73ba037..f03ca14931b1 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -725,6 +725,8 @@ class RenderingServerDefault : public RenderingServer {
FUNC1(positional_soft_shadow_filter_set_quality, ShadowQuality);
FUNC1(directional_soft_shadow_filter_set_quality, ShadowQuality);
+ FUNC1(soft_shadow_set_use_dithering, bool);
+
FUNC1(decals_set_filter, RS::DecalFilter);
FUNC1(light_projectors_set_filter, RS::LightProjectorFilter);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 4d41343ff853..896d09f32fce 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1953,6 +1953,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("positional_soft_shadow_filter_set_quality", "quality"), &RenderingServer::positional_soft_shadow_filter_set_quality);
ClassDB::bind_method(D_METHOD("directional_soft_shadow_filter_set_quality", "quality"), &RenderingServer::directional_soft_shadow_filter_set_quality);
ClassDB::bind_method(D_METHOD("directional_shadow_atlas_set_size", "size", "is_16bits"), &RenderingServer::directional_shadow_atlas_set_size);
+ ClassDB::bind_method(D_METHOD("soft_shadow_set_use_dithering", "dither"), &RenderingServer::soft_shadow_set_use_dithering);
BIND_ENUM_CONSTANT(SHADOW_QUALITY_HARD);
BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_VERY_LOW);
@@ -2891,6 +2892,8 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)"), 2);
GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile", 0);
+ GLOBAL_DEF("rendering/lights_and_shadows/soft_shadow_use_dithering", true);
+
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
// Number of commands that can be drawn per frame.
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index deac2a59f92e..eb69866048fc 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -509,6 +509,7 @@ class RenderingServer : public Object {
virtual void positional_soft_shadow_filter_set_quality(ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(ShadowQuality p_quality) = 0;
+ virtual void soft_shadow_set_use_dithering(bool p_dither) = 0;
enum LightProjectorFilter {
LIGHT_PROJECTOR_FILTER_NEAREST,