private bool DoExternalSeparated(TriangleShape triangle, out TinyStructList <ContactData> contactList) { if (GJKToolbox.AreShapesIntersecting(convex, triangle, ref Toolbox.RigidIdentity, ref Toolbox.RigidIdentity, ref localSeparatingAxis)) { state = CollisionState.ExternalNear; return(DoExternalNear(triangle, out contactList)); } TryToEscape(); contactList = new TinyStructList <ContactData>(); return(false); }
///<summary> /// Generates a contact between the objects, if possible. ///</summary> ///<param name="contact">Contact created between the pair, if possible.</param> ///<returns>Whether or not the objects were colliding.</returns> public bool GenerateContactCandidate(out ContactData contact) { //Generate contacts. This will just find one closest point using general supportmapping based systems like MPR and GJK. //The collision system moves through a state machine depending on the latest collision generation result. //At first, assume that the pair is completely separating. This is almost always the correct guess for new pairs. //An extremely fast, warm-startable boolean GJK test can be performed. If it returns with nonintersection, we can quit and do nothing. //If the initial boolean GJK test finds intersection, move onto a shallow contact test. //The shallow contact test is a different kind of GJK test that finds the closest points between the shape pair. It's not as speedy as the boolean version. //The algorithm is run between the marginless versions of the shapes, so that the closest points will form a contact somewhere in the space separating the cores. //If the closest point system finds no intersection and returns the closest points, the state is changed to ShallowContact. //If the closest point system finds intersection of the core shapes, then the state is changed to DeepContact, and MPR is run to determine contact information. //The system tries to escape from deep contact to shallow contact, and from shallow contact to separated whenever possible. //Here's the state flow: //On Separated: BooleanGJK // -Intersecting -> Go to ShallowContact. // -Nonintersecting -> Do nothing. //On ShallowContact: ClosestPointsGJK // -Intersecting -> Go to DeepContact. // -Nonintersecting: Go to Separated (without test) if squared distance > margin squared, otherwise use closest points to make contact. //On DeepContact: MPR // -Intersecting -> Go to ShallowContact if penetration depth < margin // -Nonintersecting -> This case is rare, but not impossible. Go to Separated (without test). previousState = state; switch (state) { case CollisionState.Separated: if (GJKToolbox.AreShapesIntersecting(collidableA.Shape, collidableB.Shape, ref collidableA.worldTransform, ref collidableB.worldTransform, ref localSeparatingAxis)) { state = CollisionState.ShallowContact; return(DoShallowContact(out contact)); } contact = new ContactData(); return(false); case CollisionState.ShallowContact: return(DoShallowContact(out contact)); case CollisionState.DeepContact: return(DoDeepContact(out contact)); } contact = new ContactData(); return(false); }
/// <summary> /// Constructs a new demo. /// </summary> /// <param name="game">Game owning this demo.</param> public BooleanConvexTestDemo(DemosGame game) : base(game) { var random = new Random(); int numberOfConfigurations = 1000; int numberOfTestsPerConfiguration = 10000; float size = 2; var aPositionBounds = new BoundingBox(new Vector3(-size, -size, -size), new Vector3(size, size, size)); var bPositionBounds = new BoundingBox(new Vector3(-size, -size, -size), new Vector3(size, size, size)); size = 1; var aShapeBounds = new BoundingBox(new Vector3(-size, -size, -size), new Vector3(size, size, size)); var bShapeBounds = new BoundingBox(new Vector3(-size, -size, -size), new Vector3(size, size, size)); int pointsInA = 10; int pointsInB = 10; RawList <Vector3> points = new RawList <Vector3>(); long accumulatedMPR = 0; long accumulatedGJK = 0; long accumulatedGJKSeparatingAxis = 0; for (int i = 0; i < numberOfConfigurations; i++) { //Create two convex hull shapes. for (int j = 0; j < pointsInA; j++) { Vector3 point; GetRandomPointInBoundingBox(random, ref aShapeBounds, out point); points.Add(point); } var a = new ConvexHullShape(points); points.Clear(); for (int j = 0; j < pointsInB; j++) { Vector3 point; GetRandomPointInBoundingBox(random, ref bShapeBounds, out point); points.Add(point); } var b = new ConvexHullShape(points); points.Clear(); //Generate some random tranforms for the shapes. RigidTransform aTransform; var axis = Vector3.Normalize(new Vector3((float)((random.NextDouble() - .5f) * 2), (float)((random.NextDouble() - .5f) * 2), (float)((random.NextDouble() - .5f) * 2))); var angle = (float)random.NextDouble() * MathHelper.TwoPi; Quaternion.CreateFromAxisAngle(ref axis, angle, out aTransform.Orientation); GetRandomPointInBoundingBox(random, ref aPositionBounds, out aTransform.Position); RigidTransform bTransform; axis = Vector3.Normalize(new Vector3((float)((random.NextDouble() - .5f) * 2), (float)((random.NextDouble() - .5f) * 2), (float)((random.NextDouble() - .5f) * 2))); angle = (float)random.NextDouble() * MathHelper.TwoPi; Quaternion.CreateFromAxisAngle(ref axis, angle, out bTransform.Orientation); GetRandomPointInBoundingBox(random, ref bPositionBounds, out bTransform.Position); //Perform MPR tests. //Warm up the cache a bit. MPRToolbox.AreShapesOverlapping(a, b, ref aTransform, ref bTransform); long start = Stopwatch.GetTimestamp(); for (int j = 0; j < numberOfTestsPerConfiguration; j++) { if (MPRToolbox.AreShapesOverlapping(a, b, ref aTransform, ref bTransform)) { overlapsMPR++; } } long end = Stopwatch.GetTimestamp(); accumulatedMPR += end - start; //Perform GJK tests. //Warm up the cache a bit. GJKToolbox.AreShapesIntersecting(a, b, ref aTransform, ref bTransform); start = Stopwatch.GetTimestamp(); for (int j = 0; j < numberOfTestsPerConfiguration; j++) { if (GJKToolbox.AreShapesIntersecting(a, b, ref aTransform, ref bTransform)) { overlapsGJK++; } } end = Stopwatch.GetTimestamp(); accumulatedGJK += end - start; //Perform GJK Separating Axis tests. //Warm up the cache a bit. Vector3 localSeparatingAxis = Vector3.Up; GJKToolbox.AreShapesIntersecting(a, b, ref aTransform, ref bTransform, ref localSeparatingAxis); start = Stopwatch.GetTimestamp(); for (int j = 0; j < numberOfTestsPerConfiguration; j++) { if (GJKToolbox.AreShapesIntersecting(a, b, ref aTransform, ref bTransform, ref localSeparatingAxis)) { overlapsGJKSeparatingAxis++; } } end = Stopwatch.GetTimestamp(); accumulatedGJKSeparatingAxis += end - start; } //Compute the actual time per test. long denominator = Stopwatch.Frequency * numberOfConfigurations * numberOfTestsPerConfiguration; timeMPR = (double)accumulatedMPR / denominator; timeGJK = (double)accumulatedGJK / denominator; timeGJKSeparatingAxis = (double)accumulatedGJKSeparatingAxis / denominator; }