Issues with sliding objects

Discuss any questions about BEPUphysics or problems encountered.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Issues with sliding objects

Post by Norbo »

What kind of weird collision? It may help to draw the contacts themselves. That would show how they are oriented and provide a way to distinguish between various causes.

The default margin should be fine. Decreasing it will almost certainly harm quality, though you could try increasing it a bit. That could help with some types of issues, but not others.
BabaJustin
Posts: 30
Joined: Mon Apr 25, 2011 6:07 pm

Re: Issues with sliding objects

Post by BabaJustin »

It can sometimes look like a sudden shift in direction while the object is sliding. Previously with the un-shared vertices the object would catch on it's front edge and flip up. It does not appear to be doing that anymore, it's now much more subtle.

Contacts? Where do I access those?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Issues with sliding objects

Post by Norbo »

Here's a part of the contact drawing segment in the DemosGame:

Code: Select all

                foreach (INarrowPhasePair pair in currentSimulation.Space.NarrowPhase.Pairs)
                {
                    var pairHandler = pair as CollidablePairHandler;
                    if (pairHandler != null)
                    {
                        foreach (ContactInformation information in pairHandler.Contacts)
                        {
                            contactCount++;
                            collisionNormalList.Add(new VertexPositionColor(information.Contact.Position, Color.White));
                            collisionNormalList.Add(new VertexPositionColor(information.Contact.Position + information.Contact.Normal * information.Contact.PenetrationDepth, Color.Red));
                            collisionNormalList.Add(new VertexPositionColor(information.Contact.Position + information.Contact.Normal * information.Contact.PenetrationDepth, Color.White));
                            collisionNormalList.Add(new VertexPositionColor(information.Contact.Position + information.Contact.Normal * (information.Contact.PenetrationDepth + .3f), Color.White));
                        }
                    }
                }
Basically, it looks at all pairs in the space which can have contacts and adds those contacts to a list.
It can sometimes look like a sudden shift in direction while the object is sliding. Previously with the un-shared vertices the object would catch on it's front edge and flip up. It does not appear to be doing that anymore, it's now much more subtle.
Sounds like a diagonal triangle border is being hit, but not entering deep contact. That, combined with some other circumstances, could allow an odd normal to be created. The process I'm thinking of would be pretty rare though. I'll see if I can reproduce something tomorrow.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Issues with sliding objects

Post by Norbo »

