Exemplo n.º 1
0
        /// <summary>
        /// Reduces the number of contacts in the contact set to 1 contact.
        /// </summary>
        /// <param name="contactSet">The contact set.</param>
        /// <remarks>
        /// The contact with the biggest penetration depth is kept.
        /// </remarks>
        internal static void ReduceClosestPoints(ContactSet contactSet)
        {
            // Reduce to 1 contact.
            int numberOfContacts = contactSet.Count;

            if (numberOfContacts > 1)
            {
                // Keep the contact with the deepest penetration depth.
                Contact bestContact = contactSet[0];
                for (int i = 1; i < numberOfContacts; i++)
                {
                    if (contactSet[i].PenetrationDepth > bestContact.PenetrationDepth)
                    {
                        bestContact = contactSet[i];
                    }
                }

                // Throw away other contacts.
                foreach (var contact in contactSet)
                {
                    if (contact != bestContact)
                    {
                        contact.Recycle();
                    }
                }

                contactSet.Clear();
                contactSet.Add(bestContact);
            }

            Debug.Assert(contactSet.Count == 0 || contactSet.Count == 1);

            // If we HaveContact but the contact shows a separation, delete contact.
            // This can happen for TriangleMesh vs. TriangleMesh because the triangle mesh algorithm
            // filters contacts if they have a bad normal. It can happen that all contacts are filtered
            // and only a separated contact remains in the contact set.
            if (contactSet.HaveContact && contactSet.Count > 0 && contactSet[0].PenetrationDepth < 0)
            {
                contactSet[0].Recycle();
                contactSet.Clear();
            }
        }
Exemplo n.º 2
0
        public static void Merge(ContactSet target, ContactSet newContacts, CollisionQueryType type, float contactPositionTolerance)
        {
            Debug.Assert(target != null);
            Debug.Assert(newContacts != null);
            Debug.Assert(contactPositionTolerance >= 0, "The contact position tolerance must be greater than or equal to 0");

            int numberOfNewContacts = newContacts.Count;

            for (int i = 0; i < numberOfNewContacts; i++)
            {
                Merge(target, newContacts[i], type, contactPositionTolerance);
            }

            newContacts.Clear();
        }
Exemplo n.º 3
0
        /// <summary>
        /// Updates the contact information in the given contact set.
        /// </summary>
        /// <param name="contactSet">The contact set containing the last known contacts.</param>
        /// <param name="deltaTime">
        /// The time step size in seconds. (The elapsed simulation time since
        /// <see cref="UpdateClosestPoints"/> or <see cref="UpdateContacts"/> was last called for this
        /// contact set.)
        /// </param>
        /// <remarks>
        /// If two objects move, the contact information will usually change and has to be updated.
        /// Using the contact set containing the last known contacts, this method can compute the new
        /// contacts faster than <see cref="GetContacts"/> if the poses of the objects haven't changed
        /// drastically.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="contactSet"/> is <see langword="null"/>.
        /// </exception>
        public void UpdateContacts(ContactSet contactSet, float deltaTime)
        {
            if (contactSet == null)
            {
                throw new ArgumentNullException("contactSet");
            }

            // Broad phase AABB check and collision filtering
            if (HaveAabbContact(contactSet.ObjectA, contactSet.ObjectB))
            {
                // Narrow phase
                AlgorithmMatrix[contactSet].UpdateContacts(contactSet, deltaTime);
            }
            else
            {
                foreach (var contact in contactSet)
                {
                    contact.Recycle();
                }

                contactSet.Clear();
                contactSet.HaveContact = false;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Reduces the number of contacts in the contact set to 1 contact.
        /// </summary>
        /// <param name="contactSet">
        /// The contact set. One shape in the contact set must be a <see cref="RayShape"/>!
        /// </param>
        /// <remarks>
        /// The best ray hit is kept.
        /// </remarks>
        internal static void ReduceRayHits(ContactSet contactSet)
        {
            Debug.Assert(
                contactSet.ObjectA.GeometricObject.Shape is RayShape ||
                contactSet.ObjectB.GeometricObject.Shape is RayShape,
                "ReduceRayHits was called for a contact set without a ray.");

            // For separated contacts keep the contact with the smallest separation.
            // If we have contact, keep the contact with the SMALLEST penetration (= shortest ray length)
            // and remove all invalid contacts (with separation).
            bool    haveContact          = contactSet.HaveContact;
            float   bestPenetrationDepth = haveContact ? float.PositiveInfinity : float.NegativeInfinity;
            Contact bestContact          = null;
            int     numberOfContacts     = contactSet.Count;

            for (int i = 0; i < numberOfContacts; i++)
            {
                Contact contact          = contactSet[i];
                float   penetrationDepth = contact.PenetrationDepth;

                if (haveContact)
                {
                    // Search for positive and smallest penetration depth.
                    if (penetrationDepth >= 0 && penetrationDepth < bestPenetrationDepth)
                    {
                        bestContact          = contact;
                        bestPenetrationDepth = penetrationDepth;
                    }
                }
                else
                {
                    // Search for negative and largest penetration depth (Separation!)
                    Debug.Assert(penetrationDepth < 0, "HaveContact is false, but contact shows penetration.");
                    if (penetrationDepth > bestPenetrationDepth)
                    {
                        bestContact          = contact;
                        bestPenetrationDepth = penetrationDepth;
                    }
                }
            }

            // Keep best contact.
            // Note: In some situations HaveContact is true, but the contact set does not contains any
            // contacts with penetration. This happen, for example, when testing a ray inside a triangle
            // mesh. The TriangleMeshAlgorithm automatically filters contacts with bad normals.
            // When HaveContact is false, we should always have a contact (closest point).

            // Throw away other contacts.
            foreach (var contact in contactSet)
            {
                if (contact != bestContact)
                {
                    contact.Recycle();
                }
            }

            contactSet.Clear();
            if (bestContact != null)
            {
                contactSet.Add(bestContact);
            }
        }