Objects Penetrating GImpact meshes

Bbilz
Posts: 26
Joined: Wed Feb 27, 2008 9:55 am

Objects Penetrating GImpact meshes

Post by Bbilz »

I have been following this topic:
"Bumpy triangle meshes"
http://www.bulletphysics.com/Bullet/php ... f=9&t=3052

I see GImpact being mentioned, in what I think may be a seperate issue.
I have been finding that fast moving objects can penetrate inside my GImpact meshes, even with the CCD correction turned on.

I have enclosed modifications to the MovingConcaveDemo to place a large version of the GImpact bunny in the middle of the scene, and enable you to fire boxes at it when you press '.'
With the CCD disabled the boxes pass straight through the bunny. With the CCD enabled the most common result is the boxes end up trapped inside the bunny.

My best guess at the moment is that the sweep test within the CCD motion clamping is somehow returning a result that incorrectly puts the box inside the mesh. The above mentioned topic has a fix for incorrect trimesh normals which may or may not be relevant, and I plan to try implementing it to see if it has an affect.
I mainly just saw people talking about objects passing through GImpact meshes, and wanted to provide a reproducable for your enjoyment!

Cheers
You do not have the required permissions to view the files attached to this post.
Bbilz
Posts: 26
Joined: Wed Feb 27, 2008 9:55 am

Re: Objects Penetrating GImpact meshes

Post by Bbilz »

As a follow up, I tried adding in the trimesh normal correction code suggested by Alex Silverman:
AlexSilverman wrote:Sure thing. What follows is my ContactAddedCallback implementation for combating edge collisions in triangle meshes. I never did get around to profiling the results of adding in a check to determine if the contact normal is already the triangle normal, so that might be worthwhile. In any event, here it is. I noticed this problem during development of a minigolf game, and this took care of it. That said, this was in Bullet 2.70, and hasn't been tested in anything more current.

- Alex

Code: Select all

//////////////////////////////////////////////////////////////
// NotifyOnCollision
// Let an object know it's been collided
//////////////////////////////////////////////////////////////
bool NotifyOnCollision(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0, int index0, const btCollisionObject* colObj1, int partId1, int index1)
{
    (void)partId0;
    (void)index0;
    (void)partId1;
    (void)index1;

    // Correct the normal
    if (colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
    {
        btTriangleShape * s0 = ((btTriangleShape*)colObj0->getCollisionShape());
        cp.m_normalWorldOnB = (s0->m_vertices1[1] - s0->m_vertices1[0]).cross(s0->m_vertices1[2] - s0->m_vertices1[0]);
        cp.m_normalWorldOnB.normalize();
    }
    else if (colObj1->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
    {
        btTriangleShape * s1 = ((btTriangleShape*)colObj1->getCollisionShape());
        cp.m_normalWorldOnB = (s1->m_vertices1[1] - s1->m_vertices1[0]).cross(s1->m_vertices1[2] - s1->m_vertices1[0]);
        cp.m_normalWorldOnB.normalize();
    }
    //this return value is currently ignored, but to be on the safe side: return false if you don't calculate friction
    return true;
}
I had to reverse the cross products, but it did stop the boxes passing inside the bunny..
Still not really sure what is going on here, but hopefully this information is of some use.
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Objects Penetrating GImpact meshes

Post by sparkprime »

The CCD clamping does not work very well with boxes, they seem to be deflected but not enough to stop tunnelling. This has nothing to do with gimpact. CCD clamping seems to work very well with spheres.

The triangle meshes are bumpy and the "normal correction" does not work regardless of whether you're using gimpact or not.

Personally I would like my gimpact meshes to be one-way so if something does penetrate it will not rattle around inside. I think this would also help when gimpact meshes are jammed together or into world geometry.
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Objects Penetrating GImpact meshes

Post by sparkprime »

I tried making gimpact triangle meshes one-way by manipulating the normal in a "contact added" callback similar to the above, but massaged into my other stuff. It does indeed help with penetration. I assume the reason is that you can get double as much penetration before tunneling occurs. Try this explanation:

If a sphere penetrates a triangle only slightly, it will get bounced back the direction it came from.

If a sphere penetrates a triangle so that the triangle cuts the sphere almost exactly in half, but the majority of the sphere's volume is still outside the triangle mesh, then it will get bounced back the direction it came from.

If the sphere penetrates more than half way through the triangle, it will look like a collision of a sphere from the inside, so will actually get accelerated through the triangle by the collision. By overwriting the normal you ensure that even in this case, the normal is pointing outwards and thus the sphere gets sent back the way it came.

If the sphere penetrates almost all of the way through but there is still a tiny volume left outside the triangle mesh, the same logic applies as the above.


Making gimpact meshes one-way seems to help a bit with jamming, but doesn't completely eliminate it.
sparkprime
Posts: 508
Joined: Fri May 30, 2008 2:51 am
Location: Ossining, New York

Re: Objects Penetrating GImpact meshes

Post by sparkprime »

Adding a generous margin helps a lot with jamming, I think clever mesh design is the key here.

I changed my contact added callback as follows -- for gimpact meshes rather than completely override the normal (as is necessary with bvh triangle meshes) I just mirror it if it's pointing the wrong way.

Code: Select all

void contact_added_callback_obj (btManifoldPoint& cp,
                                 const btCollisionObject* colObj,
                                 int partId, int index)
{
        (void) partId;
        (void) index;
        const btCollisionShape *shape = colObj->getCollisionShape();

        if (shape->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE) return;
        const btTriangleShape *tshape =
               static_cast<const btTriangleShape*>(colObj->getCollisionShape());


        const btCollisionShape *parent = colObj->getRootCollisionShape();
        if (parent == NULL) return;
        switch (parent->getShapeType()) {
                case TRIANGLE_MESH_SHAPE_PROXYTYPE: {

                        btVector3 normal;
                        tshape->calcNormal(normal);

                        const btMatrix3x3 &orient =
                                colObj->getWorldTransform().getBasis();

                        normal = orient * normal;

                        btScalar dot = normal.dot(cp.m_normalWorldOnB);
                        btScalar magnitude = cp.m_normalWorldOnB.length();
                        normal *= dot > 0 ? magnitude : -magnitude;

                        cp.m_normalWorldOnB = normal;

                } ; break;
                case GIMPACT_SHAPE_PROXYTYPE: {

                        btVector3 normal;
                        tshape->calcNormal(normal);
                        normal *= -1;

                        const btMatrix3x3 &orient =
                                colObj->getWorldTransform().getBasis();

                        normal = orient * normal;

                        btScalar dot = normal.dot(cp.m_normalWorldOnB);

                        if (dot < 0)
                                cp.m_normalWorldOnB -= 2 * dot * normal;


                } ; break;
        }
}

bool contact_added_callback (btManifoldPoint& cp,
                             const btCollisionObject* colObj0,
                             int partId0, int index0,
                             const btCollisionObject* colObj1,
                             int partId1, int index1)
{
        contact_added_callback_obj(cp, colObj0, partId0, index0);
        //contact_added_callback_obj(cp, colObj1, partId1, index1);
        //std::cout << to_ogre(cp.m_normalWorldOnB) << std::endl;
        return true;
}
Regarding the commented out call above, I don't know how the contact added callback is called when a gimpact body intersects a Bullet bvh body. Is it called twice, once like (gimpact,bvh) and once like (bvh,gimpact) ?