The development version now includes a couple of changes (http://bepuphysics.codeplex.com/SourceC ... evelopment). It's doubtful that they will fix the problem you are encountering, but they do address rare related issues.

After that fix, in ~0.05% of tested boundary crossings, a specific configuration of triangle-convex pairs would pop up in such a way that stopped the boundary behavior improver from correcting/ignoring a contact. The result is a bump/jump/deflection. Unfortunately, the current system does not have collect sufficient information to deal with these cases intelligently, and my current ideas for resolving it would have a little too much overhead in the worst case (or are dumbfire hacks with bad side effects).

I'm not absolutely sure that this problem is responsible for what you're seeing, but it seems likely.

Assuming that it is the cause, then you've got a few options.
-The more curved the impact surface is, the less chance that a bad normal will be *really* bad. Decreasing the radius/height of the cylinder and increasing the collision margin to make up for it could resolve much of the issue.
-Change the mesh surface to minimize the boundary crossings. Using two triangles for the whole surface may end up being acceptable given its smaller size.
-Change the main sliding surface to be a box instead of a mesh. Due to the shrink, it may work better. It must be only one box, though, so numerical issues from the excessive size are possible.
-Modify the TriangleMeshConvexContactManifold to always correct the normal. In its Update method, there's a section that looks like this:

Code: Select all

            if (UseImprovedBoundaryHandling)
            {
                for (int i = 0; i < edgeContacts.count; i++)
                {
                    //Only correct if it's allowed AND it's blocked.
                    //If it's not blocked, the contact being created is necessary!
                    //The normal generated by the triangle-convex tester is already known not to
                    //violate the triangle sidedness.
                    if (!blockedEdgeRegions.Contains(edgeContacts.Elements[i].Edge))
                    {
                        //If it's not blocked, use the contact as-is without correcting it.
                        AddLocalContact(ref edgeContacts.Elements[i].ContactData, ref orientation);
                    }
                    else if (edgeContacts.Elements[i].ShouldCorrect)
                    {
                        //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                        //it will not interfere (and cause a bump or something).
                        float dot;
                        edgeContacts.Elements[i].CorrectedNormal.Normalize();
                        Vector3.Dot(ref edgeContacts.Elements[i].CorrectedNormal, ref edgeContacts.Elements[i].ContactData.Normal, out dot);
                        edgeContacts.Elements[i].ContactData.Normal = edgeContacts.Elements[i].CorrectedNormal;
                        edgeContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                        AddLocalContact(ref edgeContacts.Elements[i].ContactData, ref orientation);

                    }
                    //If it's blocked AND it doesn't allow correction, ignore its existence.
                }
                for (int i = 0; i < vertexContacts.count; i++)
                {
                    if (!blockedVertexRegions.Contains(vertexContacts.Elements[i].Vertex))
                    {
                        //If it's not blocked, use the contact as-is without correcting it.
                        AddLocalContact(ref vertexContacts.Elements[i].ContactData, ref orientation);
                    }
                    else if (vertexContacts.Elements[i].ShouldCorrect)
                    {
                        //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                        //it will not interfere (and cause a bump or something).
                        float dot;
                        vertexContacts.Elements[i].CorrectedNormal.Normalize();
                        Vector3.Dot(ref vertexContacts.Elements[i].CorrectedNormal, ref vertexContacts.Elements[i].ContactData.Normal, out dot);
                        vertexContacts.Elements[i].ContactData.Normal = vertexContacts.Elements[i].CorrectedNormal;
                        vertexContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                        AddLocalContact(ref vertexContacts.Elements[i].ContactData, ref orientation);
                    }
                    //If it's blocked AND it doesn't allow correction, ignore its existence.
                }
                blockedEdgeRegions.Clear();
                blockedVertexRegions.Clear();
                vertexContacts.Clear();
                edgeContacts.Clear();
            }
Change it to this:

Code: Select all

            if (UseImprovedBoundaryHandling)
            {
                for (int i = 0; i < edgeContacts.count; i++)
                {

                    //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                    //it will not interfere (and cause a bump or something).
                    float dot;
                    edgeContacts.Elements[i].CorrectedNormal.Normalize();
                    Vector3.Dot(ref edgeContacts.Elements[i].CorrectedNormal, ref edgeContacts.Elements[i].ContactData.Normal, out dot);
                    edgeContacts.Elements[i].ContactData.Normal = edgeContacts.Elements[i].CorrectedNormal;
                    edgeContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                    AddLocalContact(ref edgeContacts.Elements[i].ContactData, ref orientation);

                }
                for (int i = 0; i < vertexContacts.count; i++)
                {
                    //If it is blocked, we can still make use of the contact.  But first, we need to change the contact normal to ensure that
                    //it will not interfere (and cause a bump or something).
                    float dot;
                    vertexContacts.Elements[i].CorrectedNormal.Normalize();
                    Vector3.Dot(ref vertexContacts.Elements[i].CorrectedNormal, ref vertexContacts.Elements[i].ContactData.Normal, out dot);
                    vertexContacts.Elements[i].ContactData.Normal = vertexContacts.Elements[i].CorrectedNormal;
                    vertexContacts.Elements[i].ContactData.PenetrationDepth *= MathHelper.Max(0, dot); //Never cause a negative penetration depth.
                    AddLocalContact(ref vertexContacts.Elements[i].ContactData, ref orientation);
                }
                blockedEdgeRegions.Clear();
                blockedVertexRegions.Clear();
                vertexContacts.Clear();
                edgeContacts.Clear();
            }
Additionally, in TriangleConvexPairTester, change the ShouldCorrectContactNormal property to always return true:

Code: Select all

        public override bool ShouldCorrectContactNormal
        {
            get
            {
                return true;// state == CollisionState.Deep;
            }
        }
It will now always correct the contact normals. This will cause occasional oddities when objects collide on triangle edges, but the surface will be perfectly smooth.

I'll try to improve the system such that this isn't an issue in the future, but there are some higher priorities for now.
Post Reply