mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
Add a method to compute a bounding box enclosing a set of points (#9630)
# Objective Make it easier to create bounding boxes in user code by providing a constructor that computes a box surrounding an arbitrary number of points. ## Solution Add `Aabb::enclosing`, which accepts iterators, slices, or arrays. --------- Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
This commit is contained in:
parent
36eedbfa92
commit
23598d7bec
2 changed files with 56 additions and 23 deletions
|
@ -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.
|
||||
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue