Quellcode durchsuchen

Added support for dynamic meshes rigid bodies via btConvexHull, which is a more efficient approximation of a convex mesh. More accurate higher resolution static triangle meshes are still supported via btBvhTriangleMeshShape when a mass of zero is specified.

Updated the physics sample in the sample browser to use a dynamic mesh rigid body for the duck model.
sgrenier vor 12 Jahren
Ursprung
Commit
2f4742cf4d

+ 126 - 97
gameplay/src/PhysicsController.cpp

@@ -11,6 +11,7 @@
 #undef new
 #undef new
 #endif
 #endif
 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
+#include "BulletCollision/CollisionShapes/btShapeHull.h"
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #define new DEBUG_NEW
 #define new DEBUG_NEW
 #endif
 #endif
@@ -762,7 +763,7 @@ static void computeCenterOfMass(const Vector3& center, const Vector3& scale, Vec
     centerOfMassOffset->negate();
     centerOfMassOffset->negate();
 }
 }
 
 
-PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset)
+PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset, bool dynamic)
 {
 {
     GP_ASSERT(node);
     GP_ASSERT(node);
 
 
@@ -887,7 +888,7 @@ PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsC
     case PhysicsCollisionShape::SHAPE_MESH:
     case PhysicsCollisionShape::SHAPE_MESH:
         {
         {
             // Build mesh from passed in shape.
             // Build mesh from passed in shape.
-            collisionShape = createMesh(shape.data.mesh, scale);
+            collisionShape = createMesh(shape.data.mesh, scale, dynamic);
         }
         }
         break;
         break;
 
 
@@ -1055,34 +1056,10 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, HeightFi
     return shape;
     return shape;
 }
 }
 
 
-PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3& scale)
+PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3& scale, bool dynamic)
 {
 {
     GP_ASSERT(mesh);
     GP_ASSERT(mesh);
 
 
-    // Only support meshes with triangle list primitive types.
-    bool triMesh = true;
-    if (mesh->getPartCount() > 0)
-    {
-        for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
-        {
-            if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
-            {
-                triMesh = false;
-                break;
-            }
-        }
-    }
-    else
-    {
-        triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
-    }
-
-    if (!triMesh)
-    {
-        GP_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
-        return NULL;
-    }
-
     // The mesh must have a valid URL (i.e. it must have been loaded from a Bundle)
     // The mesh must have a valid URL (i.e. it must have been loaded from a Bundle)
     // in order to fetch mesh data for computing mesh rigid body.
     // in order to fetch mesh data for computing mesh rigid body.
     if (strlen(mesh->getUrl()) == 0)
     if (strlen(mesh->getUrl()) == 0)
@@ -1091,6 +1068,36 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         return NULL;
         return NULL;
     }
     }
 
 
