Browse Source

Fixed bug in MustIncludeC logic in GetClosestPointOnTriangle (#749)

If A and C are swapped to get a better normal, then skipping skipping edge AB is incorrect as it is actually edge BC
Felix Büttner 1 year ago
parent
commit
ce6c1354e9
2 changed files with 24 additions and 18 deletions
  1. 1 1
      .github/workflows/determinism_check.yml
  2. 23 17
      Jolt/Geometry/ClosestPoint.h

+ 1 - 1
.github/workflows/determinism_check.yml

@@ -2,7 +2,7 @@ name: Determinism Check
 
 
 env:
 env:
     CONVEX_VS_MESH_HASH: '0x10139effe747511'
     CONVEX_VS_MESH_HASH: '0x10139effe747511'
-    RAGDOLL_HASH: '0xeb0afdf14f49c318'
+    RAGDOLL_HASH: '0xcdcbb4da185d1a13'
 
 
 on:
 on:
   push:
   push:

+ 23 - 17
Jolt/Geometry/ClosestPoint.h

@@ -184,6 +184,7 @@ namespace ClosestPoint
 			float best_dist_sq = inC.LengthSq();
 			float best_dist_sq = inC.LengthSq();
 
 
 			// If the closest point must include C then A or B cannot be closest
 			// If the closest point must include C then A or B cannot be closest
+			// Note that we test vertices first because we want to prefer a closest vertex over a closest edge (this results in an outSet with fewer bits set)
 			if constexpr (!MustIncludeC)
 			if constexpr (!MustIncludeC)
 			{
 			{
 				// Try vertex A
 				// Try vertex A
@@ -203,21 +204,6 @@ namespace ClosestPoint
 					closest_point = inB;
 					closest_point = inB;
 					best_dist_sq = b_len_sq;
 					best_dist_sq = b_len_sq;
 				}
 				}
-
-				// Edge AB
-				float ab_len_sq = ab.LengthSq();
-				if (ab_len_sq > Square(FLT_EPSILON))
-				{
-					float v = Clamp(-a.Dot(ab) / ab_len_sq, 0.0f, 1.0f);
-					Vec3 q = a + v * ab;
-					float dist_sq = q.LengthSq();
-					if (dist_sq < best_dist_sq)
-					{
-						closest_set = swap_ac.GetX()? 0b0110 : 0b0011;
-						closest_point = q;
-						best_dist_sq = dist_sq;
-					}
-				}
 			}
 			}
 
 
 			// Edge AC
 			// Edge AC
@@ -236,7 +222,7 @@ namespace ClosestPoint
 			}
 			}
 
 
 			// Edge BC
 			// Edge BC
-			Vec3 bc = c - inB;
+			Vec3 bc = inC - inB;
 			float bc_len_sq = bc.LengthSq();
 			float bc_len_sq = bc.LengthSq();
 			if (bc_len_sq > Square(FLT_EPSILON))
 			if (bc_len_sq > Square(FLT_EPSILON))
 			{
 			{
@@ -245,12 +231,32 @@ namespace ClosestPoint
 				float dist_sq = q.LengthSq();
 				float dist_sq = q.LengthSq();
 				if (dist_sq < best_dist_sq)
 				if (dist_sq < best_dist_sq)
 				{
 				{
-					closest_set = swap_ac.GetX()? 0b0011 : 0b0110;
+					closest_set = 0b0110;
 					closest_point = q;
 					closest_point = q;
 					best_dist_sq = dist_sq;
 					best_dist_sq = dist_sq;
 				}
 				}
 			}
 			}
 
 
+			// If the closest point must include C then AB cannot be closest
+			if constexpr (!MustIncludeC)
+			{
+				// Edge AB
+				ab = inB - inA;
+				float ab_len_sq = ab.LengthSq();
+				if (ab_len_sq > Square(FLT_EPSILON))
+				{
+					float v = Clamp(-inA.Dot(ab) / ab_len_sq, 0.0f, 1.0f);
+					Vec3 q = inA + v * ab;
+					float dist_sq = q.LengthSq();
+					if (dist_sq < best_dist_sq)
+					{
+						closest_set = 0b0011;
+						closest_point = q;
+						best_dist_sq = dist_sq;
+					}
+				}
+			}
+
 			outSet = closest_set;
 			outSet = closest_set;
 			return closest_point;
 			return closest_point;
 		}
 		}