diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 63c931a8b035d..284a4d469fa51 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -10,14 +10,6 @@ use derive_more::derive::{Deref, DerefMut}; pub use range::*; pub use render_layers::*; -use bevy_app::{Plugin, PostUpdate}; -use bevy_asset::Assets; -use bevy_ecs::{hierarchy::validate_parent_has_component, prelude::*}; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; -use bevy_transform::{components::GlobalTransform, TransformSystem}; -use bevy_utils::{Parallel, TypeIdMap}; -use smallvec::SmallVec; - use super::NoCpuCulling; use crate::{ camera::{Camera, CameraProjection, Projection}, @@ -25,6 +17,13 @@ use crate::{ primitives::{Aabb, Frustum, Sphere}, sync_world::MainEntity, }; +use bevy_app::{Plugin, PostUpdate}; +use bevy_asset::{prelude::*, AssetEvents}; +use bevy_ecs::{hierarchy::validate_parent_has_component, prelude::*}; +use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_transform::{components::GlobalTransform, TransformSystem}; +use bevy_utils::{Parallel, TypeIdMap}; +use smallvec::SmallVec; /// User indication of whether an entity is visible. Propagates down the entity hierarchy. /// @@ -340,10 +339,18 @@ impl Plugin for VisibilityPlugin { app.register_type::() .configure_sets( PostUpdate, - (CalculateBounds, UpdateFrusta, VisibilityPropagate) + (UpdateFrusta, VisibilityPropagate) .before(CheckVisibility) .after(TransformSystem::TransformPropagate), ) + .configure_sets( + PostUpdate, + (CalculateBounds) + .before(CheckVisibility) + .after(TransformSystem::TransformPropagate) + .after(AssetEvents) + .ambiguous_with(CalculateBounds), + ) .configure_sets( PostUpdate, MarkNewlyHiddenEntitiesInvisible.after(CheckVisibility), @@ -369,15 +376,30 @@ impl Plugin for VisibilityPlugin { pub fn calculate_bounds( mut commands: Commands, meshes: Res>, - without_aabb: Query<(Entity, &Mesh3d), (Without, Without)>, + new_aabb: Query<(Entity, &Mesh3d), (Without, Without)>, + mut update_aabb: Query< + (&Mesh3d, &mut Aabb), + ( + Or<(AssetChanged, Changed)>, + Without, + ), + >, ) { - for (entity, mesh_handle) in &without_aabb { + for (entity, mesh_handle) in &new_aabb { if let Some(mesh) = meshes.get(mesh_handle) { if let Some(aabb) = mesh.compute_aabb() { commands.entity(entity).try_insert(aabb); } } } + + update_aabb + .par_iter_mut() + .for_each(|(mesh_handle, mut old_aabb)| { + if let Some(aabb) = meshes.get(mesh_handle).and_then(MeshAabb::compute_aabb) { + *old_aabb = aabb; + } + }); } /// Updates [`Frustum`]. diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 37d4d2d6e48ef..5aa3e6b2339dd 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -42,10 +42,12 @@ pub use sprite::*; pub use texture_slice::*; use bevy_app::prelude::*; +use bevy_asset::prelude::AssetChanged; use bevy_asset::{load_internal_asset, weak_handle, AssetEvents, Assets, Handle}; use bevy_core_pipeline::core_2d::{AlphaMask2d, Opaque2d, Transparent2d}; use bevy_ecs::prelude::*; use bevy_image::{prelude::*, TextureAtlasPlugin}; +use bevy_math::Vec2; use bevy_render::{ batching::sort_binned_render_phase, mesh::{Mesh, Mesh2d, MeshAabb}, @@ -163,24 +165,43 @@ pub fn calculate_bounds_2d( meshes: Res>, images: Res>, atlases: Res>, - meshes_without_aabb: Query<(Entity, &Mesh2d), (Without, Without)>, - sprites_to_recalculate_aabb: Query< - (Entity, &Sprite), + new_mesh_aabb: Query<(Entity, &Mesh2d), (Without, Without)>, + mut update_mesh_aabb: Query< + (&Mesh2d, &mut Aabb), ( - Or<(Without, Changed)>, + Or<(AssetChanged, Changed)>, Without, + Without, // disjoint mutable query + ), + >, + new_sprite_aabb: Query<(Entity, &Sprite), (Without, Without)>, + mut update_sprite_aabb: Query< + (&Sprite, &mut Aabb), + ( + Changed, + Without, + Without, // disjoint mutable query ), >, ) { - for (entity, mesh_handle) in &meshes_without_aabb { - if let Some(mesh) = meshes.get(&mesh_handle.0) { + for (entity, mesh_handle) in &new_mesh_aabb { + if let Some(mesh) = meshes.get(mesh_handle) { if let Some(aabb) = mesh.compute_aabb() { commands.entity(entity).try_insert(aabb); } } } - for (entity, sprite) in &sprites_to_recalculate_aabb { - if let Some(size) = sprite + + update_mesh_aabb + .par_iter_mut() + .for_each(|(mesh_handle, mut old_aabb)| { + if let Some(aabb) = meshes.get(mesh_handle).and_then(MeshAabb::compute_aabb) { + *old_aabb = aabb; + } + }); + + let sprite_size = |sprite: &Sprite| -> Option { + sprite .custom_size .or_else(|| sprite.rect.map(|rect| rect.size())) .or_else(|| match &sprite.texture_atlas { @@ -191,14 +212,29 @@ pub fn calculate_bounds_2d( .texture_rect(&atlases) .map(|rect| rect.size().as_vec2()), }) - { - let aabb = Aabb { - center: (-sprite.anchor.as_vec() * size).extend(0.0).into(), - half_extents: (0.5 * size).extend(0.0).into(), - }; - commands.entity(entity).try_insert(aabb); - } + }; + + for (size, (entity, sprite)) in new_sprite_aabb + .iter() + .filter_map(|(entity, sprite)| sprite_size(sprite).zip(Some((entity, sprite)))) + { + let aabb = Aabb { + center: (-sprite.anchor.as_vec() * size).extend(0.0).into(), + half_extents: (0.5 * size).extend(0.0).into(), + }; + commands.entity(entity).try_insert(aabb); } + + update_sprite_aabb + .par_iter_mut() + .for_each(|(sprite, mut aabb)| { + if let Some(size) = sprite_size(sprite) { + *aabb = Aabb { + center: (-sprite.anchor.as_vec() * size).extend(0.0).into(), + half_extents: (0.5 * size).extend(0.0).into(), + }; + } + }); } #[cfg(test)]