浏览代码

Applied CustomGeometry convex hull collision patch from Pete Leigh, with added serialization support.

Lasse Öörni 12 年之前
父节点
当前提交
1d2fec862c

+ 1 - 0
Docs/ScriptAPI.dox

@@ -5604,6 +5604,7 @@ Methods:<br>
 - void SetCone(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - void SetTriangleMesh(Model@, uint, const Vector3& arg2 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg3 = Vector3 ( ), const Quaternion& arg4 = Quaternion ( ))
 - void SetConvexHull(Model@, uint, const Vector3& arg2 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg3 = Vector3 ( ), const Quaternion& arg4 = Quaternion ( ))
+- void SetCustomConvexHull(CustomGeometry@, const Vector3& arg1 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - void SetTerrain()
 - void SetTransform(const Vector3&, const Quaternion&)
 

+ 1 - 0
Docs/Urho3D.dox

@@ -56,6 +56,7 @@ Urho3D development, contributions and bugfixes by:
 - Alex Fuller
 - Mika Heinonen
 - Jason Kinzer
+- Pete Leigh
 - Vladimir Pobedinsky
 - Miika Santala
 - Firegorilla

+ 1 - 0
Engine/Engine/PhysicsAPI.cpp

@@ -77,6 +77,7 @@ static void RegisterCollisionShape(asIScriptEngine* engine)
     engine->RegisterObjectMethod("CollisionShape", "void SetCone(float, float, const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCone), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetTriangleMesh(Model@+, uint, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetTriangleMesh), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetConvexHull(Model@+, uint, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetConvexHull), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CollisionShape", "void SetCustomConvexHull(CustomGeometry@+, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCustomConvexHull), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetTerrain()", asMETHOD(CollisionShape, SetTerrain), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetTransform(const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetTransform), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void set_shapeType(ShapeType)", asMETHOD(CollisionShape, SetShapeType), asCALL_THISCALL);

+ 2 - 0
Engine/Graphics/CustomGeometry.h

@@ -42,6 +42,8 @@ struct CustomGeometryVertex
     Vector4 tangent_;
 };
 
+class VertexBuffer;
+
 /// Custom geometry component.
 class CustomGeometry : public Drawable
 {

+ 109 - 6
Engine/Physics/CollisionShape.cpp

@@ -23,6 +23,7 @@
 #include "Precompiled.h"
 #include "CollisionShape.h"
 #include "Context.h"
+#include "CustomGeometry.h"
 #include "DebugRenderer.h"
 #include "DrawableEvents.h"
 #include "Geometry.h"
@@ -152,7 +153,7 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
 {
     modelName_ = model->GetName();
     
-    PODVector<Vector3> originalVertices;
+    PODVector<Vector3> vertices;
     unsigned numGeometries = model->GetNumGeometries();
     
     for (unsigned i = 0; i < numGeometries; ++i)
@@ -184,17 +185,63 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
         for (unsigned j = 0; j < vertexCount; ++j)
         {
             const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
-            originalVertices.Push(v);
+            vertices.Push(v);
         }
     }
     
-    if (originalVertices.Size())
+    BuildHull(vertices);
+}
+
+ConvexData::ConvexData(CustomGeometry* custom)
+{
+    PODVector<Vector3> vertices;
+    unsigned numGeometries = custom->GetNumGeometries();
+    
+    for (unsigned i = 0; i < numGeometries; ++i)
+    {
+        Geometry* geom = custom->GetLodGeometry(i, 0);
+        if (!geom)
+        {
+            LOGWARNING("Skipping null geometry for convex hull collision");
+            continue;
+        }
+        
+        const unsigned char* vertexData;
+        const unsigned char* indexData;
+        unsigned vertexSize;
+        unsigned indexSize;
+        unsigned elementMask;
+        
+        geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+        if (!vertexData)
+        {
+            LOGWARNING("Skipping geometry with no CPU-side geometry data for convex hull collision - no vertex data");
+            continue;
+        }
+        
+        unsigned vertexStart = geom->GetVertexStart();
+        unsigned vertexCount = geom->GetVertexCount();
+        
+        // Copy vertex data
+        for (unsigned j = 0; j < vertexCount; ++j)
+        {
+            const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
+            vertices.Push(v);
+        }
+    }
+    
+    BuildHull(vertices);
+}
+
+void ConvexData::BuildHull(const PODVector<Vector3>& vertices)
+{
+    if (vertices.Size())
     {
         // Build the convex hull from the raw geometry
         StanHull::HullDesc desc;
         desc.SetHullFlag(StanHull::QF_TRIANGLES);
-        desc.mVcount = originalVertices.Size();
-        desc.mVertices = originalVertices[0].Data();
+        desc.mVcount = vertices.Size();
+        desc.mVertices = vertices[0].Data();
         desc.mVertexStride = 3 * sizeof(float);
         desc.mSkinWidth = 0.0f;
         
@@ -215,9 +262,14 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
         lib.ReleaseResult(result);
     }
     else
+    {
         vertexCount_ = 0;
+        indexCount_ = 0;
+    }
 }
 
+
+
 ConvexData::~ConvexData()
 {
 }
@@ -258,6 +310,7 @@ CollisionShape::CollisionShape(Context* context) :
     size_(Vector3::ONE),
     cachedWorldScale_(Vector3::ONE),
     lodLevel_(0),
+    customGeometryID_(0),
     margin_(DEFAULT_COLLISION_MARGIN),
     recreateShape_(true)
 {
@@ -283,6 +336,7 @@ void CollisionShape::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(CollisionShape, VAR_RESOURCEREF, "Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(CollisionShape, VAR_INT, "LOD Level", lodLevel_, 0, AM_DEFAULT);
     ATTRIBUTE(CollisionShape, VAR_FLOAT, "Collision Margin", margin_, DEFAULT_COLLISION_MARGIN, AM_DEFAULT);
+    ATTRIBUTE(CollisionShape, VAR_INT, "CustomGeometry NodeID", customGeometryID_, 0, AM_DEFAULT | AM_NODEID);
 }
 
 void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
@@ -353,6 +407,7 @@ void CollisionShape::SetBox(const Vector3& size, const Vector3& position, const
     position_ = position;
     rotation_ = rotation;
     model_.Reset();
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -366,6 +421,7 @@ void CollisionShape::SetSphere(float diameter, const Vector3& position, const Qu
     position_ = position;
     rotation_ = rotation;
     model_.Reset();
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -379,6 +435,7 @@ void CollisionShape::SetCylinder(float diameter, float height, const Vector3& po
     position_ = position;
     rotation_ = rotation;
     model_.Reset();
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -392,6 +449,7 @@ void CollisionShape::SetCapsule(float diameter, float height, const Vector3& pos
     position_ = position;
     rotation_ = rotation;
     model_.Reset();
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -405,6 +463,7 @@ void CollisionShape::SetCone(float diameter, float height, const Vector3& positi
     position_ = position;
     rotation_ = rotation;
     model_.Reset();
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -425,6 +484,7 @@ void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vect
     size_ = scale;
     position_ = position;
     rotation_ = rotation;
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
@@ -445,12 +505,40 @@ void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector
     size_ = scale;
     position_ = position;
     rotation_ = rotation;
+    customGeometryID_ = 0;
     
     UpdateShape();
     NotifyRigidBody();
     MarkNetworkUpdate();
 }
 
+void CollisionShape::SetCustomConvexHull(CustomGeometry* custom, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
+{
+    if (!custom)
+    {
+        LOGERROR("Null custom geometry, can not set convex hull");
+        return;
+    }
+    if (!custom->GetNode())
+    {
+        LOGERROR("Custom geometry has null scene node, can not set convex hull");
+        return;
+    }
+    
+    shapeType_ = SHAPE_CONVEXHULL;
+    model_.Reset();
+    lodLevel_ = 0;
+    size_ = scale;
+    position_ = position;
+    rotation_ = rotation;
+    customGeometryID_ = custom->GetNode()->GetID();
+    
+    UpdateShape();
+    NotifyRigidBody();
+    MarkNetworkUpdate();
+}
+
+
 void CollisionShape::SetTerrain()
 {
     Terrain* terrain = GetComponent<Terrain>();
@@ -790,7 +878,22 @@ void CollisionShape::UpdateShape()
             
         case SHAPE_CONVEXHULL:
             size_ = size_.Abs();
-            if (model_)
+            if (customGeometryID_ && GetScene())
+            {
+                Node* node = GetScene()->GetNode(customGeometryID_);
+                CustomGeometry* custom = node ? node->GetComponent<CustomGeometry>() : 0;
+                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_));
+                    LOGINFO("Set convexhull from customgeometry");
+                }
+                else
+                    LOGWARNING("Could not find custom geometry component from node ID " + String(customGeometryID_) + " for convex shape creation");
+            }
+            else if (model_)
             {
                 // Check the geometry cache
                 String id = "Convex_" + model_->GetName() + "_" + String(lodLevel_);

+ 12 - 2
Engine/Physics/CollisionShape.h

@@ -35,6 +35,7 @@ class btTriangleMesh;
 namespace Urho3D
 {
 
+class CustomGeometry;
 class Geometry;
 class Model;
 class PhysicsWorld;
@@ -81,9 +82,14 @@ struct ConvexData : public CollisionGeometryData
 {
     /// Construct from a model.
     ConvexData(Model* model, unsigned lodLevel);
+    /// Construct from a custom geometry.
+    ConvexData(CustomGeometry* custom);
     /// Destruct. Free geometry data.
     ~ConvexData();
     
+    /// Build the convex hull from vertices.
+    void BuildHull(const PODVector<Vector3>& vertices);
+    
     /// Vertex data.
     SharedArrayPtr<Vector3> vertexData_;
     /// Number of vertices.
@@ -144,12 +150,14 @@ public:
     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);
-   /// Set as a cone.
+    /// Set as a cone.
     void SetCone(float diameter, float height, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a triangle mesh.
     void SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
-    /// Set as a convex hull.
+    /// Set as a convex hull from Model.
     void SetConvexHull(Model* model, unsigned lodLevel, 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 terrain. Only works if the same scene node contains a Terrain component.
     void SetTerrain();
     /// Set shape type.
@@ -237,6 +245,8 @@ private:
     Vector3 cachedWorldScale_;
     /// Model LOD level.
     unsigned lodLevel_;
+    /// CustomGeometry component ID for convex hull mode. 0 if not creating the convex hull from a CustomGeometry.
+    int customGeometryID_;
     /// Collision margin.
     float margin_;
     /// Recrease collision shape flag.

+ 1 - 0
Readme.txt

@@ -18,6 +18,7 @@ Urho3D development, contributions and bugfixes by:
 - Alex Fuller
 - Mika Heinonen
 - Jason Kinzer
+- Pete Leigh
 - Vladimir Pobedinsky
 - Miika Santala
 - Firegorilla