Explorar el Código

Merge pull request #58512 from Calinou/light3d-add-distance-fade

Rémi Verschelde hace 3 años
padre
commit
3078b92dff

+ 18 - 1
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>

+ 11 - 0
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" />

+ 3 - 0
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) {
 }
 

+ 1 - 0
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;

+ 66 - 1
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);
 }
 

+ 16 - 0
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;
 

+ 1 - 0
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 {}

+ 59 - 4
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;

+ 10 - 0
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);

+ 25 - 0
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);

+ 1 - 0
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;

+ 1 - 0
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)

+ 1 - 0
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);

+ 1 - 0
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 {