+    if (!dynamic)
+    {
+        // Static meshes use btBvhTriangleMeshShape and therefore only support triangle mesh shapes.
+        // Dynamic meshes are approximated with a btConvexHullShape (convex wrapper on cloud of vertices)
+        // and therefore can support any primitive type.
+        bool triMesh = true;
+        if (mesh->getPartCount() > 0)
+        {
+            for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
+            {
+                if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
+                {
+                    triMesh = false;
+                    break;
+                }
+            }
+        }
+        else
+        {
+            triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
+        }
+
+        if (!triMesh)
+        {
+            GP_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
+            return NULL;
+        }
+    }
+
+    // Read mesh data from URL
     Bundle::MeshData* data = Bundle::readMeshData(mesh->getUrl());
     Bundle::MeshData* data = Bundle::readMeshData(mesh->getUrl());
     if (data == NULL)
     if (data == NULL)
     {
     {
@@ -1112,96 +1119,118 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
     for (unsigned int i = 0; i < data->vertexCount; i++)
     for (unsigned int i = 0; i < data->vertexCount; i++)
     {
     {
         v.set(*((float*)&data->vertexData[i * vertexStride + 0 * sizeof(float)]),
         v.set(*((float*)&data->vertexData[i * vertexStride + 0 * sizeof(float)]),
-              *((float*)&data->vertexData[i * vertexStride + 1 * sizeof(float)]),
-              *((float*)&data->vertexData[i * vertexStride + 2 * sizeof(float)]));
+                *((float*)&data->vertexData[i * vertexStride + 1 * sizeof(float)]),
+                *((float*)&data->vertexData[i * vertexStride + 2 * sizeof(float)]));
         v *= m;
         v *= m;
         memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
         memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
     }
     }
 
 
-    btTriangleIndexVertexArray* meshInterface = bullet_new<btTriangleIndexVertexArray>();
+    btCollisionShape* collisionShape = NULL;
+    btTriangleIndexVertexArray* meshInterface = NULL;
 
 
-    size_t partCount = data->parts.size();
-    if (partCount > 0)
+    if (dynamic)
+    {
+        // For dynamic meshes, use a btConvexHullShape approximation
+        btConvexHullShape* originalConvexShape = bullet_new<btConvexHullShape>(shapeMeshData->vertexData, data->vertexCount, sizeof(float)*3);
+
+        // Create a hull approximation for better performance
+	    btShapeHull* hull = bullet_new<btShapeHull>(originalConvexShape);
+	    hull->buildHull(originalConvexShape->getMargin());
+	    collisionShape = bullet_new<btConvexHullShape>((btScalar*)hull->getVertexPointer(), hull->numVertices());
+
+        SAFE_DELETE(hull);
+        SAFE_DELETE(originalConvexShape);
+    }
+    else
     {
     {
-        PHY_ScalarType indexType = PHY_UCHAR;
-        int indexStride = 0;
-        Bundle::MeshPartData* meshPart = NULL;
-        for (size_t i = 0; i < partCount; i++)
+        // For static meshes, use btBvhTriangleMeshShape
+        meshInterface = bullet_new<btTriangleIndexVertexArray>();
+
+        size_t partCount = data->parts.size();
+        if (partCount > 0)
         {
         {
-            meshPart = data->parts[i];
-            GP_ASSERT(meshPart);
+            PHY_ScalarType indexType = PHY_UCHAR;
+            int indexStride = 0;
+            Bundle::MeshPartData* meshPart = NULL;
+            for (size_t i = 0; i < partCount; i++)
+            {
+                meshPart = data->parts[i];
+                GP_ASSERT(meshPart);
 
 
-            switch (meshPart->indexFormat)
+                switch (meshPart->indexFormat)
+                {
+                case Mesh::INDEX8:
+                    indexType = PHY_UCHAR;
+                    indexStride = 1;
+                    break;
+                case Mesh::INDEX16:
+                    indexType = PHY_SHORT;
+                    indexStride = 2;
+                    break;
+                case Mesh::INDEX32:
+                    indexType = PHY_INTEGER;
+                    indexStride = 4;
+                    break;
+                default:
+                    GP_ERROR("Unsupported index format (%d).", meshPart->indexFormat);
+                    SAFE_DELETE(meshInterface);
+                    SAFE_DELETE_ARRAY(shapeMeshData->vertexData);
+                    SAFE_DELETE(shapeMeshData);
+                    SAFE_DELETE(data);
+                    return NULL;
+                }
+
+                // Move the index data into the rigid body's local buffer.
+                // Set it to NULL in the MeshPartData so it is not released when the data is freed.
+                shapeMeshData->indexData.push_back(meshPart->indexData);
+                meshPart->indexData = NULL;
+
+                // Create a btIndexedMesh object for the current mesh part.
+                btIndexedMesh indexedMesh;
+                indexedMesh.m_indexType = indexType;
+                indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
+                indexedMesh.m_numVertices = meshPart->indexCount;
+                indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
+                indexedMesh.m_triangleIndexStride = indexStride*3;
+                indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
+                indexedMesh.m_vertexStride = sizeof(float)*3;
+                indexedMesh.m_vertexType = PHY_FLOAT;
+
+                // Add the indexed mesh data to the mesh interface.
+                meshInterface->addIndexedMesh(indexedMesh, indexType);
+            }
+        }
+        else
+        {
+            // Generate index data for the mesh locally in the rigid body.
+            unsigned int* indexData = new unsigned int[data->vertexCount];
+            for (unsigned int i = 0; i < data->vertexCount; i++)
             {
             {
-            case Mesh::INDEX8:
-                indexType = PHY_UCHAR;
-                indexStride = 1;
-                break;
-            case Mesh::INDEX16:
-                indexType = PHY_SHORT;
-                indexStride = 2;
-                break;
-            case Mesh::INDEX32:
-                indexType = PHY_INTEGER;
-                indexStride = 4;
-                break;
-            default:
-                GP_ERROR("Unsupported index format (%d).", meshPart->indexFormat);
-                SAFE_DELETE(meshInterface);
-                SAFE_DELETE_ARRAY(shapeMeshData->vertexData);
-                SAFE_DELETE(shapeMeshData);
-                SAFE_DELETE(data);
-                return NULL;
+                indexData[i] = i;
             }
             }
+            shapeMeshData->indexData.push_back((unsigned char*)indexData);
 
 
-            // Move the index data into the rigid body's local buffer.
-            // Set it to NULL in the MeshPartData so it is not released when the data is freed.
-            shapeMeshData->indexData.push_back(meshPart->indexData);
-            meshPart->indexData = NULL;
-
-            // Create a btIndexedMesh object for the current mesh part.
+            // Create a single btIndexedMesh object for the mesh interface.
             btIndexedMesh indexedMesh;
             btIndexedMesh indexedMesh;
-            indexedMesh.m_indexType = indexType;
-            indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
-            indexedMesh.m_numVertices = meshPart->indexCount;
-            indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
-            indexedMesh.m_triangleIndexStride = indexStride*3;
+            indexedMesh.m_indexType = PHY_INTEGER;
+            indexedMesh.m_numTriangles = data->vertexCount / 3; // assume TRIANGLES primitive type
+            indexedMesh.m_numVertices = data->vertexCount;
+            indexedMesh.m_triangleIndexBase = shapeMeshData->indexData[0];
+            indexedMesh.m_triangleIndexStride = sizeof(unsigned int);
             indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
             indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
             indexedMesh.m_vertexType = PHY_FLOAT;
 
 
-            // Add the indexed mesh data to the mesh interface.
-            meshInterface->addIndexedMesh(indexedMesh, indexType);
+            // Set the data in the mesh interface.
+            meshInterface->addIndexedMesh(indexedMesh, indexedMesh.m_indexType);
         }
         }
-    }
-    else
-    {
-        // Generate index data for the mesh locally in the rigid body.
-        unsigned int* indexData = new unsigned int[data->vertexCount];
-        for (unsigned int i = 0; i < data->vertexCount; i++)
-        {
-            indexData[i] = i;
-        }
-        shapeMeshData->indexData.push_back((unsigned char*)indexData);
-
-        // Create a single btIndexedMesh object for the mesh interface.
-        btIndexedMesh indexedMesh;
-        indexedMesh.m_indexType = PHY_INTEGER;
-        indexedMesh.m_numTriangles = data->vertexCount / 3; // assume TRIANGLES primitive type
-        indexedMesh.m_numVertices = data->vertexCount;
-        indexedMesh.m_triangleIndexBase = shapeMeshData->indexData[0];
-        indexedMesh.m_triangleIndexStride = sizeof(unsigned int);
-        indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
-        indexedMesh.m_vertexStride = sizeof(float)*3;
-        indexedMesh.m_vertexType = PHY_FLOAT;
-
-        // Set the data in the mesh interface.
-        meshInterface->addIndexedMesh(indexedMesh, indexedMesh.m_indexType);
+
+        // Create our collision shape object and store shapeMeshData in it.
+        collisionShape = bullet_new<btBvhTriangleMeshShape>(meshInterface, true);
     }
     }
 
 
     // Create our collision shape object and store shapeMeshData in it.
     // Create our collision shape object and store shapeMeshData in it.
-    PhysicsCollisionShape* shape =
-        new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true), meshInterface);
+    PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, collisionShape, meshInterface);
     shape->_shapeData.meshData = shapeMeshData;
     shape->_shapeData.meshData = shapeMeshData;
 
 
     _shapes.push_back(shape);
     _shapes.push_back(shape);

