3333#include " core/config/project_settings.h"
3434#include " core/object/worker_thread_pool.h"
3535#include " core/os/os.h"
36+ #include " rendering_light_culler.h"
3637#include " rendering_server_default.h"
3738
3839#include < new>
@@ -158,7 +159,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
158159 light->geometries .insert (A);
159160
160161 if (geom->can_cast_shadows ) {
161- light->shadow_dirty = true ;
162+ light->make_shadow_dirty () ;
162163 }
163164
164165 if (A->scenario && A->array_index >= 0 ) {
@@ -265,7 +266,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
265266 light->geometries .erase (A);
266267
267268 if (geom->can_cast_shadows ) {
268- light->shadow_dirty = true ;
269+ light->make_shadow_dirty () ;
269270 }
270271
271272 if (A->scenario && A->array_index >= 0 ) {
@@ -871,7 +872,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
871872 if (geom->can_cast_shadows ) {
872873 for (HashSet<RendererSceneCull::Instance *>::Iterator I = geom->lights .begin (); I != geom->lights .end (); ++I) {
873874 InstanceLightData *light = static_cast <InstanceLightData *>((*I)->base_data );
874- light->shadow_dirty = true ;
875+ light->make_shadow_dirty () ;
875876 }
876877 }
877878 }
@@ -1565,7 +1566,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
15651566
15661567 RSG::light_storage->light_instance_set_transform (light->instance , p_instance->transform );
15671568 RSG::light_storage->light_instance_set_aabb (light->instance , p_instance->transform .xform (p_instance->aabb ));
1568- light->shadow_dirty = true ;
1569+ light->make_shadow_dirty () ;
15691570
15701571 RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode (p_instance->base );
15711572 if (RSG::light_storage->light_get_type (p_instance->base ) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode ) {
@@ -1650,7 +1651,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
16501651 if (geom->can_cast_shadows ) {
16511652 for (const Instance *E : geom->lights ) {
16521653 InstanceLightData *light = static_cast <InstanceLightData *>(E->base_data );
1653- light->shadow_dirty = true ;
1654+ light->make_shadow_dirty () ;
16541655 }
16551656 }
16561657
@@ -2075,6 +2076,9 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
20752076}
20762077
20772078void RendererSceneCull::_light_instance_setup_directional_shadow (int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
2079+ // For later tight culling, the light culler needs to know the details of the directional light.
2080+ light_culler->prepare_directional_light (p_instance, p_shadow_index);
2081+
20782082 InstanceLightData *light = static_cast <InstanceLightData *>(p_instance->base_data );
20792083
20802084 Transform3D light_transform = p_instance->transform ;
@@ -2345,6 +2349,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
23452349
23462350 RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
23472351
2352+ if (!light->is_shadow_update_full ()) {
2353+ light_culler->cull_regular_light (instance_shadow_cull_result);
2354+ }
2355+
23482356 for (int j = 0 ; j < (int )instance_shadow_cull_result.size (); j++) {
23492357 Instance *instance = instance_shadow_cull_result[j];
23502358 if (!instance->visible || !((1 << instance->base_type ) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast <InstanceGeometryData *>(instance->base_data )->can_cast_shadows || !(p_visible_layers & instance->layer_mask )) {
@@ -2423,6 +2431,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
24232431
24242432 RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
24252433
2434+ if (!light->is_shadow_update_full ()) {
2435+ light_culler->cull_regular_light (instance_shadow_cull_result);
2436+ }
2437+
24262438 for (int j = 0 ; j < (int )instance_shadow_cull_result.size (); j++) {
24272439 Instance *instance = instance_shadow_cull_result[j];
24282440 if (!instance->visible || !((1 << instance->base_type ) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast <InstanceGeometryData *>(instance->base_data )->can_cast_shadows || !(p_visible_layers & instance->layer_mask )) {
@@ -2486,6 +2498,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
24862498
24872499 RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
24882500
2501+ if (!light->is_shadow_update_full ()) {
2502+ light_culler->cull_regular_light (instance_shadow_cull_result);
2503+ }
2504+
24892505 for (int j = 0 ; j < (int )instance_shadow_cull_result.size (); j++) {
24902506 Instance *instance = instance_shadow_cull_result[j];
24912507 if (!instance->visible || !((1 << instance->base_type ) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast <InstanceGeometryData *>(instance->base_data )->can_cast_shadows || !(p_visible_layers & instance->layer_mask )) {
@@ -2940,6 +2956,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
29402956 }
29412957
29422958 for (uint32_t j = 0 ; j < cull_data.cull ->shadow_count ; j++) {
2959+ if (!light_culler->cull_directional_light (cull_data.scenario ->instance_aabbs [i], j)) {
2960+ continue ;
2961+ }
29432962 for (uint32_t k = 0 ; k < cull_data.cull ->shadows [j].cascade_count ; k++) {
29442963 if (IN_FRUSTUM (cull_data.cull ->shadows [j].cascades [k].frustum ) && VIS_CHECK) {
29452964 uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
@@ -2992,6 +3011,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
29923011void RendererSceneCull::_render_scene (const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RenderingMethod::RenderInfo *r_render_info) {
29933012 Instance *render_reflection_probe = instance_owner.get_or_null (p_reflection_probe); // if null, not rendering to it
29943013
3014+ // Prepare the light - camera volume culling system.
3015+ light_culler->prepare_camera (p_camera_data->main_transform , p_camera_data->main_projection );
3016+
29953017 Scenario *scenario = scenario_owner.get_or_null (p_scenario);
29963018
29973019 ERR_FAIL_COND (p_render_buffers.is_null ());
@@ -3126,6 +3148,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
31263148#ifdef DEBUG_CULL_TIME
31273149 uint64_t time_from = OS::get_singleton ()->get_ticks_usec ();
31283150#endif
3151+
31293152 if (cull_to > thread_cull_threshold) {
31303153 // multiple threads
31313154 for (InstanceCullResult &thread : scene_cull_result_threads) {
@@ -3263,20 +3286,46 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
32633286 }
32643287 }
32653288
3266- if (light->shadow_dirty ) {
3267- light->last_version ++;
3268- light->shadow_dirty = false ;
3289+ // We can detect whether multiple cameras are hitting this light, whether or not the shadow is dirty,
3290+ // so that we can turn off tighter caster culling.
3291+ light->detect_light_intersects_multiple_cameras (Engine::get_singleton ()->get_frames_drawn ());
3292+
3293+ if (light->is_shadow_dirty ()) {
3294+ // Dirty shadows have no need to be drawn if
3295+ // the light volume doesn't intersect the camera frustum.
3296+
3297+ // Returns false if the entire light can be culled.
3298+ bool allow_redraw = light_culler->prepare_regular_light (*ins);
3299+
3300+ // Directional lights aren't handled here, _light_instance_update_shadow is called from elsewhere.
3301+ // Checking for this in case this changes, as this is assumed.
3302+ DEV_CHECK_ONCE (RSG::light_storage->light_get_type (ins->base ) != RS::LIGHT_DIRECTIONAL);
3303+
3304+ // Tighter caster culling to the camera frustum should work correctly with multiple viewports + cameras.
3305+ // The first camera will cull tightly, but if the light is present on more than 1 camera, the second will
3306+ // do a full render, and mark the light as non-dirty.
3307+ // There is however a cost to tighter shadow culling in this situation (2 shadow updates in 1 frame),
3308+ // so we should detect this and switch off tighter caster culling automatically.
3309+ // This is done in the logic for `decrement_shadow_dirty()`.
3310+ if (allow_redraw) {
3311+ light->last_version ++;
3312+ light->decrement_shadow_dirty ();
3313+ }
32693314 }
32703315
32713316 bool redraw = RSG::light_storage->shadow_atlas_update_light (p_shadow_atlas, light->instance , coverage, light->last_version );
32723317
32733318 if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
32743319 // must redraw!
32753320 RENDER_TIMESTAMP (" > Render Light3D " + itos (i));
3276- light->shadow_dirty = _light_instance_update_shadow (ins, p_camera_data->main_transform , p_camera_data->main_projection , p_camera_data->is_orthogonal , p_camera_data->vaspect , p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers);
3321+ if (_light_instance_update_shadow (ins, p_camera_data->main_transform , p_camera_data->main_projection , p_camera_data->is_orthogonal , p_camera_data->vaspect , p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers)) {
3322+ light->make_shadow_dirty ();
3323+ }
32773324 RENDER_TIMESTAMP (" < Render Light3D " + itos (i));
32783325 } else {
3279- light->shadow_dirty = redraw;
3326+ if (redraw) {
3327+ light->make_shadow_dirty ();
3328+ }
32803329 }
32813330 }
32823331 }
@@ -3953,7 +4002,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
39534002 // ability to cast shadows change, let lights now
39544003 for (const Instance *E : geom->lights ) {
39554004 InstanceLightData *light = static_cast <InstanceLightData *>(E->base_data );
3956- light->shadow_dirty = true ;
4005+ light->make_shadow_dirty () ;
39574006 }
39584007
39594008 geom->can_cast_shadows = can_cast_shadows;
@@ -4165,6 +4214,12 @@ RendererSceneCull::RendererSceneCull() {
41654214 thread_cull_threshold = MAX (thread_cull_threshold, (uint32_t )WorkerThreadPool::get_singleton ()->get_thread_count ()); // make sure there is at least one thread per CPU
41664215
41674216 dummy_occlusion_culling = memnew (RendererSceneOcclusionCull);
4217+
4218+ light_culler = memnew (RenderingLightCuller);
4219+
4220+ bool tighter_caster_culling = GLOBAL_DEF (" rendering/lights_and_shadows/tighter_shadow_caster_culling" , true );
4221+ light_culler->set_caster_culling_active (tighter_caster_culling);
4222+ light_culler->set_light_culling_active (tighter_caster_culling);
41684223}
41694224
41704225RendererSceneCull::~RendererSceneCull () {
@@ -4187,4 +4242,9 @@ RendererSceneCull::~RendererSceneCull() {
41874242 if (dummy_occlusion_culling) {
41884243 memdelete (dummy_occlusion_culling);
41894244 }
4245+
4246+ if (light_culler) {
4247+ memdelete (light_culler);
4248+ light_culler = nullptr ;
4249+ }
41904250}
0 commit comments