Exemplo n.º 1
0
        //TODO: Having a specialized triangle-triangle pair test would be nice.  Even if it didn't use an actual triangle-triangle test, certain assumptions could still make it speedier and more elegant.
        //"Closest points between triangles" + persistent manifolding would probably be the best approach (a lot faster than the triangle-convex general case anyway).
        public override bool GenerateContactCandidates(TriangleShape triangle,
                                                       out TinyStructList <ContactData> contactList)
        {
            if (base.GenerateContactCandidates(triangle, out contactList))
            {
                //The triangle-convex pair test has already rejected contacts whose normals would violate the first triangle's sidedness.
                //However, since it's a vanilla triangle-convex test, it doesn't know about the sidedness of the other triangle!
                TriangleShape shape = (TriangleShape)convex;
                Vector3       normal;
                //Lots of recalculating ab-bc!
                Vector3 ab, ac;
                Vector3.Subtract(ref shape.vB, ref shape.vA, out ab);
                Vector3.Subtract(ref shape.vC, ref shape.vA, out ac);
                Vector3.Cross(ref ab, ref ac, out normal);
                TriangleSidedness sidedness = shape.sidedness;
                if (sidedness != TriangleSidedness.DoubleSided)
                {
                    for (int i = contactList.Count - 1; i >= 0; i--)
                    {
                        ContactData item;
                        contactList.Get(i, out item);

                        float dot;
                        Vector3.Dot(ref item.Normal, ref normal, out dot);
                        if (sidedness == TriangleSidedness.Clockwise)
                        {
                            if (dot < 0)
                            {
                                contactList.RemoveAt(i);
                            }
                        }
                        else
                        {
                            if (dot > 0)
                            {
                                contactList.RemoveAt(i);
                            }
                        }
                    }
                }

                return(contactList.Count > 0);
            }

            return(false);
        }
Exemplo n.º 2
0
        //TODO: Having a specialized triangle-triangle pair test would be nice.  Even if it didn't use an actual triangle-triangle test, certain assumptions could still make it speedier and more elegant.
        //"Closest points between triangles" + persistent manifolding would probably be the best approach (a lot faster than the triangle-convex general case anyway).
        public override bool GenerateContactCandidate(out TinyStructList<ContactData> contactList)
        {
            if (base.GenerateContactCandidate(out contactList))
            {
                //The triangle-convex pair test has already rejected contacts whose normals would violate the first triangle's sidedness.
                //However, since it's a vanilla triangle-convex test, it doesn't know about the sidedness of the other triangle!
                var shape = ((TriangleShape)convex);
                Vector3 normal;
                //Lots of recalculating ab-bc!
                Vector3 ab, ac;
                Vector3.Subtract(ref shape.vB, ref shape.vA, out ab);
                Vector3.Subtract(ref shape.vC, ref shape.vA, out ac);
                Vector3.Cross(ref ab, ref ac, out normal);
                var sidedness = shape.sidedness;
                if (sidedness != TriangleSidedness.DoubleSided)
                {
                    for (int i = contactList.Count - 1; i >= 0; i--)
                    {
                        ContactData item;
                        contactList.Get(i, out item);

                        float dot;
                        Vector3.Dot(ref item.Normal, ref normal, out dot);
                        if (sidedness == TriangleSidedness.Clockwise)
                        {
                            if (dot < 0)
                            {
                                contactList.RemoveAt(i);
                            }
                        }
                        else
                        {
                            if (dot > 0)
                            {
                                contactList.RemoveAt(i);
                            }
                        }
                    }
                }
                return contactList.Count > 0;
            }
            return false;
        }
        public override void Update(float dt)
        {
            //Now, generate a contact between the two shapes.
            float   distance;
            Vector3 axis;
            var     manifold = new TinyStructList <BoxContactData>();

            if (BoxBoxCollider.AreBoxesColliding(boxA.Shape, boxB.Shape, ref boxA.worldTransform, ref boxB.worldTransform, out distance, out axis, out manifold))
            {
                Vector3.Negate(ref axis, out axis);
                TinyList <int> toRemove = new TinyList <int>();
                BoxContactData data;
                for (int i = 0; i < contacts.Count; i++)
                {
                    bool found = false;
                    for (int j = manifold.Count - 1; j >= 0; j--)
                    {
                        manifold.Get(j, out data);
                        if (contacts.Elements[i].Id == data.Id)
                        {
                            found = true;
                            //Update contact...
                            contacts.Elements[i].Position         = data.Position;
                            contacts.Elements[i].PenetrationDepth = -data.Depth;
                            contacts.Elements[i].Normal           = axis;
                            contacts.Elements[i].Validate();
                            //Remove manifold entry
                            manifold.RemoveAt(j);
                            break;
                        }
                    }
                    if (!found)
                    {//No match found
                        toRemove.Add(i);
                    }
                }

                ////Go through the indices to remove.
                ////For each one, replace the removal index with a contact in the new manifold.
                //int removalIndex;
                //for (removalIndex = toRemove.count - 1; removalIndex >= 0 && manifold.count > 0; removalIndex--)
                //{
                //    int indexToReplace = toRemove[removalIndex];
                //    toRemove.RemoveAt(removalIndex);
                //    manifold.Get(manifold.count - 1, out data);
                //    //Update contact...
                //    contacts.Elements[indexToReplace].Position = data.Position;
                //    contacts.Elements[indexToReplace].PenetrationDepth = -data.Depth;
                //    contacts.Elements[indexToReplace].Normal = axis;
                //    contacts.Elements[indexToReplace].Id = data.Id;
                //    //Remove manifold entry
                //    manifold.RemoveAt(manifold.count - 1);

                //}

                //Alright, we ran out of contacts to replace (if, in fact, toRemove isn't empty now).  Just remove the remainder.
                //toRemove is sorted by increasing index.  Go backwards along it so that the indices are valid all the way through.
                for (int i = toRemove.Count - 1; i >= 0; i--)
                {
                    Remove(toRemove[i]);
                }

                //Add new contacts.
                for (int i = 0; i < manifold.Count; i++)
                {
                    manifold.Get(i, out data);
                    ContactData newContact = new ContactData();
                    newContact.Position         = data.Position;
                    newContact.PenetrationDepth = -data.Depth;
                    newContact.Normal           = axis;
                    newContact.Id = data.Id;

                    Add(ref newContact);
                }
            }
            else
            {
                //Not colliding, so get rid of it.
                for (int i = contacts.Count - 1; i >= 0; i--)
                {
                    Remove(i);
                }
            }
        }