+ 2 - 2
gameplay/src/PhysicsController.h

@@ -419,7 +419,7 @@ private:
 
 
     // Creates a collision shape for the given node and gameplay shape definition.
     // Creates a collision shape for the given node and gameplay shape definition.
     // Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
     // Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
-    PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset);
+    PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset, bool dynamic);
     
     
     // Creates a box collision shape.
     // Creates a box collision shape.
     PhysicsCollisionShape* createBox(const Vector3& extents, const Vector3& scale);
     PhysicsCollisionShape* createBox(const Vector3& extents, const Vector3& scale);
@@ -434,7 +434,7 @@ private:
     PhysicsCollisionShape* createHeightfield(Node* node, HeightField* heightfield, Vector3* centerOfMassOffset);
     PhysicsCollisionShape* createHeightfield(Node* node, HeightField* heightfield, Vector3* centerOfMassOffset);
 
 
     // Creates a triangle mesh collision shape.
     // Creates a triangle mesh collision shape.
-    PhysicsCollisionShape* createMesh(Mesh* mesh, const Vector3& scale);
+    PhysicsCollisionShape* createMesh(Mesh* mesh, const Vector3& scale, bool dynamic);
 
 
     // Destroys a collision shape created through PhysicsController
     // Destroys a collision shape created through PhysicsController
     void destroyShape(PhysicsCollisionShape* shape);
     void destroyShape(PhysicsCollisionShape* shape);

