diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index ef15ffac447ba2..fc9796e83f83f9 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -56,6 +56,7 @@ once_cell = "1.4.1" # TODO: replace once_cell with std equivalent if/when this l downcast-rs = "1.2.0" thiserror = "1.0" futures-lite = "1.4.0" +crossbeam-channel = "0.5.0" anyhow = "1.0" hex = "0.4.2" hexasphere = "7.0.0" diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 104c72757ddc05..4f8a456486a196 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -149,71 +149,65 @@ pub fn update_frusta( pub fn check_visibility( mut view_query: Query<(&mut VisibleEntities, &Frustum, Option<&RenderLayers>), With>, - mut visible_entity_query: ParamSet<( - Query<&mut ComputedVisibility>, - Query<( - Entity, - &Visibility, - &mut ComputedVisibility, - Option<&RenderLayers>, - Option<&Aabb>, - Option<&NoFrustumCulling>, - Option<&GlobalTransform>, - )>, + mut visible_entity_query: Query<( + Entity, + &Visibility, + &mut ComputedVisibility, + Option<&RenderLayers>, + Option<&Aabb>, + Option<&NoFrustumCulling>, + Option<&GlobalTransform>, )>, ) { - // Reset the computed visibility to false - for mut computed_visibility in visible_entity_query.p0().iter_mut() { - computed_visibility.is_visible = false; - } - for (mut visible_entities, frustum, maybe_view_mask) in view_query.iter_mut() { - visible_entities.entities.clear(); let view_mask = maybe_view_mask.copied().unwrap_or_default(); - - for ( - entity, - visibility, - mut computed_visibility, - maybe_entity_mask, - maybe_aabb, - maybe_no_frustum_culling, - maybe_transform, - ) in visible_entity_query.p1().iter_mut() - { - if !visibility.is_visible { - continue; - } - - let entity_mask = maybe_entity_mask.copied().unwrap_or_default(); - if !view_mask.intersects(&entity_mask) { - continue; - } - - // If we have an aabb and transform, do frustum culling - if let (Some(model_aabb), None, Some(transform)) = - (maybe_aabb, maybe_no_frustum_culling, maybe_transform) - { - let model = transform.compute_matrix(); - let model_sphere = Sphere { - center: model.transform_point3a(model_aabb.center), - radius: (Vec3A::from(transform.scale) * model_aabb.half_extents).length(), - }; - // Do quick sphere-based frustum culling - if !frustum.intersects_sphere(&model_sphere, false) { - continue; + let (visible_entity_sender, visible_entity_receiver) = crossbeam_channel::unbounded(); + + visible_entity_query.par_for_each_mut( + 1024, + |( + entity, + visibility, + mut computed_visibility, + maybe_entity_mask, + maybe_aabb, + maybe_no_frustum_culling, + maybe_transform, + )| { + // Reset visibility + computed_visibility.is_visible = false; + + if !visibility.is_visible { + return; } - // If we have an aabb, do aabb-based frustum culling - if !frustum.intersects_obb(model_aabb, &model, false) { - continue; + let entity_mask = maybe_entity_mask.copied().unwrap_or_default(); + if !view_mask.intersects(&entity_mask) { + return; } - } - computed_visibility.is_visible = true; - visible_entities.entities.push(entity); - } + // If we have an aabb and transform, do frustum culling + if let (Some(model_aabb), None, Some(transform)) = + (maybe_aabb, maybe_no_frustum_culling, maybe_transform) + { + let model = transform.compute_matrix(); + let model_sphere = Sphere { + center: model.transform_point3a(model_aabb.center), + radius: (Vec3A::from(transform.scale) * model_aabb.half_extents).length(), + }; + // Do quick sphere-based frustum culling + if !frustum.intersects_sphere(&model_sphere, false) { + return; + } + // If we have an aabb, do aabb-based frustum culling + if !frustum.intersects_obb(model_aabb, &model, false) { + return; + } + } - // TODO: check for big changes in visible entities len() vs capacity() (ex: 2x) and resize - // to prevent holding unneeded memory + computed_visibility.is_visible = true; + visible_entity_sender.send(entity).ok(); + }, + ); + visible_entities.entities = visible_entity_receiver.try_iter().collect(); } }