Browse Source

Add dynamic triangle meshes support.

Eugene Kozlov 8 years ago
parent
commit
d16abdeec1

+ 192 - 180
Source/Urho3D/Physics/CollisionShape.cpp

@@ -52,8 +52,9 @@
 #include <Bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h>
 #include <Bullet/BulletCollision/CollisionShapes/btSphereShape.h>
 #include <Bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h>
-#include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
 #include <Bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h>
+#include <Bullet/BulletCollision/Gimpact/btGImpactShape.h>
+#include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
 #include <StanHull/hull.h>
 
 namespace Urho3D
@@ -76,6 +77,7 @@ static const char* typeNames[] =
     "TriangleMesh",
     "ConvexHull",
     "Terrain",
+    "GImpactMesh",
     nullptr
 };
 
@@ -212,8 +214,14 @@ TriangleMeshData::TriangleMeshData(CustomGeometry* custom)
     btGenerateInternalEdgeInfo(shape_.Get(), infoMap_.Get());
 }
 
-TriangleMeshData::~TriangleMeshData()
+GImpactMeshData::GImpactMeshData(Model* model, unsigned lodLevel)
 {
+    meshInterface_ = new TriangleMeshInterface(model, lodLevel);
+}
+
+GImpactMeshData::GImpactMeshData(CustomGeometry* custom)
+{
+    meshInterface_ = new TriangleMeshInterface(custom);
 }
 
 ConvexData::ConvexData(Model* model, unsigned lodLevel)
@@ -306,10 +314,6 @@ void ConvexData::BuildHull(const PODVector<Vector3>& vertices)
     }
 }
 
-ConvexData::~ConvexData()
-{
-}
-
 HeightfieldData::HeightfieldData(Terrain* terrain, unsigned lodLevel) :
     heightData_(terrain->GetHeightData()),
     spacing_(terrain->GetSpacing()),
@@ -364,10 +368,6 @@ HeightfieldData::HeightfieldData(Terrain* terrain, unsigned lodLevel) :
     }
 }
 
-HeightfieldData::~HeightfieldData()
-{
-}
-
 bool HasDynamicBuffers(Model* model, unsigned lodLevel)
 {
     unsigned numGeometries = model->GetNumGeometries();
@@ -394,6 +394,65 @@ bool HasDynamicBuffers(Model* model, unsigned lodLevel)
     return false;
 }
 
+CollisionGeometryData* CreateCollisionGeometryData(ShapeType shapeType, Model* model, unsigned lodLevel)
+{
+    switch (shapeType)
+    {
+    case SHAPE_TRIANGLEMESH:
+        return new TriangleMeshData(model, lodLevel);
+    case SHAPE_CONVEXHULL:
+        return new ConvexData(model, lodLevel);
+    case SHAPE_GIMPACTMESH:
+        return new GImpactMeshData(model, lodLevel);
+    default:
+        return nullptr;
+    }
+}
+
+CollisionGeometryData* CreateCollisionGeometryData(ShapeType shapeType, CustomGeometry* custom)
+{
+    switch (shapeType)
+    {
+    case SHAPE_TRIANGLEMESH:
+        return new TriangleMeshData(custom);
+    case SHAPE_CONVEXHULL:
+        return new ConvexData(custom);
+    case SHAPE_GIMPACTMESH:
+        return new GImpactMeshData(custom);
+    default:
+        return nullptr;
+    }
+}
+
+btCollisionShape* CreateCollisionGeometryDataShape(ShapeType shapeType, CollisionGeometryData* geometry, const Vector3& scale)
+{
+    switch (shapeType)
+    {
+    case SHAPE_TRIANGLEMESH:
+        {
+            TriangleMeshData* triMesh = static_cast<TriangleMeshData*>(geometry);
+            return new btScaledBvhTriangleMeshShape(triMesh->shape_.Get(), ToBtVector3(scale));
+        }
+    case SHAPE_CONVEXHULL:
+        {
+            ConvexData* convex = static_cast<ConvexData*>(geometry);
+            btConvexHullShape* shape = new btConvexHullShape((btScalar*)convex->vertexData_.Get(), convex->vertexCount_, sizeof(Vector3));
+            shape->setLocalScaling(ToBtVector3(scale));
+            return shape;
+        }
+    case SHAPE_GIMPACTMESH:
+        {
+            GImpactMeshData* gimpactMesh = static_cast<GImpactMeshData*>(geometry);
+            btGImpactMeshShape* shape = new btGImpactMeshShape(gimpactMesh->meshInterface_.Get());
+            shape->setLocalScaling(ToBtVector3(scale));
+            shape->updateBound();
+            return shape;
+        }
+    default:
+        return nullptr;
+    }
+}
+
 CollisionShape::CollisionShape(Context* context) :
     Component(context),
     shapeType_(SHAPE_BOX),