Exemplo n.º 4
0
        public override void Update(float dt)
        {

            //Now, generate a contact between the two shapes.
            float distance;
            Vector3 axis;
            var manifold = new TinyStructList<BoxContactData>();
            if (BoxBoxCollider.AreBoxesColliding(boxA.Shape, boxB.Shape, ref boxA.worldTransform, ref boxB.worldTransform, out distance, out axis, out manifold))
            {
                Vector3.Negate(ref axis, out axis);
                TinyList<int> toRemove = new TinyList<int>();
                BoxContactData data;
                for (int i = 0; i < contacts.count; i++)
                {
                    bool found = false;
                    for (int j = manifold.Count - 1; j >= 0; j--)
                    {
                        manifold.Get(j, out data);
                        if (contacts.Elements[i].Id == data.Id)
                        {
                            found = true;
                            //Update contact...
                            contacts.Elements[i].Position = data.Position;
                            contacts.Elements[i].PenetrationDepth = -data.Depth;
                            contacts.Elements[i].Normal = axis;
                            //Remove manifold entry
                            manifold.RemoveAt(j);
                            break;
                        }
                    }
                    if (!found)
                    {//No match found
                        toRemove.Add(i);
                    }
                }

                ////Go through the indices to remove.
                ////For each one, replace the removal index with a contact in the new manifold.
                //int removalIndex;
                //for (removalIndex = toRemove.count - 1; removalIndex >= 0 && manifold.count > 0; removalIndex--)
                //{
                //    int indexToReplace = toRemove[removalIndex];
                //    toRemove.RemoveAt(removalIndex);
                //    manifold.Get(manifold.count - 1, out data);
                //    //Update contact...
                //    contacts.Elements[indexToReplace].Position = data.Position;
                //    contacts.Elements[indexToReplace].PenetrationDepth = -data.Depth;
                //    contacts.Elements[indexToReplace].Normal = axis;
                //    contacts.Elements[indexToReplace].Id = data.Id;
                //    //Remove manifold entry
                //    manifold.RemoveAt(manifold.count - 1);

                //}

                //Alright, we ran out of contacts to replace (if, in fact, toRemove isn't empty now).  Just remove the remainder.
                //toRemove is sorted by increasing index.  Go backwards along it so that the indices are valid all the way through.
                for (int i = toRemove.Count - 1; i >= 0; i--)
                    Remove(toRemove[i]);

                //Add new contacts.
                for (int i = 0; i < manifold.Count; i++)
                {
                    manifold.Get(i, out data);
                    ContactData newContact = new ContactData();
                    newContact.Position = data.Position;
                    newContact.PenetrationDepth = -data.Depth;
                    newContact.Normal = axis;
                    newContact.Id = data.Id;

                    Add(ref newContact);
                }
            }
            else
            {
                //Not colliding, so get rid of it.
                for (int i = contacts.count - 1; i >= 0; i--)
                {
                    Remove(i);
                }
            }
        }