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);
 }
Esempio n. 2
0
        ///<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;
        }