@@ -621,111 +680,37 @@ void CollisionShape::SetCone(float diameter, float height, const Vector3& positi
 void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position,
     const Quaternion& rotation)
 {
-    if (!model)
-    {
-        URHO3D_LOGERROR("Null model, can not set triangle mesh");
-        return;
-    }
-
-    if (model_)
-        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
-
-    shapeType_ = SHAPE_TRIANGLEMESH;
-    model_ = model;
-    lodLevel_ = lodLevel;
-    size_ = scale;
-    position_ = position;
-    rotation_ = rotation;
-    customGeometryID_ = 0;
-
-    UpdateShape();
-    NotifyRigidBody();
-    MarkNetworkUpdate();
+    SetModelShape(SHAPE_TRIANGLEMESH, model, lodLevel, scale, position, rotation);
 }
 
 void CollisionShape::SetCustomTriangleMesh(CustomGeometry* custom, const Vector3& scale, const Vector3& position,
     const Quaternion& rotation)
 {
-    if (!custom)
-    {
-        URHO3D_LOGERROR("Null custom geometry, can not set triangle mesh");
-        return;
-    }
-    if (custom->GetScene() != GetScene())
-    {
-        URHO3D_LOGERROR("Custom geometry is not in the same scene as the collision shape, can not set triangle mesh");
-        return;
-    }
-
-    if (model_)
-        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
-
-    shapeType_ = SHAPE_TRIANGLEMESH;
-    model_.Reset();
-    lodLevel_ = 0;
-    size_ = scale;
-    position_ = position;
-    rotation_ = rotation;
-    customGeometryID_ = custom->GetID();
-
-    UpdateShape();
-    NotifyRigidBody();
-    MarkNetworkUpdate();
+    SetCustomShape(SHAPE_TRIANGLEMESH, custom, scale, position, rotation);
 }
 
 void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position,
     const Quaternion& rotation)
 {
-    if (!model)
-    {
-        URHO3D_LOGERROR("Null model, can not set convex hull");
-        return;
-    }
-
-    if (model_)
-        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
-
-    shapeType_ = SHAPE_CONVEXHULL;
-    model_ = model;
-    lodLevel_ = lodLevel;
-    size_ = scale;
-    position_ = position;
-    rotation_ = rotation;
-    customGeometryID_ = 0;
-
-    UpdateShape();
-    NotifyRigidBody();
-    MarkNetworkUpdate();
+    SetModelShape(SHAPE_CONVEXHULL, model, lodLevel, scale, position, rotation);
 }
 
 void CollisionShape::SetCustomConvexHull(CustomGeometry* custom, const Vector3& scale, const Vector3& position,
     const Quaternion& rotation)
 {
-    if (!custom)
-    {
-        URHO3D_LOGERROR("Null custom geometry, can not set convex hull");
-        return;
-    }
-    if (custom->GetScene() != GetScene())
-    {
-        URHO3D_LOGERROR("Custom geometry is not in the same scene as the collision shape, can not set convex hull");
-        return;
-    }
-
-    if (model_)
-        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
+    SetCustomShape(SHAPE_CONVEXHULL, custom, scale, position, rotation);
+}
 
