public static void CheckForInvalidUnusedEdges(NativeHull hull) { for (int j = 0; j < hull.EdgeCount; j++) { ValidateEdge(hull, j); } }
public static void ValidateFace(NativeHull hull, int faceIndex) { if (faceIndex < 0) { throw new ArgumentOutOfRangeException(nameof(faceIndex)); } NativeFace face = hull.GetFace(faceIndex); Debug.Assert(face.Edge >= 0, "All faces should point to a starting edge index"); Debug.Assert(face.Edge < hull.EdgeCount, "A face references an out of range edge index"); NativeHalfEdge startEdge = hull.GetEdge(face.Edge); NativeHalfEdge current = startEdge; int currentIndex = face.Edge; var edgeCount = 0; do { var next = hull.GetEdge(current.Next); Debug.Assert(faceIndex == current.Face, "All edges in a face loop should point to the same face"); Debug.Assert(currentIndex == next.Prev, "Next and previous edges in a face loop should point to each other"); ValidateEdge(hull, currentIndex); if (++edgeCount >= hull.EdgeCount) { Debug.Assert(true, "Infinite loop in face edges"); break; } currentIndex = current.Next; current = next; }while (current.Origin != startEdge.Origin); Debug.Assert(edgeCount > 1, "Faces should have more than one edge"); }
public static unsafe void CheckAllVerticesAreUsed(NativeHull hull) { for (int i = 0; i < hull.VertexCount; i++) { bool isUsed = false; for (int j = 0; j < hull.EdgeCount; j++) { NativeHalfEdge edge = hull.GetEdge(j); if (edge.Origin == i) { isUsed = true; break; } } Debug.Assert(isUsed, "All vertices should be used by an edge"); } }
public unsafe static void ValidateHull(NativeHull hull) { Debug.Assert(hull.IsCreated); Debug.Assert(!hull.IsDisposed); Debug.Assert((IntPtr)hull.Faces != IntPtr.Zero); Debug.Assert((IntPtr)hull.Vertices != IntPtr.Zero); Debug.Assert((IntPtr)hull.Planes != IntPtr.Zero); Debug.Assert((IntPtr)hull.Faces != IntPtr.Zero); Debug.Assert((IntPtr)hull.Edges != IntPtr.Zero); for (int i = 0; i < hull.FaceCount; i++) { ValidateFace(hull, i); } CheckAllVerticesAreUsed(hull); CheckForInvalidUnusedEdges(hull); }
public static void ValidateEdge(NativeHull hull, int edgeIndex) { if (edgeIndex < 0) { throw new ArgumentOutOfRangeException(nameof(edgeIndex)); } var edge = hull.GetEdge(edgeIndex); if (edge.Twin == -1 || edge.Prev == -1 || edge.Next == -1) { Debug.LogError($"Edge {edgeIndex} has an out of range index for twin, prev or next"); // Avoid exceptions so our debug visualizations can aid in debugging the issue. return; } var twin = hull.GetEdge(edge.Twin); Debug.Assert(edgeIndex == twin.Twin, "The twin of the edge twin must be the edge itself"); Debug.Assert(math.abs(edge.Twin - edgeIndex) == 1, "An edge/twin combination should be indexed one directly after the other."); Debug.Assert(edgeIndex == hull.GetEdge(edge.Prev).Next, "The previous edge should point to the next edge"); Debug.Assert(edgeIndex == hull.GetEdge(edge.Next).Prev, "The next edge should point to the previous edge"); Debug.Assert(edge.Origin != twin.Origin, "Edges and their twin should not point to the same vertex"); Debug.Assert(edge.Face >= 0, "All edges should have a face index"); Debug.Assert(edge.Face < hull.FaceCount, "An edge references an out of range face index"); }
public ref NativeHalfEdge GetFirstEdge(NativeHull hull) => ref hull.GetEdgeRef(Edge);
public void DrawHullCollision(GameObject a, GameObject b, RigidTransform t1, NativeHull hull1, RigidTransform t2, NativeHull hull2) { var collision = HullCollision.GetDebugCollisionInfo(t1, hull1, t2, hull2); if (collision.IsColliding) { if (DrawIntersection) // Visualize all faces of the intersection { HullIntersection.DrawNativeHullHullIntersection(t1, hull1, t2, hull2); } if (DrawContact || LogContact) // Visualize the minimal contact calcluation for physics { //var manifold = HullOperations.GetContact.Invoke(t1, hull1, t2, hull2); var sw1 = System.Diagnostics.Stopwatch.StartNew(); var tmp = new NativeManifold(Allocator.Persistent); var normalResult = HullIntersection.NativeHullHullContact(ref tmp, t1, hull1, t2, hull2); sw1.Stop(); tmp.Dispose(); var sw2 = System.Diagnostics.Stopwatch.StartNew(); var burstResult = HullOperations.TryGetContact.Invoke(out NativeManifold manifold, t1, hull1, t2, hull2); sw2.Stop(); if (LogContact) { Debug.Log($"GetContact between '{a.name}'/'{b.name}' took: {sw1.Elapsed.TotalMilliseconds:N4}ms (Normal), {sw2.Elapsed.TotalMilliseconds:N4}ms (Burst)"); } if (DrawContact && burstResult) { // Do something with manifold HullDrawingUtility.DebugDrawManifold(manifold); //var points = manifold.Points; for (int i = 0; i < manifold.Length; i++) { var point = manifold[i]; DebugDrawer.DrawSphere(point.Position, 0.02f); DebugDrawer.DrawArrow(point.Position, manifold.Normal * 0.2f); var penentrationPoint = point.Position + manifold.Normal * point.Distance; DebugDrawer.DrawLabel(penentrationPoint, $"{point.Distance:N2}"); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.InEdge1, t1, hull1); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.OutEdge1, t1, hull1); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.InEdge2, t1, hull1); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.OutEdge2, t1, hull1); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.InEdge1, t2, hull2); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.OutEdge1, t2, hull2); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.InEdge2, t2, hull2); HullDrawingUtility.DrawEdge(point.Id.FeaturePair.OutEdge2, t2, hull2); DebugDrawer.DrawDottedLine(point.Position, penentrationPoint); } manifold.Dispose(); } } if (DrawIsCollided) { DebugDrawer.DrawSphere(t1.pos, 0.1f, UnityColors.GhostDodgerBlue); DebugDrawer.DrawSphere(t2.pos, 0.1f, UnityColors.GhostDodgerBlue); } } if (DrawClosestFace) { var color1 = collision.Face1.Distance > 0 ? UnityColors.Red.ToOpacity(0.3f) : UnityColors.Yellow.ToOpacity(0.3f); HullDrawingUtility.DrawFaceWithOutline(collision.Face1.Index, t1, hull1, color1, UnityColors.Black); var color2 = collision.Face2.Distance > 0 ? UnityColors.Red.ToOpacity(0.3f) : UnityColors.Yellow.ToOpacity(0.3f); HullDrawingUtility.DrawFaceWithOutline(collision.Face2.Index, t2, hull2, color2, UnityColors.Black); } }