Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a method to compute a bounding box enclosing a set of points #9630

Merged
merged 8 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 5 additions & 22 deletions crates/bevy_render/src/mesh/mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,27 +464,13 @@ impl Mesh {

/// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space
pub fn compute_aabb(&self) -> Option<Aabb> {
if let Some(VertexAttributeValues::Float32x3(values)) =
let Some(VertexAttributeValues::Float32x3(values)) =
self.attribute(Mesh::ATTRIBUTE_POSITION)
{
let mut minimum = VEC3_MAX;
let mut maximum = VEC3_MIN;
for p in values {
minimum = minimum.min(Vec3::from_slice(p));
maximum = maximum.max(Vec3::from_slice(p));
}
if minimum.x != std::f32::MAX
&& minimum.y != std::f32::MAX
&& minimum.z != std::f32::MAX
&& maximum.x != std::f32::MIN
&& maximum.y != std::f32::MIN
&& maximum.z != std::f32::MIN
{
return Some(Aabb::from_min_max(minimum, maximum));
}
}
else {
return None;
};

None
Aabb::enclosing(values.iter().map(|p| Vec3::from_slice(p)))
}

/// Whether this mesh has morph targets.
Expand Down Expand Up @@ -635,9 +621,6 @@ struct MeshAttributeData {
values: VertexAttributeValues,
}

const VEC3_MIN: Vec3 = Vec3::splat(std::f32::MIN);
const VEC3_MAX: Vec3 = Vec3::splat(std::f32::MAX);

fn face_normal(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> [f32; 3] {
let (a, b, c) = (Vec3::from(a), Vec3::from(b), Vec3::from(c));
(b - a).cross(c - a).normalize().into()
Expand Down
52 changes: 51 additions & 1 deletion crates/bevy_render/src/primitives/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::borrow::Borrow;

use bevy_ecs::{component::Component, prelude::Entity, reflect::ReflectComponent};
use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles};
use bevy_reflect::Reflect;
Expand Down Expand Up @@ -29,7 +31,7 @@ use bevy_utils::HashMap;
/// [`CalculateBounds`]: crate::view::visibility::VisibilitySystems::CalculateBounds
/// [`Mesh`]: crate::mesh::Mesh
/// [`Handle<Mesh>`]: crate::mesh::Mesh
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
#[derive(Component, Clone, Copy, Debug, Default, Reflect, PartialEq)]
#[reflect(Component)]
pub struct Aabb {
pub center: Vec3A,
Expand All @@ -49,6 +51,30 @@ impl Aabb {
}
}

/// Returns a bounding box enclosing the specified set of points.
///
/// Returns `None` if the iterator is empty.
///
/// # Examples
///
/// ```
/// # use bevy_math::{Vec3, Vec3A};
/// # use bevy_render::primitives::Aabb;
/// let bb = Aabb::enclosing([Vec3::X, Vec3::Z * 2.0, Vec3::Y * -0.5]).unwrap();
/// assert_eq!(bb.min(), Vec3A::new(0.0, -0.5, 0.0));
/// assert_eq!(bb.max(), Vec3A::new(1.0, 0.0, 2.0));
/// ```
pub fn enclosing<T: Borrow<Vec3>>(iter: impl IntoIterator<Item = T>) -> Option<Self> {
let mut iter = iter.into_iter().map(|p| *p.borrow());
let mut min = iter.next()?;
let mut max = min;
for v in iter {
min = Vec3::min(min, v);
max = Vec3::max(max, v);
}
Some(Self::from_min_max(min, max))
}

/// Calculate the relative radius of the AABB with respect to a plane
#[inline]
pub fn relative_radius(&self, p_normal: &Vec3A, model: &Mat3A) -> f32 {
Expand Down Expand Up @@ -455,4 +481,28 @@ mod tests {
};
assert!(frustum.intersects_sphere(&sphere, true));
}

#[test]
fn aabb_enclosing() {
assert_eq!(Aabb::enclosing(<[Vec3; 0]>::default()), None);
assert_eq!(
Aabb::enclosing(vec![Vec3::ONE]).unwrap(),
Aabb::from_min_max(Vec3::ONE, Vec3::ONE)
);
assert_eq!(
Aabb::enclosing(&[Vec3::Y, Vec3::X, Vec3::Z][..]).unwrap(),
Aabb::from_min_max(Vec3::ZERO, Vec3::ONE)
);
assert_eq!(
Aabb::enclosing([
Vec3::NEG_X,
Vec3::X * 2.0,
Vec3::NEG_Y * 5.0,
Vec3::Z,
Vec3::ZERO
])
.unwrap(),
Aabb::from_min_max(Vec3::new(-1.0, -5.0, 0.0), Vec3::new(2.0, 0.0, 1.0))
);
}
}