-    shapeType_ = SHAPE_CONVEXHULL;
-    model_.Reset();
-    lodLevel_ = 0;
-    size_ = scale;
-    position_ = position;
-    rotation_ = rotation;
-    customGeometryID_ = custom->GetID();
+void CollisionShape::SetGImpactMesh(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position,
+    const Quaternion& rotation)
+{
+    SetModelShape(SHAPE_GIMPACTMESH, model, lodLevel, scale, position, rotation);
+}
 
-    UpdateShape();
-    NotifyRigidBody();
-    MarkNetworkUpdate();
+void CollisionShape::SetCustomGImpactMesh(CustomGeometry* custom, const Vector3& scale, const Vector3& position,
+    const Quaternion& rotation)
+{
+    SetCustomShape(SHAPE_GIMPACTMESH, custom, scale, position, rotation);
 }
 
 void CollisionShape::SetTerrain(unsigned lodLevel)
@@ -1037,19 +1022,18 @@ void CollisionShape::UpdateShape()
 
     if (node_)
     {
-        Scene* scene = GetScene();
-        Vector3 newWorldScale = node_->GetWorldScale();
+        cachedWorldScale_ = node_->GetWorldScale();
 
         switch (shapeType_)
         {
         case SHAPE_BOX:
             shape_ = new btBoxShape(ToBtVector3(size_ * 0.5f));
-            shape_->setLocalScaling(ToBtVector3(newWorldScale));
+            shape_->setLocalScaling(ToBtVector3(cachedWorldScale_));
             break;
 
         case SHAPE_SPHERE:
             shape_ = new btSphereShape(size_.x_ * 0.5f);
-            shape_->setLocalScaling(ToBtVector3(newWorldScale));
+            shape_->setLocalScaling(ToBtVector3(cachedWorldScale_));
             break;
 
         case SHAPE_STATICPLANE:
@@ -1058,94 +1042,29 @@ void CollisionShape::UpdateShape()
 
         case SHAPE_CYLINDER:
             shape_ = new btCylinderShape(btVector3(size_.x_ * 0.5f, size_.y_ * 0.5f, size_.x_ * 0.5f));
-            shape_->setLocalScaling(ToBtVector3(newWorldScale));
+            shape_->setLocalScaling(ToBtVector3(cachedWorldScale_));
             break;
 
         case SHAPE_CAPSULE:
             shape_ = new btCapsuleShape(size_.x_ * 0.5f, Max(size_.y_ - size_.x_, 0.0f));
-            shape_->setLocalScaling(ToBtVector3(newWorldScale));
+            shape_->setLocalScaling(ToBtVector3(cachedWorldScale_));
             break;
 
         case SHAPE_CONE:
             shape_ = new btConeShape(size_.x_ * 0.5f, size_.y_);
-            shape_->setLocalScaling(ToBtVector3(newWorldScale));
+            shape_->setLocalScaling(ToBtVector3(cachedWorldScale_));
             break;
 
         case SHAPE_TRIANGLEMESH:
-            size_ = size_.Abs();
-            if (customGeometryID_ && scene)
-            {
-                CustomGeometry* custom = dynamic_cast<CustomGeometry*>(scene->GetComponent(customGeometryID_));
-                if (custom)
-                {
-                    geometry_ = new TriangleMeshData(custom);
-                    TriangleMeshData* triMesh = static_cast<TriangleMeshData*>(geometry_.Get());
-                    shape_ = new btScaledBvhTriangleMeshShape(triMesh->shape_.Get(), ToBtVector3(newWorldScale * size_));
-                }
-                else
-                    URHO3D_LOGWARNING("Could not find custom geometry component ID " + String(customGeometryID_) +
-                               " for triangle mesh shape creation");
-            }
-            else if (model_ && model_->GetNumGeometries())
-            {
-                // Check the geometry cache
-                Pair<Model*, unsigned> id = MakePair(model_.Get(), lodLevel_);
-                HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >& cache = physicsWorld_->GetTriMeshCache();
-                HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator j = cache.Find(id);
-                if (j != cache.End())
-                    geometry_ = j->second_;
-                else
-                {
-                    geometry_ = new TriangleMeshData(model_, lodLevel_);
-                    // Check if model has dynamic buffers, do not cache in that case
-                    if (!HasDynamicBuffers(model_, lodLevel_))
-                        cache[id] = geometry_;
-                }
-
-                TriangleMeshData* triMesh = static_cast<TriangleMeshData*>(geometry_.Get());
-                shape_ = new btScaledBvhTriangleMeshShape(triMesh->shape_.Get(), ToBtVector3(newWorldScale * size_));
-                // Watch for live reloads of the collision model to reload the geometry if necessary
-                SubscribeToEvent(model_, E_RELOADFINISHED, URHO3D_HANDLER(CollisionShape, HandleModelReloadFinished));
-            }
+            UpdateCachedGeometryShape(physicsWorld_->GetTriMeshCache());
             break;
 
         case SHAPE_CONVEXHULL:
-            size_ = size_.Abs();
-            if (customGeometryID_ && scene)
-            {
-                CustomGeometry* custom = dynamic_cast<CustomGeometry*>(scene->GetComponent(customGeometryID_));
-                if (custom)
-                {
-                    geometry_ = new ConvexData(custom);
-                    ConvexData* convex = static_cast<ConvexData*>(geometry_.Get());
-                    shape_ = new btConvexHullShape((btScalar*)convex->vertexData_.Get(), convex->vertexCount_, sizeof(Vector3));
-                    shape_->setLocalScaling(ToBtVector3(newWorldScale * size_));
-                }
-                else
-                    URHO3D_LOGWARNING("Could not find custom geometry component ID " + String(customGeometryID_) +
-                               " for convex shape creation");
-            }
-            else if (model_ && model_->GetNumGeometries())
-            {
-                // Check the geometry cache
-                Pair<Model*, unsigned> id = MakePair(model_.Get(), lodLevel_);
-                HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >& cache = physicsWorld_->GetConvexCache();
-                HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator j = cache.Find(id);
-                if (j != cache.End())
-                    geometry_ = j->second_;
-                else
-                {
-                    geometry_ = new ConvexData(model_, lodLevel_);
-                    // Check if model has dynamic buffers, do not cache in that case
-                    if (!HasDynamicBuffers(model_, lodLevel_))
-                        cache[id] = geometry_;
-                }
+            UpdateCachedGeometryShape(physicsWorld_->GetConvexCache());
+            break;
 
-                ConvexData* convex = static_cast<ConvexData*>(geometry_.Get());
-                shape_ = new btConvexHullShape((btScalar*)convex->vertexData_.Get(), convex->vertexCount_, sizeof(Vector3));
-                shape_->setLocalScaling(ToBtVector3(newWorldScale * size_));
-                SubscribeToEvent(model_, E_RELOADFINISHED, URHO3D_HANDLER(CollisionShape, HandleModelReloadFinished));
-            }
+        case SHAPE_GIMPACTMESH:
+            UpdateCachedGeometryShape(physicsWorld_->GetGImpactTrimeshCache());
             break;
 
         case SHAPE_TERRAIN:
@@ -1161,13 +1080,13 @@ void CollisionShape::UpdateShape()
                         new btHeightfieldTerrainShape(heightfield->size_.x_, heightfield->size_.y_, heightfield->heightData_.Get(),
                             1.0f, heightfield->minHeight_, heightfield->maxHeight_, 1, PHY_FLOAT, false);
                     shape_->setLocalScaling(
-                        ToBtVector3(Vector3(heightfield->spacing_.x_, 1.0f, heightfield->spacing_.z_) * newWorldScale * size_));
+                        ToBtVector3(Vector3(heightfield->spacing_.x_, 1.0f, heightfield->spacing_.z_) * cachedWorldScale_ * size_));
                 }
             }
             break;
 
         default:
