Browse Source

Fixed cast shape possibly not returning a hit (#1787)

when a shape cast starts touching (but not intersecting) another shape and requesting the deepest hit.

Fixes #1786
Jorrit Rouwe 2 months ago
parent
commit
28072c1bda
3 changed files with 56 additions and 1 deletions
  1. 1 0
      Docs/ReleaseNotes.md
  2. 1 1
      Jolt/Geometry/EPAPenetrationDepth.h
  3. 54 0
      UnitTests/Physics/CastShapeTests.cpp

+ 1 - 0
Docs/ReleaseNotes.md

@@ -14,6 +14,7 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
 * A 6DOF constraint that constrains all rotation axis in combination with a body that has some of its rotation axis locked would not constrain the rotation in the unlocked axis.
 * Added include `type_traits` for `std::is_trivial` to avoid compile error on macOS with clang 21.
 * Fixed compilation error when using Jolt in conjunction with the `_CRTDBG_MAP_ALLOC` define on Windows.
+* Fixed cast shape possibly not returning a hit when a shape cast starts touching (but not intersecting) another shape and requesting the deepest hit.
 
 ## v5.4.0
 

+ 1 - 1
Jolt/Geometry/EPAPenetrationDepth.h

@@ -542,7 +542,7 @@ public:
 			AddConvexRadius add_convex_b(inB, inConvexRadiusB);
 			TransformedConvexObject transformed_a(inStart, add_convex_a);
 			if (!GetPenetrationDepthStepEPA(transformed_a, add_convex_b, inPenetrationTolerance, outContactNormal, outPointA, outPointB))
-				return false;
+				outContactNormal = inDirection; // Failed to get the deepest point, use points returned by GJK and use cast direction as normal
 		}
 		else if (contact_normal_invalid)
 		{

+ 54 - 0
UnitTests/Physics/CastShapeTests.cpp

@@ -13,6 +13,7 @@
 #include <Jolt/Physics/Collision/Shape/MeshShape.h>
 #include <Jolt/Physics/Collision/Shape/ScaledShape.h>
 #include <Jolt/Physics/Collision/Shape/BoxShape.h>
+#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
 #include <Jolt/Physics/Collision/ShapeFilter.h>
 #include <Jolt/Physics/Collision/CollisionDispatch.h>
 #include <Jolt/Physics/Collision/CastSphereVsTriangles.h>
@@ -457,4 +458,57 @@ TEST_SUITE("CastShapeTests")
 			CHECK_APPROX_EQUAL(closest_collector.mHits[1].mContactPointOn1, Vec3(0.5f, 0, 0));
 		}
 	}
+
+	// Test 2D shape cast against a box
+	TEST_CASE("TestCast2DBoxVsBox")
+	{
+		RefConst<Shape> box_shape;
+		{
+			float size = 5.0f;
+			float thickness = 1.0f;
+			Array<Vec3> points = {
+				Vec3(-size, -size, thickness),
+				Vec3(size, -size, thickness),
+				Vec3(size, size, thickness),
+				Vec3(-size, size, thickness),
+				Vec3(-size, -size, -thickness),
+				Vec3(size, -size, -thickness),
+				Vec3(size, size, -thickness),
+				Vec3(-size, size, -thickness),
+			};
+			ConvexHullShapeSettings box_shape_settings(points);
+			box_shape_settings.SetEmbedded();
+			box_shape_settings.mMaxConvexRadius = 0.0f;
+			box_shape = box_shape_settings.Create().Get();
+		}
+
+		RefConst<Shape> cast_shape;
+		{
+			float size = 1.0f;
+			Array<Vec3> points = {
+				Vec3(-size, -size, 0),
+				Vec3(size, -size, 0),
+				Vec3(size, size, 0),
+				Vec3(-size, size, 0),
+			};
+			ConvexHullShapeSettings cast_shape_settings(points);
+			cast_shape_settings.SetEmbedded();
+			cast_shape_settings.mMaxConvexRadius = 0.0f;
+			cast_shape = cast_shape_settings.Create().Get();
+		}
+
+		// The 2d box cast touches the surface of the box at the start and moves into it
+		ShapeCastSettings settings;
+		settings.mReturnDeepestPoint = true;
+		ShapeCast shape_cast(cast_shape, Vec3::sOne(), Mat44::sTranslation(Vec3(0, 0, 1)), Vec3(0, 0, -10));
+		ClosestHitCollisionCollector<CastShapeCollector> cast_shape_collector;
+		CollisionDispatch::sCastShapeVsShapeLocalSpace(shape_cast, settings, box_shape, Vec3::sOne(), ShapeFilter(), Mat44::sIdentity(), SubShapeIDCreator(), SubShapeIDCreator(), cast_shape_collector);
+
+		CHECK(cast_shape_collector.HadHit());
+		CHECK(cast_shape_collector.mHit.mFraction == 0.0f);
+		CHECK_APPROX_EQUAL(cast_shape_collector.mHit.mPenetrationAxis.Normalized(), Vec3(0, 0, -1));
+		CHECK_APPROX_EQUAL(cast_shape_collector.mHit.mPenetrationDepth, 0.0f);
+		CHECK_APPROX_EQUAL(cast_shape_collector.mHit.mContactPointOn1, Vec3(0, 0, 1), 1.0e-4f);
+		CHECK_APPROX_EQUAL(cast_shape_collector.mHit.mContactPointOn2, Vec3(0, 0, 1), 1.0e-4f);
+	}
 }