Browse Source

Fixed GetWorldSpaceBounds returning an infinite sized bounding box for empty mutable compound (#366)

This bug also caused bounding boxes to be much bigger than needed in double precision mode which was one of the main causes of slowdown compared to single precision mode. Updated the documentation to reflect this.
Jorrit Rouwe 2 years ago
parent
commit
f7d19a91da
3 changed files with 32 additions and 2 deletions
  1. 1 1
      Docs/Architecture.md
  2. 10 1
      Jolt/Physics/Collision/Shape/Shape.h
  3. 21 0
      UnitTests/Physics/ShapeTests.cpp

+ 1 - 1
Docs/Architecture.md

@@ -307,7 +307,7 @@ Keep in mind that:
 * When the collision results of a single query are kilometers apart, precision will suffer as they will be far away from the 'base offset'.
 * When the collision results of a single query are kilometers apart, precision will suffer as they will be far away from the 'base offset'.
 * The effectiveness of the broad phase (which works in floats) will become less at large distances from the origin, e.g. at 10000 km from the origin, the resolution of the broad phase is reduced to 1 m which means that everything that's closer than 1 m will be considered colliding. This will not impact the quality of the simulation but it will result in extra collision tests in the narrow phase so will hurt performance.
 * The effectiveness of the broad phase (which works in floats) will become less at large distances from the origin, e.g. at 10000 km from the origin, the resolution of the broad phase is reduced to 1 m which means that everything that's closer than 1 m will be considered colliding. This will not impact the quality of the simulation but it will result in extra collision tests in the narrow phase so will hurt performance.
 
 
-Because of the minimal use of doubles, the simulation runs 10-20% slower in double precision mode compared to float precision mode.
+Because of the minimal use of doubles, the simulation runs 5-10% slower in double precision mode compared to float precision mode.
 
 
 ## Continuous Collision Detection
 ## Continuous Collision Detection
 
 

+ 10 - 1
Jolt/Physics/Collision/Shape/Shape.h

@@ -195,7 +195,16 @@ public:
 	virtual AABox					GetWorldSpaceBounds(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const { return GetLocalBounds().Scaled(inScale).Transformed(inCenterOfMassTransform); }
 	virtual AABox					GetWorldSpaceBounds(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const { return GetLocalBounds().Scaled(inScale).Transformed(inCenterOfMassTransform); }
 
 
 	/// Get world space bounds including convex radius.
 	/// Get world space bounds including convex radius.
-	AABox							GetWorldSpaceBounds(DMat44Arg inCenterOfMassTransform, Vec3Arg inScale) const { return GetLocalBounds().Scaled(inScale).Transformed(inCenterOfMassTransform); }
+	AABox							GetWorldSpaceBounds(DMat44Arg inCenterOfMassTransform, Vec3Arg inScale) const
+	{
+		// Use single precision version using the rotation only
+		AABox bounds = GetWorldSpaceBounds(inCenterOfMassTransform.GetRotation(), inScale);
+
+		// Apply translation
+		bounds.Translate(inCenterOfMassTransform.GetTranslation());
+
+		return bounds;
+	}
 
 
 	/// Returns the radius of the biggest sphere that fits entirely in the shape. In case this shape consists of multiple sub shapes, it returns the smallest sphere of the parts. 
 	/// Returns the radius of the biggest sphere that fits entirely in the shape. In case this shape consists of multiple sub shapes, it returns the smallest sphere of the parts. 
 	/// This can be used as a measure of how far the shape can be moved without risking going through geometry.
 	/// This can be used as a measure of how far the shape can be moved without risking going through geometry.

+ 21 - 0
UnitTests/Physics/ShapeTests.cpp

@@ -598,4 +598,25 @@ TEST_SUITE("ShapeTests")
 			}
 			}
 		}
 		}
 	}
 	}
+
+	TEST_CASE("TestEmptyMutableCompound")
+	{
+		// Create empty shape
+		RefConst<Shape> mutable_compound = new MutableCompoundShape();
+
+		// A non-identity rotation
+		Quat rotation = Quat::sRotation(Vec3::sReplicate(1.0f / sqrt(3.0f)), 0.1f * JPH_PI);
+
+		// Check that local bounding box is invalid
+		AABox bounds1 = mutable_compound->GetLocalBounds();
+		CHECK(!bounds1.IsValid());
+
+		// Check that get world space bounds returns an invalid bounding box
+		AABox bounds2 = mutable_compound->GetWorldSpaceBounds(Mat44::sRotationTranslation(rotation, Vec3(100, 200, 300)), Vec3(1, 2, 3));
+		CHECK(!bounds2.IsValid());
+
+		// Check that get world space bounds returns an invalid bounding box for double precision parameters
+		AABox bounds3 = mutable_compound->GetWorldSpaceBounds(DMat44::sRotationTranslation(rotation, DVec3(100, 200, 300)), Vec3(1, 2, 3));
+		CHECK(!bounds3.IsValid());
+	}
 }
 }