-            shape_ = this->UpdateDerivedShape(shapeType_, newWorldScale);
+            shape_ = this->UpdateDerivedShape(shapeType_, cachedWorldScale_);
             break;
         }
 
@@ -1176,8 +1095,6 @@ void CollisionShape::UpdateShape()
             shape_->setUserPointer(this);
             shape_->setMargin(margin_);
         }
-
-        cachedWorldScale_ = newWorldScale;
     }
 
     if (physicsWorld_)
@@ -1187,13 +1104,108 @@ void CollisionShape::UpdateShape()
     retryCreation_ = false;
 }
 
+void CollisionShape::UpdateCachedGeometryShape(CollisionGeometryDataCache& cache)
+{
+    Scene* scene = GetScene();
+    size_ = size_.Abs();
+    if (customGeometryID_ && scene)
+    {
+        CustomGeometry* custom = dynamic_cast<CustomGeometry*>(scene->GetComponent(customGeometryID_));
+        if (custom)
+        {
+            geometry_ = CreateCollisionGeometryData(shapeType_, custom);
+            assert(geometry_);
+            shape_ = CreateCollisionGeometryDataShape(shapeType_, geometry_.Get(), cachedWorldScale_ * size_);
+            assert(shape_);
+        }
+        else
+            URHO3D_LOGWARNING("Could not find custom geometry component ID " + String(customGeometryID_) +
+                " for collision shape creation");
+    }
+    else if (model_ && model_->GetNumGeometries())
+    {
+        // Check the geometry cache
+        Pair<Model*, unsigned> id = MakePair(model_.Get(), lodLevel_);
+        auto cachedGeometry = cache.Find(id);
+        if (cachedGeometry != cache.End())
+            geometry_ = cachedGeometry->second_;
+        else
+        {
+            geometry_ = CreateCollisionGeometryData(shapeType_, model_, lodLevel_);
+            assert(geometry_);
+            // Check if model has dynamic buffers, do not cache in that case
+            if (!HasDynamicBuffers(model_, lodLevel_))
+                cache[id] = geometry_;
+        }
+
+        shape_ = CreateCollisionGeometryDataShape(shapeType_, geometry_.Get(), cachedWorldScale_ * size_);
+        assert(shape_);
+        // Watch for live reloads of the collision model to reload the geometry if necessary
+        SubscribeToEvent(model_, E_RELOADFINISHED, URHO3D_HANDLER(CollisionShape, HandleModelReloadFinished));
+    }
+}
+
+void CollisionShape::SetModelShape(ShapeType shapeType, Model* model, unsigned lodLevel,
+    const Vector3& scale, const Vector3& position, const Quaternion& rotation)
+{
+    if (!model)
+    {
+        URHO3D_LOGERROR("Null model, can not set collsion shape");
+        return;
+    }
+
+    if (model_)
+        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
+
+    shapeType_ = shapeType;
+    model_ = model;
+    lodLevel_ = lodLevel;
+    size_ = scale;
+    position_ = position;
+    rotation_ = rotation;
+    customGeometryID_ = 0;
+
+    UpdateShape();
+    NotifyRigidBody();
+    MarkNetworkUpdate();
+}
+
+void CollisionShape::SetCustomShape(ShapeType shapeType, CustomGeometry* custom,
+    const Vector3& scale, const Vector3& position, const Quaternion& rotation)
+{
+    if (!custom)
+    {
+        URHO3D_LOGERROR("Null custom geometry, can not set collsion shape");
+        return;
+    }
+    if (custom->GetScene() != GetScene())
+    {
+        URHO3D_LOGERROR("Custom geometry is not in the same scene as the collision shape, can not set collsion shape");
+        return;
+    }
+
+    if (model_)
+        UnsubscribeFromEvent(model_, E_RELOADFINISHED);
+
+    shapeType_ = shapeType;
+    model_.Reset();
+    lodLevel_ = 0;
+    size_ = scale;
+    position_ = position;
+    rotation_ = rotation;
+    customGeometryID_ = custom->GetID();
+
+    UpdateShape();
+    NotifyRigidBody();
+    MarkNetworkUpdate();
+}
+
 btCollisionShape* CollisionShape::UpdateDerivedShape(int shapeType, const Vector3& newWorldScale)
 {
     // To be overridden in derived classes.
     return nullptr;
 }
 
