Skip to content
54 changes: 54 additions & 0 deletions crates/bevy_camera/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ impl Aabb {
let signed_distance = p_normal.dot(aabb_center_world) + half_space.d();
signed_distance > r
}

/// Optimized version of [`Self::is_in_half_space`] when the AABB is already in world space.
/// Use this when `world_from_local` would be the identity transform.
#[inline]
pub fn is_in_half_space_identity(&self, half_space: &HalfSpace) -> bool {
let p_normal = half_space.normal();
let r = self.half_extents.abs().dot(p_normal.abs());
let signed_distance = p_normal.dot(self.center) + half_space.d();
signed_distance > r
}
}

impl From<Sphere> for Aabb {
Expand Down Expand Up @@ -348,6 +358,18 @@ impl Frustum {
}
true
}

/// Optimized version of [`Self::contains_aabb`] when the AABB is already in world space.
/// Use this when `world_from_local` would be [`Affine3A::IDENTITY`].
#[inline]
pub fn contains_aabb_identity(&self, aabb: &Aabb) -> bool {
for half_space in &self.half_spaces {
if !aabb.is_in_half_space_identity(half_space) {
return false;
}
}
true
}
}

pub struct CubeMapFace {
Expand Down Expand Up @@ -740,4 +762,36 @@ mod tests {
);
assert!(!frustum.contains_aabb(&aabb, &model));
}

#[test]
fn test_identity_optimized_equivalence() {
let cases = vec![
(
Aabb {
center: Vec3A::ZERO,
half_extents: Vec3A::splat(1.0),
},
HalfSpace::new(Vec4::new(1.0, 0.0, 0.0, -0.5)),
),
(
Aabb {
center: Vec3A::new(2.0, -1.0, 0.5),
half_extents: Vec3A::new(1.0, 2.0, 0.5),
},
HalfSpace::new(Vec4::new(1.0, 1.0, 1.0, -1.0).normalize()),
),
(
Aabb {
center: Vec3A::new(1.0, 1.0, 1.0),
half_extents: Vec3A::ZERO,
},
HalfSpace::new(Vec4::new(0.0, 0.0, 1.0, -2.0)),
),
];
for (aabb, half_space) in cases {
let general = aabb.is_in_half_space(&half_space, &Affine3A::IDENTITY);
let identity = aabb.is_in_half_space_identity(&half_space);
assert_eq!(general, identity,);
}
}
}
Loading