Setting up collision between OpenGL meshes

Post Reply
jimjamjack
Posts: 39
Joined: Tue Jan 31, 2017 8:07 pm

Setting up collision between OpenGL meshes

Post by jimjamjack »

Hello, I'm pretty new to Bullet so I'm pretty confused about setting up collisions between meshes. I understand how to set it up for basic shapes, but I'm having issues giving three of my meshes a collision shape of its mesh (I want simple ray callbacks, and I have a ray casting method).

I have three meshes in the shape of targets, for which I want each to have their mesh as the collision shape. How would I go about this?
Can anyone provide some sort of code to help me through this? Thanks in advance :)
Last edited by jimjamjack on Mon May 01, 2017 9:48 pm, edited 1 time in total.
benelot
Posts: 350
Joined: Sat Jul 04, 2015 10:33 am
Location: Bern, Switzerland
Contact:

Re: Setting up collision between OpenGL meshes

Post by benelot »

If you want performance, do not try to use your OpenGL meshes to detect collisions. You should use an approximation of it built from the primitives. So if your mesh looks a bit like and mainly behaves like a sphere, use a sphere. If a capsule is better, then use that. Things like characters are usually full of capsules :)

If you really need to go for the full meshes, perform a convex shape decomposition and compose the convex hulls into a compound shape.
jimjamjack
Posts: 39
Joined: Tue Jan 31, 2017 8:07 pm

Re: Setting up collision between OpenGL meshes

Post by jimjamjack »

The meshes are shooting targets, I currently have a collision box shape for each one but it's inaccurate since I can shoot through the box but not the target and still 'hit' it. Would you recommend another primitive shape in particular? :)

I've looked into convex hulls and btvTriangleArrays and similar things, but honestly cannot figure out how to create the collision shape using the vertices/indices that I have. I know it's less efficient than using primitives, but accuracy is quite important for the ray calls :/

Appreciate the help though :)
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Setting up collision between OpenGL meshes

Post by drleviathan »

Here is some code that may work for you. I tried to make it clear and correct, however please keep in mind that I did not test: there may be syntax errors, incorrect API usage, and memory leaks. Use at your own risk:

Code: Select all

    std::vector<unsigned short> targetIndices;
    std::vector<glm::vec3> targetVertices;
    std::vector<glm::vec2> targetUvs;
    std::vector<glm::vec3> targetNormals;
    res = loadAssImp("target2.obj", targetIndices, targetVertices, targetUvs, targetNormals);

    // first create a btTriangleIndexVertexArray
    // NOTE: we must track this pointer and delete it when all shapes are done with it!
    btTriangleIndexVertexArray* data = new btTriangleIndexVertexArray;

    // add an empty mesh (data makes a copy)
    btIndexedMesh tempMesh;
    data->addIndexedMesh(tempMesh, PHY_FLOAT);

    // get a reference to internal copy of the empty mesh
    btIndexedMesh& mesh = data->getIndexedMeshArray()[0];

    // allocate memory for the mesh
    const int32_t VERTICES_PER_TRIANGLE = 3;
    size_t numIndices = targetIndices.size();
    mesh.m_numTriangles = numIndices / VERTICES_PER_TRIANGLE;
    if (numIndices < std::numeric_limits<int16_t>::max()) {
        // we can use 16-bit indices
        mesh.m_triangleIndexBase = new unsigned char[sizeof(int16_t) * (size_t)numIndices];
        mesh.m_indexType = PHY_SHORT;
        mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int16_t);
    } else {
        // we need 32-bit indices
        mesh.m_triangleIndexBase = new unsigned char[sizeof(int32_t) * (size_t)numIndices];
        mesh.m_indexType = PHY_INTEGER;
        mesh.m_triangleIndexStride = VERTICES_PER_TRIANGLE * sizeof(int32_t);
    }
    mesh.m_numVertices = targetVertices.size();
    mesh.m_vertexBase = new unsigned char[VERTICES_PER_TRIANGLE * sizeof(btScalar) * (size_t)mesh.m_numVertices];
    mesh.m_vertexStride = VERTICES_PER_TRIANGLE * sizeof(btScalar);

    // copy vertices into mesh
    btScalar* vertexData = static_cast<btScalar*>((void*)(mesh.m_vertexBase));
    for (int32_t i = 0; i < mesh.m_numVertices; ++i) {
        int32_t j = i * VERTICES_PER_TRIANGLE;
        const glm::vec3& point = targetVertices[i];
        vertexData[j] = point.x;
        vertexData[j + 1] = point.y;
        vertexData[j + 2] = point.z;
    }
    // copy indices into mesh
    if (numIndices < std::numeric_limits<int16_t>::max()) {
        // 16-bit case
        int16_t* indices = static_cast<int16_t*>((void*)(mesh.m_triangleIndexBase));
        for (int32_t i = 0; i < numIndices; ++i) {
            indices[i] = (int16_t)targetIndices[i];
        }
    } else {
        // 32-bit case
        int32_t* indices = static_cast<int32_t*>((void*)(mesh.m_triangleIndexBase));
        for (int32_t i = 0; i < numIndices; ++i) {
            indices[i] = targetIndices[i];
        }
    }

    // create the shape
    // NOTE: we must track this pointer and delete it when all btCollisionObjects that use it are done with it!
    const bool USE_QUANTIZED_AABB_COMPRESSION = true;
    btBvhTriangleMeshShape* shape = new btBvhTriangleMeshShape(data, USE_QUANTIZED_AABB_COMPRESSION);
jimjamjack
Posts: 39
Joined: Tue Jan 31, 2017 8:07 pm

Re: Setting up collision between OpenGL meshes

Post by jimjamjack »

@drleviathan

Wow, after scouring the web for about a week that is by far the most useful post I've come across! Thanks for the code and break down, it really was helpful. The code works perfectly, apart from the impact on performance and frame rate, but I'll take a look at that when I can :)

That is unless you have any suggestions for improving performance? Regardless, an extremely useful post, so thanks again :)
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Setting up collision between OpenGL meshes

Post by drleviathan »

If your graphics mesh data are in the right format I believe is is possible to create a btStridingMeshInterface that points into that memory: you can share the same data for rendering and collisions. I've never done it so I don't have any example code to offer.
jimjamjack
Posts: 39
Joined: Tue Jan 31, 2017 8:07 pm

Re: Setting up collision between OpenGL meshes

Post by jimjamjack »

Ah, I've actually looked into btStridingMeshInterfaces before. I'll look into them again, and if I make any progress with it then I'll post it here. If anyone else is looking into them as well, the basic idea is to create a btStridingMeshInterface, call getLockedVertexIndexBase, fill the array it returns, and unlock.

Cheers again :)
Post Reply