-
 void CollisionShape::HandleTerrainCreated(StringHash eventType, VariantMap& eventData)
 {
     if (shapeType_ == SHAPE_TERRAIN)

+ 40 - 19
Source/Urho3D/Physics/CollisionShape.h

@@ -30,6 +30,7 @@
 class btBvhTriangleMeshShape;
 class btCollisionShape;
 class btCompoundShape;
+class btGImpactMeshShape;
 class btTriangleMesh;
 
 struct btTriangleInfoMap;
@@ -56,7 +57,8 @@ enum ShapeType
     SHAPE_CONE,
     SHAPE_TRIANGLEMESH,
     SHAPE_CONVEXHULL,
-    SHAPE_TERRAIN
+    SHAPE_TERRAIN,
+    SHAPE_GIMPACTMESH
 };
 
 /// Base class for collision shape geometry data.
@@ -64,6 +66,10 @@ struct CollisionGeometryData : public RefCounted
 {
 };
 
+/// Cache of collision geometry data.
+/// \todo Remove duplicate declaration
+using CollisionGeometryDataCache = HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >;
+
 /// Triangle mesh geometry data.
 struct TriangleMeshData : public CollisionGeometryData
 {
@@ -71,8 +77,6 @@ struct TriangleMeshData : public CollisionGeometryData
     TriangleMeshData(Model* model, unsigned lodLevel);
     /// Construct from a custom geometry.
     TriangleMeshData(CustomGeometry* custom);
-    /// Destruct. Free geometry data.
-    virtual ~TriangleMeshData() override;
 
     /// Bullet triangle mesh interface.
     UniquePtr<TriangleMeshInterface> meshInterface_;
@@ -82,6 +86,18 @@ struct TriangleMeshData : public CollisionGeometryData
     UniquePtr<btTriangleInfoMap> infoMap_;
 };
 
