DanielChappuis / reactphysics3d

Open source C++ physics engine library in 3D
http://www.reactphysics3d.com
zlib License
1.55k stars 224 forks source link

Bug with pyramid custom mesh #306

Closed patrikpatrik closed 1 year ago

patrikpatrik commented 1 year ago

Can you verify this? Ive checked and rechecked but for some reason, when a 4-sided pyramid custom shape is created, it tips over as if the bottom has only 1 face. Yet it has 2 faces (2 triangles) for bottom base. (5 vertices and 6 faces total)

This was kind of confusing to figure out but I've made sure my vertices windings are counter clockwise, as well as the indices. It compiles successfully and enabling debugging lines + triangles I always see it tipping over as if the bottom is only supported by 3 vertices. Could this be a bug?

// 4 sided pyramid
float quadTriVertices[15];
    quadTriVertices[0]  = -1;  quadTriVertices[1]  = -1;  quadTriVertices[2]  =  1; // front left
    quadTriVertices[3]  =  1;  quadTriVertices[4]  = -1;  quadTriVertices[5]  =  1; // front right
    quadTriVertices[6]  =  1;  quadTriVertices[7]  = -1;  quadTriVertices[8]  = -1; // back right
    quadTriVertices[9]  = -1;  quadTriVertices[10] = -1;  quadTriVertices[11] = -1; // back left
    quadTriVertices[12] =  0;  quadTriVertices[13] =  1;  quadTriVertices[14] =  0; // top
int quadTriIndices[18];
    quadTriIndices[0] = 0; quadTriIndices[1] = 2;  quadTriIndices[2] = 1;       // bottom right lower tri
    quadTriIndices[3] = 0; quadTriIndices[4] = 3;  quadTriIndices[5] = 2;       // bottom left upper tri
    quadTriIndices[6] = 0; quadTriIndices[7] = 4;  quadTriIndices[8] = 3;       // left
    quadTriIndices[9] = 0; quadTriIndices[10] = 1;  quadTriIndices[11] = 4;   // front
    quadTriIndices[12] = 1; quadTriIndices[13] = 2;  quadTriIndices[14] = 4;  // right
    quadTriIndices[15] = 4; quadTriIndices[16] = 2;  quadTriIndices[17] = 3;  // back
rp3d::PolygonVertexArray::PolygonFace* quadTriFaces = new rp3d::PolygonVertexArray::PolygonFace[6];
    rp3d::PolygonVertexArray::PolygonFace* quadTriFace = quadTriFaces;

    for (int i = 0; i < 6; i++) {

        // First vertex of the face in the indices array 
        quadTriFace->indexBase = i * 3;
        // Number of vertices in the face 
        quadTriFace->nbVertices = 3;

        quadTriFace++;
    }
    // positions for custom quad 4 sided pyramid shape!
    rp3d::Vector3 positionFour(0.0f, 2.0f, 0.0f);
    rp3d::Quaternion orientationFour = rp3d::Quaternion::identity();
    rp3d::Transform transformFour(positionFour, orientationFour);
    rp3d::RigidBody* bodyFour = world->createRigidBody(transformFour);

    // Create the quad 4 sided pyramid vertex array
    rp3d::PolygonVertexArray* quadTriVertexArray = new rp3d::PolygonVertexArray(5, quadTriVertices, 3 * sizeof(float),
        quadTriIndices, sizeof(int), 6, quadTriFaces,
        rp3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
        rp3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);

    // Create the polyhedron 4 sided quad pyramid mesh 
    rp3d::PolyhedronMesh* quadPyramidPolyhedronMesh = physicsCommon.createPolyhedronMesh(quadTriVertexArray);

    // Create the custom 4 sided quad pyramid convex mesh collision shape
    rp3d::ConvexMeshShape* quadPyramidMeshShape = physicsCommon.createConvexMeshShape(quadPyramidPolyhedronMesh);
DanielChappuis commented 1 year ago

Hello,

Your pyramid mesh seems to be fine. However, as you can read in the documentation here:

You need to make sure that the mesh you provide is indeed convex. Secondly, you should provide the simplest possible convex mesh. It means that you need to avoid coplanar faces in your convex mesh shape. Coplanar faces have to be merged together. Remember that convex meshes are not limited to triangular faces, you can create faces with more than three vertices.

Therefore, you should really not use two coplanar triangular faces for the bottom face. You need to use a quad face instead, the collision detection will be more stable this way.

patrikpatrik commented 1 year ago

Therefore, you should really not use two coplanar triangular faces for the bottom face. You need to use a quad face instead, the collision detection will be more stable this way.

Is there a way to slightly tweak the code to make it so that the bottom base uses 4 vertices and the sides just 3 without crashing? I can't seem to make that happen without making it all 3 vertices all around.

For instance, then the indices would change to 16 instead of 18 correct? 3 * 4 (sides) + 4 (bottom base) ?

int quadTriIndices[16];
    // ccw for 1st
    quadTriIndices[0] = 0; quadTriIndices[1] = 1;  quadTriIndices[2] = 4;  // front
    quadTriIndices[3] = 0; quadTriIndices[4] = 4;  quadTriIndices[5] = 3;  // left
    quadTriIndices[6] = 1; quadTriIndices[7] = 2;  quadTriIndices[8] = 4;  // right
    quadTriIndices[9] = 3; quadTriIndices[10] = 4;  quadTriIndices[11] = 2;  // back
    quadTriIndices[12] = 1; quadTriIndices[13] = 0;  quadTriIndices[14] = 3;  quadTriIndices[15] = 2; // bottom base

Then the polygonFace is now 5 instead of 6 faces.

rp3d::PolygonVertexArray::PolygonFace* quadTriFaces = new rp3d::PolygonVertexArray::PolygonFace[5];
rp3d::PolygonVertexArray::PolygonFace* quadTriFace = quadTriFaces ;

And then I've tried two different variations of this loop but crash

for (int i = 0; i < 5; i++) {
        if (i == 4) { // for bottom base
            quadTriFace->indexBase = i * 4;
            quadTriFace->nbVertices = 4;
        }
        else
        {
            // First vertex of the face in the indices array 
            quadTriFace->indexBase = i * 3;
            // Number of vertices in the face 
            quadTriFace->nbVertices = 3;
        }
        quadTriFace++;
    }

And then here is a version of a loop without incrementing quadTriFace and doing it manually outside the loop

rp3d::PolygonVertexArray::PolygonFace* quadTriFaces = new rp3d::PolygonVertexArray::PolygonFace[5];
//rp3d::PolygonVertexArray::PolygonFace* quadTriFace = quadTriFaces;
    for (int i = 0; i < 4; i++) {

        // First vertex of the face in the indices array 
        quadTriFaces[i].indexBase = i * 3;
        // Number of vertices in the face 
        quadTriFaces[i].nbVertices = 3;
    }
    // for bottom base
    quadTriFaces[4].indexBase = 4 * 4; 
    quadTriFaces[4].nbVertices = 4;

Am I doing something wrong in the loop?

patrikpatrik commented 1 year ago

Am I doing something wrong in the loop?

Yes you are. The indexBase needed to be (i - 1) * 4 and NOT i * 4 I couldn't understand out why, until I needed to write this this down paper and pen. So the indices are laid out like so: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Then the starting index for each face would occur at: 0, 3, 6, 9, 12 which equals 5 faces. The first 4 faces are 3 vertices of triangles, and the last face is 1 quad of 4 vertices. However, quadTriFaces[4].indexBase = 4 * 4; would equal 16, which is out of bounds and throws an error. So to start on the 12th index, quadTriFaces[4].indexBase = (i - 1) * 4; = 12. Which is the bottom quad face, therefore quadTriFaces[4].nbVertices = 4;

Now I generate a stable pyramid! My god... thank you Daniel for the helpful tip!

DanielChappuis commented 1 year ago

Perfect. Glad that you find the issue.