From 2811a034b8770de781b647fb688522f8b53c3c35 Mon Sep 17 00:00:00 2001 From: Eero Lehtinen Date: Sun, 18 May 2025 09:24:37 +0300 Subject: [PATCH] Fix point light shadow glitches (#19265) # Objective Fixes #18945 ## Solution Entities that are not visible in any view (camera or light), get their render meshes removed. When they become visible somewhere again, the meshes get recreated and assigned possibly different ids. Point/spot light visible entities weren't cleared when the lights themseves went out of view, which caused them to try to queue these fake visible entities for rendering every frame. The shadow phase cache usually flushes non visible entites, but because of this bug it never flushed them and continued to queue meshes with outdated ids. The simple solution is to every frame clear all visible entities for all point/spot lights that may or may not be visible. The visible entities get repopulated directly afterwards. I also renamed the `global_point_lights` to `global_visible_clusterable` to make it clear that it includes only visible things. ## Testing - Tested with the code from the issue. --- crates/bevy_pbr/src/render/light.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index d71dccc71a..dfc7f679f3 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -220,7 +220,8 @@ pub fn extract_lights( mut commands: Commands, point_light_shadow_map: Extract>, directional_light_shadow_map: Extract>, - global_point_lights: Extract>, + global_visible_clusterable: Extract>, + cubemap_visible_entities: Extract>>, point_lights: Extract< Query<( Entity, @@ -276,6 +277,16 @@ pub fn extract_lights( if directional_light_shadow_map.is_changed() { commands.insert_resource(directional_light_shadow_map.clone()); } + + // Clear previous visible entities for all cubemapped lights as they might not be in the + // `global_visible_clusterable` list anymore. + commands.try_insert_batch( + cubemap_visible_entities + .iter() + .map(|render_entity| (render_entity, RenderCubemapVisibleEntities::default())) + .collect::>(), + ); + // This is the point light shadow map texel size for one face of the cube as a distance of 1.0 // world unit from the light. // point_light_texel_size = 2.0 * 1.0 * tan(PI / 4.0) / cube face width in texels @@ -286,7 +297,7 @@ pub fn extract_lights( let point_light_texel_size = 2.0 / point_light_shadow_map.size as f32; let mut point_lights_values = Vec::with_capacity(*previous_point_lights_len); - for entity in global_point_lights.iter().copied() { + for entity in global_visible_clusterable.iter().copied() { let Ok(( main_entity, render_entity, @@ -350,7 +361,7 @@ pub fn extract_lights( commands.try_insert_batch(point_lights_values); let mut spot_lights_values = Vec::with_capacity(*previous_spot_lights_len); - for entity in global_point_lights.iter().copied() { + for entity in global_visible_clusterable.iter().copied() { if let Ok(( main_entity, render_entity,