+/// Triangle mesh geometry data.
+struct GImpactMeshData : public CollisionGeometryData
+{
+    /// Construct from a model.
+    GImpactMeshData(Model* model, unsigned lodLevel);
+    /// Construct from a custom geometry.
+    GImpactMeshData(CustomGeometry* custom);
+
+    /// Bullet triangle mesh interface.
+    UniquePtr<TriangleMeshInterface> meshInterface_;
+};
+
 /// Convex hull geometry data.
 struct ConvexData : public CollisionGeometryData
 {
@@ -89,8 +105,6 @@ struct ConvexData : public CollisionGeometryData
     ConvexData(Model* model, unsigned lodLevel);
     /// Construct from a custom geometry.
     ConvexData(CustomGeometry* custom);
-    /// Destruct. Free geometry data.
-    virtual ~ConvexData() override;
 
     /// Build the convex hull from vertices.
     void BuildHull(const PODVector<Vector3>& vertices);
@@ -110,8 +124,6 @@ struct HeightfieldData : public CollisionGeometryData
 {
     /// Construct from a terrain.
     HeightfieldData(Terrain* terrain, unsigned lodLevel);
-    /// Destruct. Free geometry data.
-    virtual ~HeightfieldData() override;
 
     /// Height data. On LOD level 0 the original height data will be used.
     SharedArrayPtr<float> heightData_;
@@ -154,28 +166,29 @@ public:
     /// Set as a static plane.
     void SetStaticPlane(const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a cylinder.
-    void SetCylinder
-        (float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetCylinder(float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a capsule.
-    void SetCapsule
-        (float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetCapsule(float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a cone.
-    void SetCone
-        (float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetCone(float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a triangle mesh from Model. If you update a model's geometry and want to reapply the shape, call physicsWorld->RemoveCachedGeometry(model) first.
-    void SetTriangleMesh
-        (Model* model, unsigned lodLevel = 0, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
-            const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetTriangleMesh(Model* model, unsigned lodLevel = 0, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
+        const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a triangle mesh from CustomGeometry.
     void SetCustomTriangleMesh(CustomGeometry* custom, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
         const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a convex hull from Model.
-    void SetConvexHull
-        (Model* model, unsigned lodLevel = 0, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
-            const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetConvexHull(Model* model, unsigned lodLevel = 0, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
+        const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a convex hull from CustomGeometry.
     void SetCustomConvexHull(CustomGeometry* custom, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
         const Quaternion& rotation = Quaternion::IDENTITY);
+    /// Set as a triangle mesh from Model. If you update a model's geometry and want to reapply the shape, call physicsWorld->RemoveCachedGeometry(model) first.
+    void SetGImpactMesh(Model* model, unsigned lodLevel = 0, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
+        const Quaternion& rotation = Quaternion::IDENTITY);
+    /// Set as a triangle mesh from CustomGeometry.
+    void SetCustomGImpactMesh(CustomGeometry* custom, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO,
+        const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a terrain. Only works if the same scene node contains a Terrain component.
     void SetTerrain(unsigned lodLevel = 0);
     /// Set shape type.
@@ -258,6 +271,14 @@ private:
     btCompoundShape* GetParentCompoundShape();
     /// Update the collision shape after attribute changes.
     void UpdateShape();
+    /// Update cached geometry collision shape.
+    void UpdateCachedGeometryShape(CollisionGeometryDataCache& cache);
+    /// Set as specified shape type using model and LOD.
+    void SetModelShape(ShapeType shapeType, Model* model, unsigned lodLevel,
+        const Vector3& scale, const Vector3& position, const Quaternion& rotation);
+    /// Set as specified shape type using CustomGeometry.
+    void SetCustomShape(ShapeType shapeType, CustomGeometry* custom,
+        const Vector3& scale, const Vector3& position, const Quaternion& rotation);
     /// Update terrain collision shape from the terrain component.
     void HandleTerrainCreated(StringHash eventType, VariantMap& eventData);
     /// Update trimesh or convex shape after a model has reloaded itself.

+ 29 - 30
Source/Urho3D/Physics/PhysicsWorld.cpp

@@ -44,6 +44,7 @@
 #include <Bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
 #include <Bullet/BulletCollision/CollisionShapes/btBoxShape.h>
 #include <Bullet/BulletCollision/CollisionShapes/btSphereShape.h>
+#include <Bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>
 #include <Bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
 #include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
 
@@ -88,6 +89,26 @@ static bool CustomMaterialCombinerCallback(btManifoldPoint& cp, const btCollisio
     return true;
 }
 
+void RemoveCachedGeometryImpl(CollisionGeometryDataCache& triMeshCache_, Model* model)
+{
+    for (auto i = triMeshCache_.Begin(); i != triMeshCache_.End();)
+    {
+        auto current = i++;
+        if (current->first_.first_ == model)
+            triMeshCache_.Erase(current);
+    }
+}
+
+void CleanupGeometryCacheImpl(CollisionGeometryDataCache& triMeshCache_)
+{
+    for (auto i = triMeshCache_.Begin(); i != triMeshCache_.End();)
+    {
+        auto current = i++;
+        if (current->second_.Refs() == 1)
+            triMeshCache_.Erase(current);
+    }
+}
+
 /// Callback for physics world queries.
 struct PhysicsQueryCallback : public btCollisionWorld::ContactResultCallback
 {
@@ -117,7 +138,6 @@ struct PhysicsQueryCallback : public btCollisionWorld::ContactResultCallback
     unsigned collisionMask_;
 };
 
-
 PhysicsWorld::PhysicsWorld(Context* context) :
     Component(context),
     collisionConfiguration_(nullptr),
@@ -141,6 +161,8 @@ PhysicsWorld::PhysicsWorld(Context* context) :
         collisionConfiguration_ = new btDefaultCollisionConfiguration();
 
     collisionDispatcher_ = new btCollisionDispatcher(collisionConfiguration_);
+    btGImpactCollisionAlgorithm::registerAlgorithm(static_cast<btCollisionDispatcher*>(collisionDispatcher_.Get()));
+
     broadphase_ = new btDbvtBroadphase();
     solver_ = new btSequentialImpulseConstraintSolver();
     world_ = new btDiscreteDynamicsWorld(collisionDispatcher_.Get(), broadphase_.Get(), solver_.Get(), collisionConfiguration_);
@@ -154,7 +176,6 @@ PhysicsWorld::PhysicsWorld(Context* context) :
     world_->setSynchronizeAllMotionStates(true);
 }
 
-
 PhysicsWorld::~PhysicsWorld()
 {
     if (scene_)
@@ -591,20 +612,9 @@ void PhysicsWorld::ConvexCast(PhysicsRaycastResult& result, btCollisionShape* sh
 
 void PhysicsWorld::RemoveCachedGeometry(Model* model)
 {
-    for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = triMeshCache_.Begin();
-         i != triMeshCache_.End();)
-    {
-        HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
-        if (current->first_.first_ == model)
-            triMeshCache_.Erase(current);
-    }
-    for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = convexCache_.Begin();
-         i != convexCache_.End();)
-    {
-        HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
-        if (current->first_.first_ == model)
-            convexCache_.Erase(current);
-    }
+    RemoveCachedGeometryImpl(triMeshCache_, model);
+    RemoveCachedGeometryImpl(convexCache_, model);
+    RemoveCachedGeometryImpl(gimpactTrimeshCache_, model);
 }
 
 void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const Sphere& sphere, unsigned collisionMask)
@@ -760,20 +770,9 @@ void PhysicsWorld::SetDebugDepthTest(bool enable)
 void PhysicsWorld::CleanupGeometryCache()
 {
     // Remove cached shapes whose only reference is the cache itself
-    for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = triMeshCache_.Begin();
-         i != triMeshCache_.End();)
-    {
-        HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
-        if (current->second_.Refs() == 1)
-            triMeshCache_.Erase(current);
-    }
-    for (HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator i = convexCache_.Begin();
-         i != convexCache_.End();)
-    {
-        HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >::Iterator current = i++;
-        if (current->second_.Refs() == 1)
-            convexCache_.Erase(current);
-    }
+    CleanupGeometryCacheImpl(triMeshCache_);
+    CleanupGeometryCacheImpl(convexCache_);
+    CleanupGeometryCacheImpl(gimpactTrimeshCache_);
 }
 
 void PhysicsWorld::OnSceneSet(Scene* scene)

+ 12 - 4
Source/Urho3D/Physics/PhysicsWorld.h

@@ -126,6 +126,9 @@ struct PhysicsWorldConfig
 
 static const float DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY = 100.0f;
 
+/// Cache of collision geometry data.
+using CollisionGeometryDataCache = HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >;
+
 /// Physics simulation world component. Should be added only to the root scene node.
 class URHO3D_API PhysicsWorld : public Component, public btIDebugDraw
 {
@@ -267,10 +270,13 @@ public:
     void CleanupGeometryCache();
 
     /// Return trimesh collision geometry cache.
-    HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >& GetTriMeshCache() { return triMeshCache_; }
+    CollisionGeometryDataCache& GetTriMeshCache() { return triMeshCache_; }
 
     /// Return convex collision geometry cache.
-    HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> >& GetConvexCache() { return convexCache_; }
+    CollisionGeometryDataCache& GetConvexCache() { return convexCache_; }
+
+    /// Return GImpact trimesh collision geometry cache.
+    CollisionGeometryDataCache& GetGImpactTrimeshCache() { return gimpactTrimeshCache_; }
 
     /// Set node dirtying to be disregarded.
     void SetApplyingTransforms(bool enable) { applyingTransforms_ = enable; }
@@ -323,9 +329,11 @@ private:
     /// Delayed (parented) world transform assignments.
     HashMap<RigidBody*, DelayedWorldTransform> delayedWorldTransforms_;
     /// Cache for trimesh geometry data by model and LOD level.
-    HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> > triMeshCache_;
+    CollisionGeometryDataCache triMeshCache_;
     /// Cache for convex geometry data by model and LOD level.
-    HashMap<Pair<Model*, unsigned>, SharedPtr<CollisionGeometryData> > convexCache_;
+    CollisionGeometryDataCache convexCache_;
+    /// Cache for GImpact trimesh geometry data by model and LOD level.
+    CollisionGeometryDataCache gimpactTrimeshCache_;
     /// Preallocated event data map for physics collision events.
     VariantMap physicsCollisionData_;
     /// Preallocated event data map for node collision events.