Skip to content

Commit a465c1d

Browse files
committed
Store Mesh AABBs on Meshes instead of Entities
1 parent 724e69b commit a465c1d

File tree

8 files changed

+140
-66
lines changed

8 files changed

+140
-66
lines changed

crates/bevy_gizmos/src/lib.rs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ use bevy_reflect::{
3939
use bevy_render::{
4040
color::Color,
4141
extract_component::{ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin},
42-
primitives::Aabb,
42+
prelude::Mesh,
43+
primitives::{Aabb, AabbSource},
4344
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssets},
4445
render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass},
4546
render_resource::{
@@ -201,30 +202,45 @@ pub struct AabbGizmo {
201202
}
202203

203204
fn draw_aabbs(
204-
query: Query<(Entity, &Aabb, &GlobalTransform, &AabbGizmo)>,
205+
query: Query<(
206+
Entity,
207+
&AabbSource,
208+
&GlobalTransform,
209+
&AabbGizmo,
210+
Option<&Handle<Mesh>>,
211+
)>,
212+
meshes: Res<Assets<Mesh>>,
205213
config: Res<GizmoConfig>,
206214
mut gizmos: Gizmos,
207215
) {
208-
for (entity, &aabb, &transform, gizmo) in &query {
209-
let color = gizmo
210-
.color
211-
.or(config.aabb.default_color)
212-
.unwrap_or_else(|| color_from_entity(entity));
213-
gizmos.cuboid(aabb_transform(aabb, transform), color);
216+
for (entity, &aabb_source, &transform, gizmo, mesh) in &query {
217+
if let Some(aabb) = aabb_source.get(mesh, &meshes) {
218+
let color = gizmo
219+
.color
220+
.or(config.aabb.default_color)
221+
.unwrap_or_else(|| color_from_entity(entity));
222+
gizmos.cuboid(aabb_transform(aabb, transform), color);
223+
}
214224
}
215225
}
216226

217227
fn draw_all_aabbs(
218-
query: Query<(Entity, &Aabb, &GlobalTransform), Without<AabbGizmo>>,
228+
query: Query<
229+
(Entity, &AabbSource, &GlobalTransform, Option<&Handle<Mesh>>),
230+
Without<AabbGizmo>,
231+
>,
232+
meshes: Res<Assets<Mesh>>,
219233
config: Res<GizmoConfig>,
220234
mut gizmos: Gizmos,
221235
) {
222-
for (entity, &aabb, &transform) in &query {
223-
let color = config
224-
.aabb
225-
.default_color
226-
.unwrap_or_else(|| color_from_entity(entity));
227-
gizmos.cuboid(aabb_transform(aabb, transform), color);
236+
for (entity, &aabb_source, &transform, mesh) in &query {
237+
if let Some(aabb) = aabb_source.get(mesh, &meshes) {
238+
let color = config
239+
.aabb
240+
.default_color
241+
.unwrap_or_else(|| color_from_entity(entity));
242+
gizmos.cuboid(aabb_transform(aabb, transform), color);
243+
}
228244
}
229245
}
230246

crates/bevy_gltf/src/loader.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@ async fn load_gltf<'a, 'b>(
306306
}
307307
}
308308

309+
let bounds = primitive.bounding_box();
310+
mesh.set_aabb(Aabb::from_min_max(
311+
Vec3::from_slice(&bounds.min),
312+
Vec3::from_slice(&bounds.max),
313+
));
314+
309315
let mesh = load_context.set_labeled_asset(&primitive_label, LoadedAsset::new(mesh));
310316
primitives.push(super::GltfPrimitive {
311317
mesh,
@@ -783,7 +789,6 @@ fn load_node(
783789
}
784790

785791
let primitive_label = primitive_label(&mesh, &primitive);
786-
let bounds = primitive.bounding_box();
787792
let mesh_asset_path =
788793
AssetPath::new_ref(load_context.path(), Some(&primitive_label));
789794
let material_asset_path =
@@ -808,10 +813,6 @@ fn load_node(
808813
// > the accessors of the original primitive.
809814
primitive_entity.insert(MeshMorphWeights::new(weights).unwrap());
810815
}
811-
primitive_entity.insert(Aabb::from_min_max(
812-
Vec3::from_slice(&bounds.min),
813-
Vec3::from_slice(&bounds.max),
814-
));
815816

816817
if let Some(extras) = primitive.extras() {
817818
primitive_entity.insert(super::GltfExtras {

crates/bevy_pbr/src/bundle.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bevy_ecs::{bundle::Bundle, component::Component, prelude::Entity, reflect::R
77
use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect};
88
use bevy_render::{
99
mesh::Mesh,
10-
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
10+
primitives::{AabbSource, CascadesFrusta, CubemapFrusta, Frustum},
1111
view::{ComputedVisibility, Visibility, VisibleEntities},
1212
};
1313
use bevy_transform::components::{GlobalTransform, Transform};
@@ -27,12 +27,14 @@ pub struct MaterialMeshBundle<M: Material> {
2727
pub visibility: Visibility,
2828
/// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
2929
pub computed_visibility: ComputedVisibility,
30+
pub aabb_source: AabbSource,
3031
}
3132

3233
impl<M: Material> Default for MaterialMeshBundle<M> {
3334
fn default() -> Self {
3435
Self {
3536
mesh: Default::default(),
37+
aabb_source: Default::default(),
3638
material: Default::default(),
3739
transform: Default::default(),
3840
global_transform: Default::default(),

crates/bevy_pbr/src/light.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use bevy_render::{
77
camera::Camera,
88
color::Color,
99
extract_resource::ExtractResource,
10-
prelude::Projection,
11-
primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, HalfSpace, Sphere},
10+
prelude::{Mesh, Projection},
11+
primitives::{Aabb, AabbSource, CascadesFrusta, CubemapFrusta, Frustum, HalfSpace, Sphere},
1212
render_resource::BufferBindingType,
1313
renderer::RenderDevice,
1414
view::{ComputedVisibility, RenderLayers, VisibleEntities},
@@ -22,6 +22,7 @@ use crate::{
2222
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, CUBE_MAP_FACES, MAX_UNIFORM_BUFFER_POINT_LIGHTS,
2323
POINT_LIGHT_NEAR_Z,
2424
};
25+
use bevy_asset::{Assets, Handle};
2526

2627
/// A light that emits light in all directions from a central point.
2728
///
@@ -1911,6 +1912,7 @@ pub fn update_spot_light_frusta(
19111912
}
19121913

19131914
pub fn check_light_mesh_visibility(
1915+
meshes: Res<Assets<Mesh>>,
19141916
visible_point_lights: Query<&VisiblePointLights>,
19151917
mut point_lights: Query<(
19161918
&PointLight,
@@ -1941,8 +1943,9 @@ pub fn check_light_mesh_visibility(
19411943
Entity,
19421944
&mut ComputedVisibility,
19431945
Option<&RenderLayers>,
1944-
Option<&Aabb>,
1946+
Option<&AabbSource>,
19451947
Option<&GlobalTransform>,
1948+
Option<&Handle<Mesh>>,
19461949
),
19471950
(Without<NotShadowCaster>, Without<DirectionalLight>),
19481951
>,
@@ -2002,8 +2005,14 @@ pub fn check_light_mesh_visibility(
20022005

20032006
let view_mask = maybe_view_mask.copied().unwrap_or_default();
20042007

2005-
for (entity, mut computed_visibility, maybe_entity_mask, maybe_aabb, maybe_transform) in
2006-
&mut visible_entity_query
2008+
for (
2009+
entity,
2010+
mut computed_visibility,
2011+
maybe_entity_mask,
2012+
maybe_aabb_source,
2013+
maybe_transform,
2014+
maybe_mesh,
2015+
) in &mut visible_entity_query
20072016
{
20082017
if !computed_visibility.is_visible_in_hierarchy() {
20092018
continue;
@@ -2014,6 +2023,8 @@ pub fn check_light_mesh_visibility(
20142023
continue;
20152024
}
20162025

2026+
let maybe_aabb = maybe_aabb_source.and_then(|s| s.get(maybe_mesh, &meshes));
2027+
20172028
// If we have an aabb and transform, do frustum culling
20182029
if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) {
20192030
for (view, view_frusta) in frusta.frusta.iter() {
@@ -2026,7 +2037,8 @@ pub fn check_light_mesh_visibility(
20262037
view_frusta.iter().zip(view_visible_entities)
20272038
{
20282039
// Disable near-plane culling, as a shadow caster could lie before the near plane.
2029-
if !frustum.intersects_obb(aabb, &transform.compute_matrix(), false, true) {
2040+
if !frustum.intersects_obb(&aabb, &transform.compute_matrix(), false, true)
2041+
{
20302042
continue;
20312043
}
20322044

@@ -2084,8 +2096,9 @@ pub fn check_light_mesh_visibility(
20842096
entity,
20852097
mut computed_visibility,
20862098
maybe_entity_mask,
2087-
maybe_aabb,
2099+
maybe_aabb_source,
20882100
maybe_transform,
2101+
maybe_mesh,
20892102
) in &mut visible_entity_query
20902103
{
20912104
if !computed_visibility.is_visible_in_hierarchy() {
@@ -2097,19 +2110,20 @@ pub fn check_light_mesh_visibility(
20972110
continue;
20982111
}
20992112

2113+
let maybe_aabb = maybe_aabb_source.and_then(|s| s.get(maybe_mesh, &meshes));
21002114
// If we have an aabb and transform, do frustum culling
21012115
if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) {
21022116
let model_to_world = transform.compute_matrix();
21032117
// Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light
2104-
if !light_sphere.intersects_obb(aabb, &model_to_world) {
2118+
if !light_sphere.intersects_obb(&aabb, &model_to_world) {
21052119
continue;
21062120
}
21072121

21082122
for (frustum, visible_entities) in cubemap_frusta
21092123
.iter()
21102124
.zip(cubemap_visible_entities.iter_mut())
21112125
{
2112-
if frustum.intersects_obb(aabb, &model_to_world, true, true) {
2126+
if frustum.intersects_obb(&aabb, &model_to_world, true, true) {
21132127
computed_visibility.set_visible_in_view();
21142128
visible_entities.entities.push(entity);
21152129
}
@@ -2148,8 +2162,9 @@ pub fn check_light_mesh_visibility(
21482162
entity,
21492163
mut computed_visibility,
21502164
maybe_entity_mask,
2151-
maybe_aabb,
2165+
maybe_aabb_source,
21522166
maybe_transform,
2167+
maybe_mesh,
21532168
) in visible_entity_query.iter_mut()
21542169
{
21552170
if !computed_visibility.is_visible_in_hierarchy() {
@@ -2161,15 +2176,16 @@ pub fn check_light_mesh_visibility(
21612176
continue;
21622177
}
21632178

2179+
let maybe_aabb = maybe_aabb_source.and_then(|s| s.get(maybe_mesh, &meshes));
21642180
// If we have an aabb and transform, do frustum culling
21652181
if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) {
21662182
let model_to_world = transform.compute_matrix();
21672183
// Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light
2168-
if !light_sphere.intersects_obb(aabb, &model_to_world) {
2184+
if !light_sphere.intersects_obb(&aabb, &model_to_world) {
21692185
continue;
21702186
}
21712187

2172-
if frustum.intersects_obb(aabb, &model_to_world, true, true) {
2188+
if frustum.intersects_obb(&aabb, &model_to_world, true, true) {
21732189
computed_visibility.set_visible_in_view();
21742190
visible_entities.entities.push(entity);
21752191
}

crates/bevy_render/src/mesh/mesh/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub struct Mesh {
3939
indices: Option<Indices>,
4040
morph_targets: Option<Handle<Image>>,
4141
morph_target_names: Option<Vec<String>>,
42+
aabb: Option<Aabb>,
4243
}
4344

4445
/// Contains geometry in the form of a mesh.
@@ -133,6 +134,7 @@ impl Mesh {
133134
primitive_topology,
134135
attributes: Default::default(),
135136
indices: None,
137+
aabb: None,
136138
morph_targets: None,
137139
morph_target_names: None,
138140
}
@@ -451,6 +453,20 @@ impl Mesh {
451453
None
452454
}
453455

456+
/// Updates the internal AABB (uses the results of [`Mesh::compute_aabb`]).
457+
pub fn update_aabb(&mut self) {
458+
self.aabb = self.compute_aabb();
459+
}
460+
461+
/// Sets the current [`Aabb`] value.
462+
pub fn set_aabb(&mut self, aabb: Aabb) {
463+
self.aabb = Some(aabb);
464+
}
465+
466+
pub fn aabb(&self) -> Option<Aabb> {
467+
self.aabb
468+
}
469+
454470
/// Whether this mesh has morph targets.
455471
pub fn has_morph_targets(&self) -> bool {
456472
self.morph_targets.is_some()

crates/bevy_render/src/primitives/mod.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use crate::mesh::Mesh;
2+
use bevy_asset::{Assets, Handle};
13
use bevy_ecs::{component::Component, prelude::Entity, reflect::ReflectComponent};
24
use bevy_math::{Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
35
use bevy_reflect::{FromReflect, Reflect, ReflectFromReflect};
46
use bevy_utils::HashMap;
57

68
/// An axis-aligned bounding box.
7-
#[derive(Component, Clone, Copy, Debug, Default, Reflect, FromReflect)]
8-
#[reflect(Component)]
9+
#[derive(Clone, Copy, Debug, Default, Reflect, FromReflect)]
910
pub struct Aabb {
1011
pub center: Vec3A,
1112
pub half_extents: Vec3A,
@@ -59,6 +60,22 @@ impl From<Sphere> for Aabb {
5960
}
6061
}
6162

63+
#[derive(Component, Clone, Copy, Debug, Default, Reflect, FromReflect)]
64+
pub enum AabbSource {
65+
#[default]
66+
Mesh,
67+
Aabb(Aabb),
68+
}
69+
70+
impl AabbSource {
71+
pub fn get(&self, handle: Option<&Handle<Mesh>>, meshes: &Assets<Mesh>) -> Option<Aabb> {
72+
match self {
73+
AabbSource::Mesh => handle.and_then(|h| meshes.get(h).and_then(|m| m.aabb())),
74+
AabbSource::Aabb(aabb) => Some(*aabb),
75+
}
76+
}
77+
}
78+
6279
#[derive(Clone, Debug, Default)]
6380
pub struct Sphere {
6481
pub center: Vec3A,

0 commit comments

Comments
 (0)