diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml
index afd85a9cb75..233b1f0c16e 100644
--- a/doc/classes/DirectionalLight3D.xml
+++ b/doc/classes/DirectionalLight3D.xml
@@ -41,6 +41,9 @@
+
+ If [code]true[/code], this [DirectionalLight3D] will not be used for anything except sky shaders. Use this for lights that impact your sky shader that you may want to hide from affecting the rest of the scene. For example, you may want to enable this when the sun in your sky shader falls below the horizon.
+
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 857c13deb58..4c5ec13cd08 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1432,6 +1432,17 @@
Sets the shadow mode for this directional light. Equivalent to [member DirectionalLight3D.directional_shadow_mode]. See [enum LightDirectionalShadowMode] for options.
+
+
+
+
+
+
+
+
+ If [code]true[/code], this light will not be used for anything except sky shaders. Use this for lights that impact your sky shader that you may want to hide from affecting the rest of the scene. For example, you may want to enable this when the sun in your sky shader falls below the horizon.
+
+
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index bef4d999af5..37bfa981d9a 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -591,6 +591,8 @@ public:
void light_directional_set_blend_splits(RID p_light, bool p_enable) override {}
bool light_directional_get_blend_splits(RID p_light) const override { return false; }
void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) override {}
+ void light_directional_set_sky_only(RID p_light, bool p_sky_only) override {}
+ bool light_directional_is_sky_only(RID p_light) const override { return false; }
RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const override { return RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; }
RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; }
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 46c3f18c385..73228959d5a 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -394,6 +394,15 @@ bool DirectionalLight3D::is_blend_splits_enabled() const {
return blend_splits;
}
+void DirectionalLight3D::set_sky_only(bool p_sky_only) {
+ sky_only = p_sky_only;
+ RS::get_singleton()->light_directional_set_sky_only(light, p_sky_only);
+}
+
+bool DirectionalLight3D::is_sky_only() const {
+ return sky_only;
+}
+
void DirectionalLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight3D::set_shadow_mode);
ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight3D::get_shadow_mode);
@@ -404,6 +413,9 @@ void DirectionalLight3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight3D::set_blend_splits);
ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight3D::is_blend_splits_enabled);
+ ClassDB::bind_method(D_METHOD("set_sky_only", "priority"), &DirectionalLight3D::set_sky_only);
+ ClassDB::bind_method(D_METHOD("is_sky_only"), &DirectionalLight3D::is_sky_only);
+
ADD_GROUP("Directional Shadow", "directional_shadow_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal (Fast),PSSM 2 Splits (Average),PSSM 4 Splits (Slow)"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
@@ -415,6 +427,8 @@ void DirectionalLight3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_EXP_RANGE, "0,1024,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_sky_only"), "set_sky_only", "is_sky_only");
+
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 69c0478b866..08287a33131 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -158,6 +158,7 @@ private:
bool blend_splits;
ShadowMode shadow_mode;
ShadowDepthRange shadow_depth_range;
+ bool sky_only = false;
protected:
static void _bind_methods();
@@ -172,6 +173,9 @@ public:
void set_blend_splits(bool p_enable);
bool is_blend_splits_enabled() const;
+ void set_sky_only(bool p_sky_only);
+ bool is_sky_only() const;
+
DirectionalLight3D();
};
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index cecd313fbde..dad45bafa9a 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -517,6 +517,8 @@ public:
virtual void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) = 0;
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
virtual bool light_directional_get_blend_splits(RID p_light) const = 0;
+ virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0;
+ virtual bool light_directional_is_sky_only(RID p_light) const = 0;
virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0;
virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index f708b6ce007..2b1fea2aa17 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -1187,6 +1187,11 @@ void RasterizerSceneRD::sdfgi_update_probes(RID p_render_buffers, RID p_environm
LightInstance *li = light_instance_owner.getornull(p_directional_light_instances[j]);
ERR_CONTINUE(!li);
+
+ if (storage->light_directional_is_sky_only(li->light)) {
+ continue;
+ }
+
Vector3 dir = -li->transform.basis.get_axis(Vector3::AXIS_Z);
dir.y *= rb->sdfgi->y_mult;
dir.normalize();
@@ -4391,6 +4396,11 @@ void RasterizerSceneRD::gi_probe_update(RID p_probe, bool p_update_light_instanc
RID light = light_instance_get_base_light(light_instance);
l.type = storage->light_get_type(light);
+ if (l.type == RS::LIGHT_DIRECTIONAL && storage->light_directional_is_sky_only(light)) {
+ light_count--;
+ continue;
+ }
+
l.attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
l.energy = storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
l.radius = to_cell.basis.xform(Vector3(storage->light_get_param(light, RS::LIGHT_PARAM_RANGE), 0, 0)).length();
@@ -5930,7 +5940,40 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
RS::LightType type = storage->light_get_type(base);
switch (type) {
case RS::LIGHT_DIRECTIONAL: {
- if (r_directional_light_count >= cluster.max_directional_lights) {
+ // Copy to SkyDirectionalLightData
+ if (r_directional_light_count < sky_scene_state.max_directional_lights) {
+ SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
+ Transform light_transform = light_instance_get_base_transform(li);
+ Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
+
+ sky_light_data.direction[0] = world_direction.x;
+ sky_light_data.direction[1] = world_direction.y;
+ sky_light_data.direction[2] = -world_direction.z;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+ sky_light_data.energy = sign * storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
+
+ Color linear_col = storage->light_get_color(base).to_linear();
+ sky_light_data.color[0] = linear_col.r;
+ sky_light_data.color[1] = linear_col.g;
+ sky_light_data.color[2] = linear_col.b;
+
+ sky_light_data.enabled = true;
+
+ float angular_diameter = storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
+ if (angular_diameter > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ } else {
+ angular_diameter = 0.0;
+ }
+ sky_light_data.size = angular_diameter;
+ sky_scene_state.ubo.directional_light_count++;
+ }
+
+ if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) {
continue;
}
@@ -6073,27 +6116,6 @@ void RasterizerSceneRD::_setup_lights(RID *p_light_cull_result, int p_light_cull
}
}
- // Copy to SkyDirectionalLightData
- if (r_directional_light_count < sky_scene_state.max_directional_lights) {
- SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[r_directional_light_count];
-
- Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
-
- sky_light_data.direction[0] = world_direction.x;
- sky_light_data.direction[1] = world_direction.y;
- sky_light_data.direction[2] = -world_direction.z;
-
- sky_light_data.energy = light_data.energy / Math_PI;
-
- sky_light_data.color[0] = light_data.color[0];
- sky_light_data.color[1] = light_data.color[1];
- sky_light_data.color[2] = light_data.color[2];
-
- sky_light_data.enabled = true;
- sky_light_data.size = angular_diameter;
- sky_scene_state.ubo.directional_light_count++;
- }
-
r_directional_light_count++;
} break;
case RS::LIGHT_SPOT:
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index e723028e56c..0bbbc68c948 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -4950,6 +4950,20 @@ bool RasterizerStorageRD::light_directional_get_blend_splits(RID p_light) const
return light->directional_blend_splits;
}
+void RasterizerStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_sky_only = p_sky_only;
+}
+
+bool RasterizerStorageRD::light_directional_is_sky_only(RID p_light) const {
+ const Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
+
+ return light->directional_sky_only;
+}
+
RS::LightDirectionalShadowMode RasterizerStorageRD::light_directional_get_shadow_mode(RID p_light) {
const Light *light = light_owner.getornull(p_light);
ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index b03a26e2002..2fa6ce58675 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -823,6 +823,7 @@ private:
RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
bool directional_blend_splits = false;
+ bool directional_sky_only = false;
uint64_t version = 0;
RasterizerScene::InstanceDependency instance_dependency;
@@ -1459,6 +1460,8 @@ public:
void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode);
void light_directional_set_blend_splits(RID p_light, bool p_enable);
bool light_directional_get_blend_splits(RID p_light) const;
+ void light_directional_set_sky_only(RID p_light, bool p_sky_only);
+ bool light_directional_is_sky_only(RID p_light) const;
void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode);
RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index 97477f1d3e5..436577fae38 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -337,6 +337,7 @@ public:
BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
BIND2(light_directional_set_blend_splits, RID, bool)
+ BIND2(light_directional_set_sky_only, RID, bool)
BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index ae6786090ab..b933a550e27 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -2169,7 +2169,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const
//check shadow..
if (light) {
- if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base)) {
+ if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) {
lights_with_shadow[directional_shadow_count++] = E->get();
}
//add to list
@@ -2595,7 +2595,8 @@ void RenderingServerScene::render_probes() {
cache->radius != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_RANGE) ||
cache->attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION) ||
cache->spot_angle != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE) ||
- cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION)) {
+ cache->spot_attenuation != RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION) ||
+ cache->sky_only != RSG::storage->light_directional_is_sky_only(instance->base)) {
cache_dirty = true;
}
}
@@ -2664,6 +2665,7 @@ void RenderingServerScene::render_probes() {
cache->attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_ATTENUATION);
cache->spot_angle = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ANGLE);
cache->spot_attenuation = RSG::storage->light_get_param(instance->base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+ cache->sky_only = RSG::storage->light_directional_is_sky_only(instance->base);
idx++;
}
diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h
index 1b0a6176270..aa8439c164f 100644
--- a/servers/rendering/rendering_server_scene.h
+++ b/servers/rendering/rendering_server_scene.h
@@ -351,6 +351,7 @@ public:
float spot_angle;
float spot_attenuation;
bool has_shadow;
+ bool sky_only;
};
Vector light_cache;
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index c2337f8c9e6..d3319c7ed26 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -244,6 +244,7 @@ public:
FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
FUNC2(light_directional_set_blend_splits, RID, bool)
+ FUNC2(light_directional_set_sky_only, RID, bool)
FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
/* PROBE API */
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index e2f1ddb2246..4b79660d22d 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1618,6 +1618,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode);
ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits);
+ ClassDB::bind_method(D_METHOD("light_directional_set_sky_only", "light", "enable"), &RenderingServer::light_directional_set_sky_only);
ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode);
ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index e50170bdf76..9ffdd15f5a1 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -435,6 +435,7 @@ public:
virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0;
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
+ virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0;
enum LightDirectionalShadowDepthRangeMode {
LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,