mosra / magnum-integration

Integration libraries for the Magnum C++11 graphics engine
https://magnum.graphics/
Other
99 stars 44 forks source link

BulletIntegration: conversion of Magnum mesh data into Bullet collision mesh [snippet] #20

Open mosra opened 8 years ago

mosra commented 8 years ago

As @Squareys mentioned in #19, here's his code snippet for creating Bullet collision mesh directly from Magnum mesh data, licensed under CC0: https://groups.google.com/forum/#!topic/magnum-engine/V3iL35umkwU

/* source mesh, a valid pointer to data which needs to persist
 * for the resulting shape to stay valid */
MeshData3D* mesh = /* ... */;
/* resulting shape */
btCollisionShape* shape = nullptr;

/* this code only works for Triangles only meshes */
if (mesh->primitive() == MeshPrimitive::Triangles) {
  /* create a bullet indexed mesh from our mesh data */
  btIndexedMesh bulletMesh;
  bulletMesh.m_numTriangles = mesh->indices().size()/3;
  bulletMesh.m_triangleIndexBase = (const unsigned char *)mesh->indices().data();
  bulletMesh.m_triangleIndexStride = 3 * sizeof(UnsignedInt);
  bulletMesh.m_numVertices = mesh->positions(0).size();
  bulletMesh.m_vertexBase = (const unsigned char *)mesh->positions(0).data();
  bulletMesh.m_vertexStride = sizeof(Vector3);
  bulletMesh.m_indexType = PHY_INTEGER;
  bulletMesh.m_vertexType = PHY_FLOAT;

  btTriangleIndexVertexArray *pTriMesh = new btTriangleIndexVertexArray();
  pTriMesh->addIndexedMesh(bulletMesh, PHY_INTEGER);

  shape = new btBvhTriangleMeshShape(pTriMesh, true, true);
} else {
  Error() << "Unsupported mesh primitive type while converting Magnum mesh to Bullet mesh.";
}

Since btConvexHullShape is more efficient with smaller meshes (see http://bulletphysics.org/mediawiki-1.5.8/index.php/Collision_Shapes#Meshes) here is another code snippet which you can replace the contents of the if block with:

shape = new btConvexHullShape((const btScalar *)mesh->positions(0).data(), mesh->positions(0).size(), sizeof(Vector3));       

Note that it is recommended to use meshes of less than around 100 vertices for bullet convex hulls (see the link above). Also, convex hulls are, obviously, convex. They might not be suited for you individual collision mesh. (Also note, that I didn't test that line very much)

Just putting it here since the Google Groups forum seems to be quite abandoned now (which I completely understand, the UI is horrible). I think this snippet may even be useful and general enough to include directly in the Bullet Integration library.

Squareys commented 8 years ago

Updated version:

    std::optional<Trade::MeshData3D> meshData = ...;

    if(!meshData || meshData->primitive() != MeshPrimitive::Triangles) {
        Error() << "Cannot load collision mesh, skipping";
        return;
    }

    /* this is a collision mesh, convert to bullet mesh */
    btIndexedMesh bulletMesh;
    bulletMesh.m_numTriangles = meshData->indices().size()/3;
    bulletMesh.m_triangleIndexBase = reinterpret_cast<const unsigned char *>(meshData->indices().data());
    bulletMesh.m_triangleIndexStride = 3 * sizeof(UnsignedInt);
    bulletMesh.m_numVertices = meshData->positions(0).size();
    bulletMesh.m_vertexBase = reinterpret_cast<const unsigned char *>(meshData->positions(0).data());
    bulletMesh.m_vertexStride = sizeof(Vector3);
    bulletMesh.m_indexType = PHY_INTEGER;
    bulletMesh.m_vertexType = PHY_FLOAT;

The btIndexedMesh can then further be used as follows:

    btCollisionShape* shape = nullptr;
    auto tivArray = new btTriangleIndexVertexArray());
    tivArray->addIndexedMesh(bulletMesh, PHY_INTEGER);
    if(shapeType == "TriangleMeshShape") {
        /* exact shape, but worse performance */
        shape = new btBvhTriangleMeshShape(tivArray, true);
    } else {
        /* convex hull, but better performance */
        shape = new btConvexTriangleMeshShape(tivArray, true);
    } /* btConvexHullShape can be even more performant */

PS: also CC0, in case anybody cares.

Squareys commented 7 years ago

Will a free function in BulletIntegration namespace suffice?

mosra commented 7 years ago

Yup, why not? :)