Browse Source

Added LOD level attribute support to Terrain collision shape & SetTerrain() function. This works like mipmap levels: each successive LOD level halves the resolution. Closes #639.

Lasse Öörni 11 years ago
parent
commit
c2535edac3

+ 1 - 1
Source/Urho3D/LuaScript/pkgs/Physics/CollisionShape.pkg

@@ -25,7 +25,7 @@ class CollisionShape : public Component
     void SetCustomTriangleMesh(CustomGeometry* custom, 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);
     void SetCustomConvexHull(CustomGeometry* custom, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
-    void SetTerrain();
+    void SetTerrain(unsigned lodLevel = 0);
     void SetShapeType(ShapeType type);
     void SetSize(const Vector3& size);
     void SetPosition(const Vector3& position);

+ 37 - 3
Source/Urho3D/Physics/CollisionShape.cpp

@@ -305,7 +305,7 @@ ConvexData::~ConvexData()
 {
 }
 
-HeightfieldData::HeightfieldData(Terrain* terrain) :
+HeightfieldData::HeightfieldData(Terrain* terrain, unsigned lodLevel) :
     heightData_(terrain->GetHeightData()),
     spacing_(terrain->GetSpacing()),
     size_(terrain->GetNumVertices()),
@@ -314,6 +314,39 @@ HeightfieldData::HeightfieldData(Terrain* terrain) :
 {
     if (heightData_)
     {
+        if (lodLevel > 0)
+        {
+            IntVector2 lodSize = size_;
+            Vector3 lodSpacing = spacing_;
+            unsigned skip = 1;
+
+            for (unsigned i = 0; i < lodLevel; ++i)
+            {
+                skip *= 2;
+                lodSpacing.x_ *= 2.0f;
+                lodSpacing.z_ *= 2.0f;
+                int rX = lodSize.x_ & 1;
+                int rY = lodSize.y_ & 1;
+                lodSize.x_ >>= 1;
+                lodSize.y_ >>= 1;
+                lodSize.x_ += rX;
+                lodSize.y_ += rY;
+                if (lodSize.x_ <= 2 || lodSize.y_ <= 2)
+                    break;
+            }
+            
+            SharedArrayPtr<float> lodHeightData(new float[lodSize.x_ * lodSize.y_]);
+            for (int y = 0, dY = 0; y < size_.y_ && dY < lodSize.y_; y += skip, ++dY)
+            {
+                for (int x = 0, dX = 0; x < size_.x_ && dX < lodSize.x_; x += skip, ++dX)
+                    lodHeightData[dY * lodSize.x_ + dX] = heightData_[y * size_.x_ + x];
+            }
+
+            size_ = lodSize;
+            spacing_ = lodSpacing;
+            heightData_ = lodHeightData;
+        }
+
         unsigned points = size_.x_ * size_.y_;
         float* data = heightData_.Get();
 
@@ -662,7 +695,7 @@ void CollisionShape::SetCustomConvexHull(CustomGeometry* custom, const Vector3&
     MarkNetworkUpdate();
 }
 
-void CollisionShape::SetTerrain()
+void CollisionShape::SetTerrain(unsigned lodLevel)
 {
     Terrain* terrain = GetComponent<Terrain>();
     if (!terrain)
@@ -675,6 +708,7 @@ void CollisionShape::SetTerrain()
         UnsubscribeFromEvent(model_, E_RELOADFINISHED);
 
     shapeType_ = SHAPE_TERRAIN;
+    lodLevel_ = lodLevel;
 
     UpdateShape();
     NotifyRigidBody();
@@ -1066,7 +1100,7 @@ void CollisionShape::UpdateShape()
                 Terrain* terrain = GetComponent<Terrain>();
                 if (terrain && terrain->GetHeightData())
                 {
-                    geometry_ = new HeightfieldData(terrain);
+                    geometry_ = new HeightfieldData(terrain, lodLevel_);
                     HeightfieldData* heightfield = static_cast<HeightfieldData*>(geometry_.Get());
 
                     shape_ = new btHeightfieldTerrainShape(heightfield->size_.x_, heightfield->size_.y_,

+ 3 - 3
Source/Urho3D/Physics/CollisionShape.h

@@ -109,11 +109,11 @@ struct ConvexData : public CollisionGeometryData
 struct HeightfieldData : public CollisionGeometryData
 {
     /// Construct from a terrain.
-    HeightfieldData(Terrain* terrain);
+    HeightfieldData(Terrain* terrain, unsigned lodLevel);
     /// Destruct. Free geometry data.
     ~HeightfieldData();
 
-    /// Height data.
+    /// Height data. On LOD level 0 the original height data will be used.
     SharedArrayPtr<float> heightData_;
     /// Vertex spacing.
     Vector3 spacing_;
@@ -168,7 +168,7 @@ public:
     /// 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();
+    void SetTerrain(unsigned lodLevel = 0);
     /// Set shape type.
     void SetShapeType(ShapeType type);
     /// Set shape size.

+ 1 - 1
Source/Urho3D/Script/PhysicsAPI.cpp

@@ -85,7 +85,7 @@ static void RegisterCollisionShape(asIScriptEngine* engine)
     engine->RegisterObjectMethod("CollisionShape", "void SetCustomTriangleMesh(CustomGeometry@+, const Vector3&in scale = Vector3(1, 1, 1), const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCustomTriangleMesh), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetConvexHull(Model@+, uint lodLevel = 0, 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 SetTerrain(uint lodLevel = 0)", 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);
     engine->RegisterObjectMethod("CollisionShape", "ShapeType get_shapeType() const", asMETHOD(CollisionShape, GetShapeType), asCALL_THISCALL);