NVIDIAGameWorks/PhysX

Inconsistent compute penetration depth results using different Geometries

gabrielecaddeo opened this issue · 2 comments

Hi, I am using the PxGeometryQuery::computePenetration with two boxes that are compenetrating (pose0 and pose1), as the image below shows.
example_nvidia
Basically I am trying to use this query to compute the penetration between a Triangle mesh and a simple box. However, I see that sometimes the function return very different results if I am using 2 simple boxes or if I am using a simple box and a Triangle mesh. The triangle mesh is loaded using the code in the samples directory.
The green box can be either box0 or trimeshGeom object. The red box is the box1.
I attach here the code.

#define NDEBUG
#include "PxPhysicsAPI.h"
#include <iostream>
#include "wavefront.h"


using namespace physx;

PxDefaultAllocator	gAllocator;
PxDefaultErrorCallback	gErrorCallback;
PxFoundation*           gFoundation = NULL;
PxPhysics*		gPhysics	= NULL;
PxCooking*		gCooking	= NULL;

int main (int argc, char** argv)
{
    // Init the top level PxPhysics object

    gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
    if(!gFoundation)
        std::cout<<"PxCreateFoundation failed!"<<std::endl;

    gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(), true);
	if(!gPhysics)
		exit(0);

    gCooking = PxCreateCooking(PX_PHYSICS_VERSION, *gFoundation, PxCookingParams(PxTolerancesScale()));
   
    WavefrontObj obj;
    obj.loadObj("/path/to/the/prism.obj", false); 

    PxVec3*  vertices = new PxVec3[obj.mVertexCount];
    PxU32* indices = new PxU32[obj.mTriCount * 3];

    for (int i = 0; i < obj.mVertexCount ; i++)
    {
	PxVec3 v(obj.mVertices[i*3], obj.mVertices[i*3+1], obj.mVertices[i*3+2]);
	vertices[i] = v;
    }


    for (int i = 0; i < obj.mTriCount; i++)
    {
	for (int j = 0; j<3; j++)
	{
    	    indices[i*3 +j] = obj.mIndices[i*3 +j];
	}
    }

    // Create the triangle mesh

    PxTriangleMeshDesc meshDesc;
    meshDesc.points.count = obj.mVertexCount;
    meshDesc.points.data = vertices;
    meshDesc.points.stride = sizeof(PxVec3);
    meshDesc.triangles.count = obj.mTriCount;
    meshDesc.triangles.data = indices;
    meshDesc.triangles.stride = 3 * sizeof(PxU32);
    PxTriangleMesh* triMesh = NULL;
    triMesh = gCooking->createTriangleMesh(meshDesc, gPhysics->getPhysicsInsertionCallback());
    PxTriangleMeshGeometry trimeshGeom(triMesh);

    // Create the simple boxes
    PxBoxGeometry box0(0.023, 0.0455, 0.0865);
    PxBoxGeometry box1(0.0161, 0.0135, 0.017);

    PxVec3 direction;
    PxF32 depth;

    PxTransform pose0(PxVec3(0.1171, 0.0015, 0.1955));
    PxTransform pose1(PxVec3(0.133365, 0.000294747, 0.275435), PxQuat(-0.00200156, 0.000335579, 0.999991, 0.00359089));

    bool isPenetrating = PxGeometryQuery::computePenetration(direction, depth, box0, pose0, box1, pose1);

    std::cout<<isPenetrating<<std::endl;
    if (isPenetrating)
    {
        std::cout<<depth<<std::endl;
        std::cout<< direction.x << " " << direction.y << " " << direction.z << std::endl;
    }

    isPenetrating = PxGeometryQuery::computePenetration(direction, depth, trimeshGeom, pose0, box1, pose1);

    std::cout<<isPenetrating<<std::endl;
    if (isPenetrating)
    {
        std::cout<<depth<<std::endl;
        std::cout<< direction.x << " " << direction.y << " " << direction.z << std::endl;
    }
    
    gCooking->release();
    gPhysics->release();
    gFoundation->release();
    
    return 0;

}

This is the output of the code:

1
0.0229577
-0.999992 0 -0.00400068
0

In this example, the function with the trimeshGeom does not return any compenetration. However, if I slightly change the pose0 for example in this way
PxTransform pose0(PxVec3(0.1, 0.0015, 0.1955));
then the code works perfectly.
Can you give me some advice or explanation?
Here is the code of the prism.obj file

####
#
# OBJ File Generated by Meshlab
#
####
# Object unit_cube_small.obj
#
# Vertices: 8
# Faces: 12
#
####
vn -0.005774 -0.005774 0.005774
v -0.0230000 -0.04550000 0.08650000
vn -0.005774 0.005774 0.005774
v -0.0230000 0.04550000 0.08650000
vn -0.005774 -0.005774 -0.005774
v -0.0230000 -0.04550000 -0.08650000
vn -0.005774 0.005774 -0.005774
v -0.0230000 0.04550000 -0.08650000
vn 0.005774 -0.005774 0.005774
v 0.0230000 -0.04550000 0.08650000
vn 0.005774 -0.005774 -0.005774
v 0.0230000 -0.04550000 -0.08650000
vn 0.005774 0.005774 0.005774
v 0.0230000 0.04550000 0.08650000
vn 0.005774 0.005774 -0.005774
v 0.0230000 0.04550000 -0.08650000
# 8 vertices, 0 vertices normals

f 1//1 2//2 3//3
f 3//3 2//2 4//4
f 5//5 1//1 6//6
f 6//6 1//1 3//3
f 7//7 5//5 8//8
f 8//8 5//5 6//6
f 2//2 7//7 4//4
f 4//4 7//7 8//8
f 5//5 7//7 1//1
f 1//1 7//7 2//2
f 8//8 6//6 4//4
f 4//4 6//6 3//3
# 12 faces, 0 coords texture

# End of File

Contacts/MTDs are for box-box pairs are generated based on the pair of box geometries that have well-defined volumes, it can generate a valid MTD regardless of the configuration of the intersecting boxes (including one being fully contained by the other).

However, there is no volumetric information associated with a triMesh. It's just a set of triangles that form a shape - this shape could be closed (e.g. a box) or open (e.g. the surface of a ground). As we have no notion of volumetric information, a box made from a triMesh is effectively treated as a hollow shell of a box. As such, PhysX generates MTDs based on triangle-box intersections. These are really only well-defined when the COM of the box is on the positive side of the triangle's plane. If COM is on the negative side but touching the triangle, the triangle is culled. As such, there are many cases where a triangle mesh and box/convex equivalent would not generate the same MTD.

Thanks for your answer!