From 0e1858bc4f1a9e7664898c27d41ad19e9c651c31 Mon Sep 17 00:00:00 2001 From: IQuick 143 Date: Wed, 10 Jul 2024 18:00:19 +0200 Subject: [PATCH] fix: Possible NaN due to denormalised quaternions in AABB implementations for round shapes. (#14240) # Objective With an unlucky denormalised quaternion (or just a regular very denormalised quaternion), it's possible to obtain NaN values for AABB's in shapes which rely on an AABB for a disk. ## Solution Add an additional `.max(Vec3::ZERO)` clamp to get rid of negative values arising due to numerical errors. Fixup some unnecessary calculations and improve variable names in relevant code, aiming for consistency. ## Discussion These two (nontrivial) lines of code are repeated at least 5 times, maybe they could be their own method. --- .../src/bounding/bounded3d/extrusion.rs | 2 +- .../src/bounding/bounded3d/primitive_impls.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index a60f98608b..f6aac82d97 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -20,7 +20,7 @@ impl BoundedExtrusion for Circle { let segment_dir = rotation * Vec3::Z; let top = (segment_dir * half_depth).abs(); - let e = Vec3::ONE - segment_dir * segment_dir; + let e = (Vec3::ONE - segment_dir * segment_dir).max(Vec3::ZERO); let half_size = self.radius * Vec3::new(e.x.sqrt(), e.y.sqrt(), e.z.sqrt()); Aabb3d { diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index d11f8b9bbe..efd605a0d9 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -125,7 +125,7 @@ impl Bounded3d for Cylinder { let top = segment_dir * self.half_height; let bottom = -top; - let e = Vec3::ONE - segment_dir * segment_dir; + let e = (Vec3::ONE - segment_dir * segment_dir).max(Vec3::ZERO); let half_size = self.radius * Vec3::new(e.x.sqrt(), e.y.sqrt(), e.z.sqrt()); Aabb3d { @@ -169,11 +169,11 @@ impl Bounded3d for Cone { fn aabb_3d(&self, translation: Vec3, rotation: Quat) -> Aabb3d { // Reference: http://iquilezles.org/articles/diskbbox/ - let top = rotation * Vec3::Y * 0.5 * self.height; + let segment_dir = rotation * Vec3::Y; + let top = segment_dir * 0.5 * self.height; let bottom = -top; - let segment = bottom - top; - let e = 1.0 - segment * segment / segment.length_squared(); + let e = (Vec3::ONE - segment_dir * segment_dir).max(Vec3::ZERO); let half_extents = Vec3::new(e.x.sqrt(), e.y.sqrt(), e.z.sqrt()); Aabb3d { @@ -203,11 +203,11 @@ impl Bounded3d for ConicalFrustum { fn aabb_3d(&self, translation: Vec3, rotation: Quat) -> Aabb3d { // Reference: http://iquilezles.org/articles/diskbbox/ - let top = rotation * Vec3::Y * 0.5 * self.height; + let segment_dir = rotation * Vec3::Y; + let top = segment_dir * 0.5 * self.height; let bottom = -top; - let segment = bottom - top; - let e = 1.0 - segment * segment / segment.length_squared(); + let e = (Vec3::ONE - segment_dir * segment_dir).max(Vec3::ZERO); let half_extents = Vec3::new(e.x.sqrt(), e.y.sqrt(), e.z.sqrt()); Aabb3d { @@ -286,7 +286,7 @@ impl Bounded3d for Torus { // Compute the AABB of a flat disc with the major radius of the torus. // Reference: http://iquilezles.org/articles/diskbbox/ let normal = rotation * Vec3::Y; - let e = 1.0 - normal * normal; + let e = (Vec3::ONE - normal * normal).max(Vec3::ZERO); let disc_half_size = self.major_radius * Vec3::new(e.x.sqrt(), e.y.sqrt(), e.z.sqrt()); // Expand the disc by the minor radius to get the torus half-size