+ 1 - 1
gameplay/src/PhysicsGhostObject.cpp

@@ -14,7 +14,7 @@ PhysicsGhostObject::PhysicsGhostObject(Node* node, const PhysicsCollisionShape::
     GP_ASSERT(physicsController);
     GP_ASSERT(physicsController);
 
 
     // Create and set the collision shape for the ghost object.
     // Create and set the collision shape for the ghost object.
-    _collisionShape = physicsController->createShape(node, shape, &centerOfMassOffset);
+    _collisionShape = physicsController->createShape(node, shape, &centerOfMassOffset, false);
     GP_ASSERT(_collisionShape);
     GP_ASSERT(_collisionShape);
 
 
     // Create the ghost object.
     // Create the ghost object.

+ 2 - 2
gameplay/src/PhysicsRigidBody.cpp

@@ -18,7 +18,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Defi
 
 
     // Create our collision shape.
     // Create our collision shape.
     Vector3 centerOfMassOffset;
     Vector3 centerOfMassOffset;
-    _collisionShape = Game::getInstance()->getPhysicsController()->createShape(node, shape, &centerOfMassOffset);
+    _collisionShape = Game::getInstance()->getPhysicsController()->createShape(node, shape, &centerOfMassOffset, parameters.mass != 0.0f);
     GP_ASSERT(_collisionShape && _collisionShape->getShape());
     GP_ASSERT(_collisionShape && _collisionShape->getShape());
 
 
     // Create motion state object.
     // Create motion state object.
@@ -28,7 +28,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Defi
     // inertia. However, if the collision shape is a triangle mesh, we don't calculate 
     // inertia. However, if the collision shape is a triangle mesh, we don't calculate 
     // inertia since Bullet doesn't currently support this.
     // inertia since Bullet doesn't currently support this.
     btVector3 localInertia(0.0, 0.0, 0.0);
     btVector3 localInertia(0.0, 0.0, 0.0);
-    if (parameters.mass != 0.0 && _collisionShape->getType() != PhysicsCollisionShape::SHAPE_MESH)
+    if (parameters.mass != 0.0)
         _collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
         _collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
 
 
     // Create the Bullet physics rigid body object.
     // Create the Bullet physics rigid body object.

+ 2 - 2
samples/browser/res/common/physics.physics

@@ -34,8 +34,8 @@ collisionObject capsule
 collisionObject duck
 collisionObject duck
 {
 {
     type = RIGID_BODY
     type = RIGID_BODY
-    shape = BOX
-    mass = 1.0
+    shape = MESH
+    mass = 5.0
     friction = 1.0
     friction = 1.0
     restitution = 0.0
     restitution = 0.0
     linearDamping = 0.5
     linearDamping = 0.5