Skip to content

Commit

Permalink
Add a project setting to disable soft shadow dithering
Browse files Browse the repository at this point in the history
Soft shadow dithering can look bad in scenes with large flat color areas,
especially at lower viewport resolutions or when not using FXAA/TAA.

This adds a project setting that can be used to globally disable
soft shadow dithering.
  • Loading branch information
Calinou committed May 19, 2023
1 parent 809a982 commit 79412df
Show file tree
Hide file tree
Showing 22 changed files with 100 additions and 28 deletions.
2 changes: 1 addition & 1 deletion doc/classes/Light3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</member>
<member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0">
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.
</member>
<member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
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].
Expand Down
13 changes: 9 additions & 4 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</member>
<member name="rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
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.
</member>
<member name="rendering/lights_and_shadows/directional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
Expand Down Expand Up @@ -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.
</member>
<member name="rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality" type="int" setter="" getter="" default="2">
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.
</member>
<member name="rendering/lights_and_shadows/positional_shadow/soft_shadow_filter_quality.mobile" type="int" setter="" getter="" default="0">
Expand Down Expand Up @@ -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.
</member>
<member name="rendering/lights_and_shadows/soft_shadow_use_dithering" type="bool" setter="" getter="" default="true">
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.
</member>
<member name="rendering/textures/default_filters/texture_mipmap_bias" type="float" setter="" getter="" default="0.0">
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.
Expand Down
12 changes: 10 additions & 2 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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].
</description>
</method>
<method name="soft_shadow_set_use_dithering">
<return type="void" />
<argument index="0" name="dither" type="bool" />
<description>
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].
</description>
</method>
<method name="canvas_item_set_distance_field_mode">
<return type="void" />
<param index="0" name="item" type="RID" />
Expand Down Expand Up @@ -1024,14 +1032,14 @@
<param index="0" name="size" type="int" />
<param index="1" name="is_16bits" type="bool" />
<description>
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.
</description>
</method>
<method name="directional_soft_shadow_filter_set_quality">
<return type="void" />
<param index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality" />
<description>
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.
</description>
</method>
<method name="environment_bake_panorama">
Expand Down
3 changes: 3 additions & 0 deletions drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/rasterizer_scene_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")));
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/dummy/rasterizer_scene_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,

};

Expand Down
9 changes: 9 additions & 0 deletions servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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"));
Expand Down
5 changes: 5 additions & 0 deletions servers/rendering/renderer_rd/renderer_scene_render_rd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 79412df

Please sign in to comment.