diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 123756e49102b..7299547e71f46 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -1,5 +1,3 @@ -use std::ops::DerefMut; - use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Vec3A, Vec4}; @@ -16,7 +14,6 @@ use bevy_render::{ }, }; use bevy_transform::components::{GlobalTransform, Transform}; -use bevy_utils::Parallel; use crate::*; @@ -658,21 +655,21 @@ fn shrink_entities(visible_entities: &mut Vec) { } pub fn check_dir_light_mesh_visibility( - mut commands: Commands, mut directional_lights: Query< ( &DirectionalLight, &CascadesFrusta, &mut CascadesVisibleEntities, Option<&RenderLayers>, - &ViewVisibility, + &mut ViewVisibility, ), Without, >, - visible_entity_query: Query< + mut visible_entity_query: Query< ( Entity, &InheritedVisibility, + &mut ViewVisibility, Option<&RenderLayers>, Option<&Aabb>, Option<&GlobalTransform>, @@ -685,144 +682,113 @@ pub fn check_dir_light_mesh_visibility( ), >, visible_entity_ranges: Option>, - mut visible_entities_queue: Local>>, - mut view_visible_entities_queue: Local>>>, ) { let visible_entity_ranges = visible_entity_ranges.as_deref(); - directional_lights.iter_mut().for_each( - |( - directional_light, - frusta, - mut cascades_visible_entities, - maybe_view_mask, - light_view_visibility, - )| { - let mut views_to_remove = Vec::new(); - for (view, cascade_view_entities) in &mut cascades_visible_entities.entities { - match frusta.frusta.get(view) { - Some(view_frusta) => { - cascade_view_entities.resize(view_frusta.len(), Default::default()); - cascade_view_entities - .iter_mut() - .for_each(|x| x.entities.clear()); - } - None => views_to_remove.push(*view), - }; - } - for (view, frusta) in &frusta.frusta { - cascades_visible_entities - .entities - .entry(*view) - .or_insert_with(|| vec![VisibleEntities::default(); frusta.len()]); - } + // Directional lights + for (directional_light, frusta, mut visible_entities, maybe_view_mask, light_view_visibility) in + &mut directional_lights + { + // Re-use already allocated entries where possible. + let mut views_to_remove = Vec::new(); + for (view, cascade_view_entities) in &mut visible_entities.entities { + match frusta.frusta.get(view) { + Some(view_frusta) => { + cascade_view_entities.resize(view_frusta.len(), Default::default()); + cascade_view_entities + .iter_mut() + .for_each(|x| x.clear::()); + } + None => views_to_remove.push(*view), + }; + } + for (view, frusta) in &frusta.frusta { + visible_entities + .entities + .entry(*view) + .or_insert_with(|| vec![VisibleEntities::default(); frusta.len()]); + } + for v in views_to_remove { + visible_entities.entities.remove(&v); + } - for v in views_to_remove { - cascades_visible_entities.entities.remove(&v); - } + // NOTE: If shadow mapping is disabled for the light then it must have no visible entities + if !directional_light.shadows_enabled || !light_view_visibility.get() { + continue; + } - // NOTE: If shadow mapping is disabled for the light then it must have no visible entities - if !directional_light.shadows_enabled || !light_view_visibility.get() { - return; + let view_mask = maybe_view_mask.unwrap_or_default(); + + for ( + entity, + inherited_visibility, + mut view_visibility, + maybe_entity_mask, + maybe_aabb, + maybe_transform, + has_visibility_range, + ) in &mut visible_entity_query + { + if !inherited_visibility.get() { + continue; } - let view_mask = maybe_view_mask.unwrap_or_default(); - - for (view, view_frusta) in &frusta.frusta { - visible_entity_query.par_iter().for_each_init( - || { - let mut entities = view_visible_entities_queue.borrow_local_mut(); - let cap = entities.first().map(|v| v.capacity()).unwrap_or_default(); - entities.resize(view_frusta.len(), Vec::with_capacity(cap)); - (visible_entities_queue.borrow_local_mut(), entities) - }, - |(queue0, queue1), - ( - entity, - inherited_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_transform, - has_visibility_range, - )| { - if !inherited_visibility.get() { - return; - } + let entity_mask = maybe_entity_mask.unwrap_or_default(); + if !view_mask.intersects(entity_mask) { + continue; + } - let entity_mask = maybe_entity_mask.unwrap_or_default(); - if !view_mask.intersects(entity_mask) { - return; - } + // If we have an aabb and transform, do frustum culling + if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { + for (view, view_frusta) in &frusta.frusta { + let view_visible_entities = visible_entities + .entities + .get_mut(view) + .expect("Per-view visible entities should have been inserted already"); + + // Check visibility ranges. + if has_visibility_range + && visible_entity_ranges.is_some_and(|visible_entity_ranges| { + !visible_entity_ranges.entity_is_in_range_of_view(entity, *view) + }) + { + continue; + } - // Check visibility ranges. - if has_visibility_range - && visible_entity_ranges.is_some_and(|visible_entity_ranges| { - !visible_entity_ranges.entity_is_in_range_of_view(entity, *view) - }) - { - return; + for (frustum, frustum_visible_entities) in + view_frusta.iter().zip(view_visible_entities) + { + // Disable near-plane culling, as a shadow caster could lie before the near plane. + if !frustum.intersects_obb(aabb, &transform.affine(), false, true) { + continue; } - if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - let mut visible = false; - for (frustum, frustum_visible_entities) in - view_frusta.iter().zip(queue1.iter_mut()) - { - // Disable near-plane culling, as a shadow caster could lie before the near plane. - if !frustum.intersects_obb(aabb, &transform.affine(), false, true) { - continue; - } - visible = true; - - frustum_visible_entities.push(entity); - } - if visible { - queue0.push(entity); - } - } else { - queue0.push(entity); - for frustum_visible_entities in queue1.iter_mut() { - frustum_visible_entities.push(entity); - } - } - }, - ); - for entities in view_visible_entities_queue.iter_mut() { - cascades_visible_entities + view_visibility.set(); + frustum_visible_entities.get_mut::().push(entity); + } + } + } else { + view_visibility.set(); + for view in frusta.frusta.keys() { + let view_visible_entities = visible_entities .entities .get_mut(view) - .unwrap() - .iter_mut() - .map(|v| v.get_mut::()) - .zip(entities.iter_mut()) - .for_each(|(dst, source)| { - dst.append(source); - }); + .expect("Per-view visible entities should have been inserted already"); + + for frustum_visible_entities in view_visible_entities { + frustum_visible_entities.get_mut::().push(entity); + } } } - }, - ); + } - for (_, _, mut cascades_visible_entities, _, _) in &mut directional_lights { - for (_, cascade_view_entities) in &mut cascades_visible_entities.entities { + for (_, cascade_view_entities) in &mut visible_entities.entities { cascade_view_entities .iter_mut() .map(|x| x.get_mut::()) .for_each(shrink_entities); } } - - // TODO: use resource to avoid unnecessary memory alloc - let mut defer_queue = std::mem::take(visible_entities_queue.deref_mut()); - commands.add(move |world: &mut World| { - let mut query = world.query::<&mut ViewVisibility>(); - for entities in defer_queue.iter_mut() { - let mut iter = query.iter_many_mut(world, entities.iter()); - while let Some(mut t) = iter.fetch_next() { - t.set(); - } - } - }); } pub fn check_point_light_mesh_visibility( @@ -858,10 +824,9 @@ pub fn check_point_light_mesh_visibility( ), >, visible_entity_ranges: Option>, - mut cubmap_visible_entity_queue: Local; 6]>>, - mut spot_visible_entity_queue: Local>>, ) { let visible_entity_ranges = visible_entity_ranges.as_deref(); + for visible_lights in &visible_point_lights { for light_entity in visible_lights.entities.iter().copied() { // Point lights @@ -888,64 +853,57 @@ pub fn check_point_light_mesh_visibility( radius: point_light.range, }; - visible_entity_query.par_iter_mut().for_each_init( - || cubmap_visible_entity_queue.borrow_local_mut(), - |queue, - ( - entity, - inherited_visibility, - mut view_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_transform, - has_visibility_range, - )| { - if !inherited_visibility.get() { - return; - } - let entity_mask = maybe_entity_mask.unwrap_or_default(); - if !view_mask.intersects(entity_mask) { - return; - } - if has_visibility_range - && visible_entity_ranges.is_some_and(|visible_entity_ranges| { - !visible_entity_ranges.entity_is_in_range_of_any_view(entity) - }) - { - return; - } + for ( + entity, + inherited_visibility, + mut view_visibility, + maybe_entity_mask, + maybe_aabb, + maybe_transform, + has_visibility_range, + ) in &mut visible_entity_query + { + if !inherited_visibility.get() { + continue; + } - // If we have an aabb and transform, do frustum culling - if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - let model_to_world = transform.affine(); - // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light - if !light_sphere.intersects_obb(aabb, &model_to_world) { - return; - } + let entity_mask = maybe_entity_mask.unwrap_or_default(); + if !view_mask.intersects(entity_mask) { + continue; + } - for (frustum, visible_entities) in - cubemap_frusta.iter().zip(queue.iter_mut()) - { - if frustum.intersects_obb(aabb, &model_to_world, true, true) { - view_visibility.set(); - visible_entities.push(entity); - } - } - } else { - view_visibility.set(); - for visible_entities in queue.iter_mut() { - visible_entities.push(entity); - } + // Check visibility ranges. + if has_visibility_range + && visible_entity_ranges.is_some_and(|visible_entity_ranges| { + !visible_entity_ranges.entity_is_in_range_of_any_view(entity) + }) + { + continue; + } + + // If we have an aabb and transform, do frustum culling + if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { + let model_to_world = transform.affine(); + // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light + if !light_sphere.intersects_obb(aabb, &model_to_world) { + continue; } - }, - ); - for entities in cubmap_visible_entity_queue.iter_mut() { - cubemap_visible_entities - .iter_mut() - .map(|v| v.get_mut::()) - .zip(entities.iter_mut()) - .for_each(|(dst, source)| dst.append(source)); + for (frustum, visible_entities) in cubemap_frusta + .iter() + .zip(cubemap_visible_entities.iter_mut()) + { + if frustum.intersects_obb(aabb, &model_to_world, true, true) { + view_visibility.set(); + visible_entities.push::(entity); + } + } + } else { + view_visibility.set(); + for visible_entities in cubemap_visible_entities.iter_mut() { + visible_entities.push::(entity); + } + } } for visible_entities in cubemap_visible_entities.iter_mut() { @@ -970,55 +928,50 @@ pub fn check_point_light_mesh_visibility( radius: point_light.range, }; - visible_entity_query.par_iter_mut().for_each_init( - || spot_visible_entity_queue.borrow_local_mut(), - |queue, - ( - entity, - inherited_visibility, - mut view_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_transform, - has_visibility_range, - )| { - if !inherited_visibility.get() { - return; - } + for ( + entity, + inherited_visibility, + mut view_visibility, + maybe_entity_mask, + maybe_aabb, + maybe_transform, + has_visibility_range, + ) in &mut visible_entity_query + { + if !inherited_visibility.get() { + continue; + } - let entity_mask = maybe_entity_mask.unwrap_or_default(); - if !view_mask.intersects(entity_mask) { - return; - } - // Check visibility ranges. - if has_visibility_range - && visible_entity_ranges.is_some_and(|visible_entity_ranges| { - !visible_entity_ranges.entity_is_in_range_of_any_view(entity) - }) - { - return; - } + let entity_mask = maybe_entity_mask.unwrap_or_default(); + if !view_mask.intersects(entity_mask) { + continue; + } - if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { - let model_to_world = transform.affine(); - // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light - if !light_sphere.intersects_obb(aabb, &model_to_world) { - return; - } + // Check visibility ranges. + if has_visibility_range + && visible_entity_ranges.is_some_and(|visible_entity_ranges| { + !visible_entity_ranges.entity_is_in_range_of_any_view(entity) + }) + { + continue; + } - if frustum.intersects_obb(aabb, &model_to_world, true, true) { - view_visibility.set(); - queue.push(entity); - } - } else { - view_visibility.set(); - queue.push(entity); + // If we have an aabb and transform, do frustum culling + if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { + let model_to_world = transform.affine(); + // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light + if !light_sphere.intersects_obb(aabb, &model_to_world) { + continue; } - }, - ); - for entities in spot_visible_entity_queue.iter_mut() { - visible_entities.get_mut::().append(entities); + if frustum.intersects_obb(aabb, &model_to_world, true, true) { + view_visibility.set(); + visible_entities.push::(entity); + } + } else { + view_visibility.set(); + visible_entities.push::(entity); + } } shrink_entities(visible_entities.get_mut::());