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
					
				@ -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 New Issue
	
	Block a user