@@ -133,6 +133,16 @@ impl Aabb {
133133 let signed_distance = p_normal. dot ( aabb_center_world) + half_space. d ( ) ;
134134 signed_distance > r
135135 }
136+
137+ /// Optimized version of [`Self::is_in_half_space`] when the AABB is already in world space.
138+ /// Use this when `world_from_local` would be the identity transform.
139+ #[ inline]
140+ pub fn is_in_half_space_identity ( & self , half_space : & HalfSpace ) -> bool {
141+ let p_normal = half_space. normal ( ) ;
142+ let r = self . half_extents . abs ( ) . dot ( p_normal. abs ( ) ) ;
143+ let signed_distance = p_normal. dot ( self . center ) + half_space. d ( ) ;
144+ signed_distance > r
145+ }
136146}
137147
138148impl From < Aabb3d > for Aabb {
@@ -369,7 +379,22 @@ impl Frustum {
369379 true
370380 }
371381
372- /// Check if the frustum contains the Axis-Aligned Bounding Box (AABB).
382+ /// Optimized version of [`Frustum::intersects_obb`]
383+ /// where the transform is [`Affine3A::IDENTITY`] and both `intersect_near` and `intersect_far` are `true`.
384+ #[ inline]
385+ pub fn intersects_obb_identity ( & self , aabb : & Aabb ) -> bool {
386+ let aabb_center_world = aabb. center . extend ( 1.0 ) ;
387+ for half_space in self . half_spaces . iter ( ) {
388+ let p_normal = half_space. normal ( ) ;
389+ let relative_radius = aabb. half_extents . abs ( ) . dot ( p_normal. abs ( ) ) ;
390+ if half_space. normal_d ( ) . dot ( aabb_center_world) + relative_radius <= 0.0 {
391+ return false ;
392+ }
393+ }
394+ true
395+ }
396+
397+ /// Check if the frustum contains the entire Axis-Aligned Bounding Box (AABB).
373398 /// Referenced from: [Frustum Culling](https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling)
374399 #[ inline]
375400 pub fn contains_aabb ( & self , aabb : & Aabb , world_from_local : & Affine3A ) -> bool {
@@ -380,6 +405,18 @@ impl Frustum {
380405 }
381406 true
382407 }
408+
409+ /// Optimized version of [`Self::contains_aabb`] when the AABB is already in world space.
410+ /// Use this when `world_from_local` would be [`Affine3A::IDENTITY`].
411+ #[ inline]
412+ pub fn contains_aabb_identity ( & self , aabb : & Aabb ) -> bool {
413+ for half_space in & self . half_spaces {
414+ if !aabb. is_in_half_space_identity ( half_space) {
415+ return false ;
416+ }
417+ }
418+ true
419+ }
383420}
384421
385422pub struct CubeMapFace {
@@ -772,4 +809,62 @@ mod tests {
772809 ) ;
773810 assert ! ( !frustum. contains_aabb( & aabb, & model) ) ;
774811 }
812+
813+ #[ test]
814+ fn test_identity_optimized_equivalence ( ) {
815+ let cases = vec ! [
816+ (
817+ Aabb {
818+ center: Vec3A :: ZERO ,
819+ half_extents: Vec3A :: splat( 1.0 ) ,
820+ } ,
821+ HalfSpace :: new( Vec4 :: new( 1.0 , 0.0 , 0.0 , -0.5 ) ) ,
822+ ) ,
823+ (
824+ Aabb {
825+ center: Vec3A :: new( 2.0 , -1.0 , 0.5 ) ,
826+ half_extents: Vec3A :: new( 1.0 , 2.0 , 0.5 ) ,
827+ } ,
828+ HalfSpace :: new( Vec4 :: new( 1.0 , 1.0 , 1.0 , -1.0 ) . normalize( ) ) ,
829+ ) ,
830+ (
831+ Aabb {
832+ center: Vec3A :: new( 1.0 , 1.0 , 1.0 ) ,
833+ half_extents: Vec3A :: ZERO ,
834+ } ,
835+ HalfSpace :: new( Vec4 :: new( 0.0 , 0.0 , 1.0 , -2.0 ) ) ,
836+ ) ,
837+ ] ;
838+ for ( aabb, half_space) in cases {
839+ let general = aabb. is_in_half_space ( & half_space, & Affine3A :: IDENTITY ) ;
840+ let identity = aabb. is_in_half_space_identity ( & half_space) ;
841+ assert_eq ! ( general, identity, ) ;
842+ }
843+ }
844+
845+ #[ test]
846+ fn intersects_obb_identity_matches_standard_true_true ( ) {
847+ let frusta = [ frustum ( ) , long_frustum ( ) , big_frustum ( ) ] ;
848+ let aabbs = [
849+ Aabb {
850+ center : Vec3A :: ZERO ,
851+ half_extents : Vec3A :: new ( 0.5 , 0.5 , 0.5 ) ,
852+ } ,
853+ Aabb {
854+ center : Vec3A :: new ( 1.0 , 0.0 , 0.5 ) ,
855+ half_extents : Vec3A :: new ( 0.9 , 0.9 , 0.9 ) ,
856+ } ,
857+ Aabb {
858+ center : Vec3A :: new ( 100.0 , 100.0 , 100.0 ) ,
859+ half_extents : Vec3A :: new ( 1.0 , 1.0 , 1.0 ) ,
860+ } ,
861+ ] ;
862+ for fr in & frusta {
863+ for aabb in & aabbs {
864+ let standard = fr. intersects_obb ( aabb, & Affine3A :: IDENTITY , true , true ) ;
865+ let optimized = fr. intersects_obb_identity ( aabb) ;
866+ assert_eq ! ( standard, optimized) ;
867+ }
868+ }
869+ }
775870}
0 commit comments