summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2022-03-04 12:26:29 +0100
committerGitHub <noreply@github.com>2022-03-04 12:26:29 +0100
commit3078b92dffd59204556037315acebaf2fe46dbff (patch)
tree2cf27b219f3075e2775d01c5448a1827a66fae68
parent0ff45dd3a7ff28b7fb686cb6e8640926f885038a (diff)
parentb1a295b739eb056557e9f2fe47ac80be6cc6d79d (diff)
Merge pull request #58512 from Calinou/light3d-add-distance-fade
-rw-r--r--doc/classes/Light3D.xml19
-rw-r--r--doc/classes/RenderingServer.xml11
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp3
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h1
-rw-r--r--scene/3d/light_3d.cpp67
-rw-r--r--scene/3d/light_3d.h16
-rw-r--r--servers/rendering/rasterizer_dummy.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp63
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h25
-rw-r--r--servers/rendering/renderer_storage.h1
-rw-r--r--servers/rendering/rendering_server_default.h1
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--servers/rendering_server.h1
14 files changed, 214 insertions, 6 deletions
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index a058611915..0350d09dfd 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -28,6 +28,23 @@
</method>
</methods>
<members>
+ <member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0">
+ The distance from the camera at which the light begins to fade away (in 3D units).
+ [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D].
+ </member>
+ <member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false">
+ If [code]true[/code], the light will smoothly fade away when far from the active [Camera3D] starting at [member distance_fade_begin]. This acts as a form of level of detail (LOD). The light will fade out over [member distance_fade_begin] + [member distance_fade_length], after which it will be culled and not sent to the shader at all. Use this to reduce the number of active lights in a scene and thus improve performance.
+ [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D].
+ </member>
+ <member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0">
+ Distance over which the light fades. The light's energy is progressively reduced over this distance and is completely invisible at the end.
+ [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D].
+ </member>
+ <member name="distance_fade_shadow" type="float" setter="set_distance_fade_shadow" getter="get_distance_fade_shadow" default="50.0">
+ The distance from the camera at which the light's shadow cuts off (in 3D units). Set this to a value lower than [member distance_fade_begin] + [member distance_fade_length] to further improve performance, as shadow rendering is often more expensive than light rendering itself.
+ [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D], and only when [member shadow_enabled] is [code]true[/code].
+ [b]Note:[/b] Due to a rendering engine limitation, shadows will be disabled instantly instead of fading smoothly according to [member distance_fade_length]. This may result in visible pop-in depending on the scene topography.
+ </member>
<member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false">
If [code]true[/code], the light only appears in the editor and will not be visible at runtime.
</member>
@@ -73,7 +90,7 @@
The color of shadows cast by this light.
</member>
<member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
- If [code]true[/code], the light will cast shadows.
+ 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].
</member>
<member name="shadow_fog_fade" type="float" setter="set_param" getter="get_param" default="0.1">
</member>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 11a681b235..ba3f5e10f5 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1650,6 +1650,17 @@
Sets the cull mask for this Light3D. Lights only affect objects in the selected layers. Equivalent to [member Light3D.light_cull_mask].
</description>
</method>
+ <method name="light_set_distance_fade">
+ <return type="void" />
+ <argument index="0" name="decal" type="RID" />
+ <argument index="1" name="enabled" type="bool" />
+ <argument index="2" name="begin" type="float" />
+ <argument index="3" name="shadow" type="float" />
+ <argument index="4" name="length" type="float" />
+ <description>
+ Sets the distance fade for this Light3D. This acts as a form of level of detail (LOD) and can be used to improve performance. Equivalent to [member Light3D.distance_fade_enabled], [member Light3D.distance_fade_begin], [member Light3D.distance_fade_shadow], and [member Light3D.distance_fade_length].
+ </description>
+ </method>
<method name="light_set_max_sdfgi_cascade">
<return type="void" />
<argument index="0" name="light" type="RID" />
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index abbba13ee6..8e0b7bc9b8 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -2267,6 +2267,9 @@ void RasterizerStorageGLES3::light_set_negative(RID p_light, bool p_enable) {
void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) {
}
+void RasterizerStorageGLES3::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {
+}
+
void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
}
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index b6a5c0e73e..462c6af89f 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -902,6 +902,7 @@ public:
void light_set_projector(RID p_light, RID p_texture) override;
void light_set_negative(RID p_light, bool p_enable) override;
void light_set_cull_mask(RID p_light, uint32_t p_mask) override;
+ void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override;
void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override;
void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override;
void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override;
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index b2e605a262..0dd3fc8a23 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -74,6 +74,43 @@ bool Light3D::is_negative() const {
return negative;
}
+void Light3D::set_enable_distance_fade(bool p_enable) {
+ distance_fade_enabled = p_enable;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+ notify_property_list_changed();
+}
+
+bool Light3D::is_distance_fade_enabled() const {
+ return distance_fade_enabled;
+}
+
+void Light3D::set_distance_fade_begin(real_t p_distance) {
+ distance_fade_begin = p_distance;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_begin() const {
+ return distance_fade_begin;
+}
+
+void Light3D::set_distance_fade_shadow(real_t p_distance) {
+ distance_fade_shadow = p_distance;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_shadow() const {
+ return distance_fade_shadow;
+}
+
+void Light3D::set_distance_fade_length(real_t p_length) {
+ distance_fade_length = p_length;
+ RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length);
+}
+
+real_t Light3D::get_distance_fade_length() const {
+ return distance_fade_length;
+}
+
void Light3D::set_cull_mask(uint32_t p_cull_mask) {
cull_mask = p_cull_mask;
RS::get_singleton()->light_set_cull_mask(light, p_cull_mask);
@@ -195,7 +232,7 @@ bool Light3D::is_editor_only() const {
}
void Light3D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur")) {
+ if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
property.usage = PROPERTY_USAGE_NO_EDITOR;
}
@@ -203,6 +240,11 @@ void Light3D::_validate_property(PropertyInfo &property) const {
// Angular distance is only used in DirectionalLight3D.
property.usage = PROPERTY_USAGE_NONE;
}
+
+ if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
VisualInstance3D::_validate_property(property);
}
@@ -222,6 +264,18 @@ void Light3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cull_mask", "cull_mask"), &Light3D::set_cull_mask);
ClassDB::bind_method(D_METHOD("get_cull_mask"), &Light3D::get_cull_mask);
+ ClassDB::bind_method(D_METHOD("set_enable_distance_fade", "enable"), &Light3D::set_enable_distance_fade);
+ ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &Light3D::is_distance_fade_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_begin", "distance"), &Light3D::set_distance_fade_begin);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_begin"), &Light3D::get_distance_fade_begin);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_shadow", "distance"), &Light3D::set_distance_fade_shadow);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_shadow"), &Light3D::get_distance_fade_shadow);
+
+ ClassDB::bind_method(D_METHOD("set_distance_fade_length", "distance"), &Light3D::set_distance_fade_length);
+ ClassDB::bind_method(D_METHOD("get_distance_fade_length"), &Light3D::get_distance_fade_length);
+
ClassDB::bind_method(D_METHOD("set_color", "color"), &Light3D::set_color);
ClassDB::bind_method(D_METHOD("get_color"), &Light3D::get_color);
@@ -257,6 +311,11 @@ void Light3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR);
+ ADD_GROUP("Distance Fade", "distance_fade_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_begin", "get_distance_fade_begin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_shadow", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_shadow", "get_distance_fade_shadow");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_length", "get_distance_fade_length");
ADD_GROUP("Editor", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
ADD_GROUP("", "");
@@ -391,6 +450,12 @@ void DirectionalLight3D::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NONE;
}
+ if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") {
+ // Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights.
+ // For DirectionalLight3D, `directional_shadow_max_distance` can be used instead.
+ property.usage = PROPERTY_USAGE_NONE;
+ }
+
Light3D::_validate_property(property);
}
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index d5d2aee43d..21d785e2f7 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -75,6 +75,10 @@ private:
bool negative = false;
bool reverse_cull = false;
uint32_t cull_mask = 0;
+ bool distance_fade_enabled = false;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_shadow = 50.0;
+ real_t distance_fade_length = 10.0;
RS::LightType type = RenderingServer::LIGHT_DIRECTIONAL;
bool editor_only = false;
void _update_visibility();
@@ -107,6 +111,18 @@ public:
void set_negative(bool p_enable);
bool is_negative() const;
+ void set_enable_distance_fade(bool p_enable);
+ bool is_distance_fade_enabled() const;
+
+ void set_distance_fade_begin(real_t p_distance);
+ real_t get_distance_fade_begin() const;
+
+ void set_distance_fade_shadow(real_t p_distance);
+ real_t get_distance_fade_shadow() const;
+
+ void set_distance_fade_length(real_t p_length);
+ real_t get_distance_fade_length() const;
+
void set_cull_mask(uint32_t p_cull_mask);
uint32_t get_cull_mask() const;
diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h
index 74c080660d..987f2f4342 100644
--- a/servers/rendering/rasterizer_dummy.h
+++ b/servers/rendering/rasterizer_dummy.h
@@ -412,6 +412,7 @@ public:
void light_set_projector(RID p_light, RID p_texture) override {}
void light_set_negative(RID p_light, bool p_enable) override {}
void light_set_cull_mask(RID p_light, uint32_t p_mask) override {}
+ void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) override {}
void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override {}
void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override {}
void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override {}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index db8f5461cf..8814822cda 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -3440,8 +3440,22 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
continue;
}
+ const real_t distance = camera_plane.distance_to(li->transform.origin);
+
+ if (storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
cluster.omni_light_sort[cluster.omni_light_count].instance = li;
- cluster.omni_light_sort[cluster.omni_light_count].depth = camera_plane.distance_to(li->transform.origin);
+ cluster.omni_light_sort[cluster.omni_light_count].depth = distance;
cluster.omni_light_count++;
} break;
case RS::LIGHT_SPOT: {
@@ -3449,8 +3463,22 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
continue;
}
+ const real_t distance = camera_plane.distance_to(li->transform.origin);
+
+ if (storage->light_is_distance_fade_enabled(li->light)) {
+ const float fade_begin = storage->light_get_distance_fade_begin(li->light);
+ const float fade_length = storage->light_get_distance_fade_length(li->light);
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
cluster.spot_light_sort[cluster.spot_light_count].instance = li;
- cluster.spot_light_sort[cluster.spot_light_count].depth = camera_plane.distance_to(li->transform.origin);
+ cluster.spot_light_sort[cluster.spot_light_count].depth = distance;
cluster.spot_light_count++;
} break;
}
@@ -3494,7 +3522,24 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION);
- float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI;
+ // Reuse fade begin, fade length and distance for shadow LOD determination later.
+ float fade_begin = 0.0;
+ float fade_length = 0.0;
+ real_t distance = 0.0;
+
+ float fade = 1.0;
+ if (storage->light_is_distance_fade_enabled(li->light)) {
+ fade_begin = storage->light_get_distance_fade_begin(li->light);
+ fade_length = storage->light_get_distance_fade_length(li->light);
+ distance = camera_plane.distance_to(li->transform.origin);
+
+ if (distance > fade_begin) {
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+ fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+ }
+ }
+
+ float energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
light_data.color[0] = linear_col.r * energy;
light_data.color[1] = linear_col.g * energy;
@@ -3555,7 +3600,17 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.projector_rect[3] = 0;
}
- if (shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) {
+ const bool needs_shadow = shadow_atlas && shadow_atlas->shadow_owners.has(li->self);
+
+ bool in_shadow_range = true;
+ if (needs_shadow && storage->light_is_distance_fade_enabled(li->light)) {
+ if (distance > storage->light_get_distance_fade_shadow(li->light)) {
+ // Out of range, don't draw shadows to improve performance.
+ in_shadow_range = false;
+ }
+ }
+
+ if (needs_shadow && in_shadow_range) {
// fill in the shadow information
light_data.shadow_enabled = true;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 1473a92a1a..35aa0f1f31 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -6600,6 +6600,16 @@ void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) {
light->dependency.changed_notify(DEPENDENCY_CHANGED_LIGHT);
}
+void RendererStorageRD::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->distance_fade = p_enabled;
+ light->distance_fade_begin = p_begin;
+ light->distance_fade_shadow = p_shadow;
+ light->distance_fade_length = p_length;
+}
+
void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 33a3b8e229..cb35c2bf65 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -1033,6 +1033,10 @@ private:
RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
uint32_t max_sdfgi_cascade = 2;
uint32_t cull_mask = 0xFFFFFFFF;
+ bool distance_fade = false;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_shadow = 50.0;
+ real_t distance_fade_length = 10.0;
RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
bool directional_blend_splits = false;
@@ -1841,6 +1845,7 @@ public:
void light_set_projector(RID p_light, RID p_texture);
void light_set_negative(RID p_light, bool p_enable);
void light_set_cull_mask(RID p_light, uint32_t p_mask);
+ void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length);
void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled);
void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode);
void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade);
@@ -1899,6 +1904,26 @@ public:
return light->cull_mask;
}
+ _FORCE_INLINE_ bool light_is_distance_fade_enabled(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_begin(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_begin;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_shadow(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_shadow;
+ }
+
+ _FORCE_INLINE_ float light_get_distance_fade_length(RID p_light) {
+ const Light *light = light_owner.get_or_null(p_light);
+ return light->distance_fade_length;
+ }
+
_FORCE_INLINE_ bool light_has_shadow(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h
index a2df7ad38e..762362afed 100644
--- a/servers/rendering/renderer_storage.h
+++ b/servers/rendering/renderer_storage.h
@@ -321,6 +321,7 @@ public:
virtual void light_set_projector(RID p_light, RID p_texture) = 0;
virtual void light_set_negative(RID p_light, bool p_enable) = 0;
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
+ virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
virtual void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) = 0;
virtual void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) = 0;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 6d2c36537b..9ed2b2ad4f 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -346,6 +346,7 @@ public:
FUNC2(light_set_projector, RID, RID)
FUNC2(light_set_negative, RID, bool)
FUNC2(light_set_cull_mask, RID, uint32_t)
+ FUNC5(light_set_distance_fade, RID, bool, float, float, float)
FUNC2(light_set_reverse_cull_face_mode, RID, bool)
FUNC2(light_set_bake_mode, RID, LightBakeMode)
FUNC2(light_set_max_sdfgi_cascade, RID, uint32_t)
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index fe5c7dc0de..39a0acb2bd 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1883,6 +1883,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_set_projector", "light", "texture"), &RenderingServer::light_set_projector);
ClassDB::bind_method(D_METHOD("light_set_negative", "light", "enable"), &RenderingServer::light_set_negative);
ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &RenderingServer::light_set_cull_mask);
+ ClassDB::bind_method(D_METHOD("light_set_distance_fade", "decal", "enabled", "begin", "shadow", "length"), &RenderingServer::light_set_distance_fade);
ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &RenderingServer::light_set_reverse_cull_face_mode);
ClassDB::bind_method(D_METHOD("light_set_bake_mode", "light", "bake_mode"), &RenderingServer::light_set_bake_mode);
ClassDB::bind_method(D_METHOD("light_set_max_sdfgi_cascade", "light", "cascade"), &RenderingServer::light_set_max_sdfgi_cascade);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 5748d8808b..533c000166 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -443,6 +443,7 @@ public:
virtual void light_set_projector(RID p_light, RID p_texture) = 0;
virtual void light_set_negative(RID p_light, bool p_enable) = 0;
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
+ virtual void light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
enum LightBakeMode {