Ver código fonte

Added RigidBody::ReAddBodyToWorld().
Added heightfield smoothing attribute.
Allow CollisionShape::SetTriangleMesh() & SetConvexHull() without specifying LOD level (0 is default)
Refactored Vehicle example and increased vehicle speed.

Lasse Öörni 12 anos atrás
pai
commit
27b31af0cf

+ 2 - 2
Bin/Data/Scripts/Navigation.as

@@ -177,7 +177,7 @@ void InitScene()
 
         RigidBody@ body = objectNode.CreateComponent("RigidBody");
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(object.model, 0);
+        shape.SetTriangleMesh(object.model);
     }
 
     testScene.CreateComponent("Navigable");
@@ -424,7 +424,7 @@ void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
 
                 RigidBody@ body = objectNode.CreateComponent("RigidBody");
                 CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-                shape.SetTriangleMesh(object.model, 0);
+                shape.SetTriangleMesh(object.model);
 
                 rebuild = true;
                 rebuildBox = object.worldBoundingBox;

+ 1 - 1
Bin/Data/Scripts/Physics.as

@@ -173,7 +173,7 @@ void InitScene()
 
         RigidBody@ body = objectNode.CreateComponent("RigidBody");
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
+        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"));
     }
 }
 

+ 2 - 1
Bin/Data/Scripts/Terrain.as

@@ -135,6 +135,7 @@ void InitScene()
         terrain = terrainNode.CreateComponent("Terrain");
         terrain.patchSize = 64;
         terrain.spacing = Vector3(2, 0.5, 2);
+        terrain.smoothing = true;
         terrain.heightMap = cache.GetResource("Image", "Textures/HeightMap.png");
         terrain.material = cache.GetResource("Material", "Materials/Terrain.xml");
         terrain.occluder = true;
@@ -162,7 +163,7 @@ void InitScene()
 
         RigidBody@ body = objectNode.CreateComponent("RigidBody");
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
+        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"));
     }
 }
 

+ 1 - 1
Bin/Data/Scripts/TestScene.as

@@ -186,7 +186,7 @@ void InitScene()
 
         RigidBody@ body = objectNode.CreateComponent("RigidBody");
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(object.model, 0);
+        shape.SetTriangleMesh(object.model);
     }
 
     for (uint i = 0; i < 50; ++i)

+ 1 - 1
Bin/Data/Scripts/TestSceneOld.as

@@ -126,7 +126,7 @@ void InitScene()
 
         RigidBody@ body = newNode.CreateComponent("RigidBody");
         CollisionShape@ shape = newNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(object.model, 0);
+        shape.SetTriangleMesh(object.model);
     }
 
     // Create mushroom groups

+ 69 - 77
Bin/Data/Scripts/Vehicle.as

@@ -1,7 +1,7 @@
 Scene@ testScene;
 Camera@ camera;
 Node@ cameraNode;
-Node@ vehicleHullNode;
+Node@ vehicleNode;
 
 float yaw = 0.0;
 float pitch = 0.0;
@@ -18,7 +18,6 @@ void Start()
         OpenConsoleWindow();
 
     InitScene();
-    InitVehicle();
 
     SubscribeToEvent("Update", "HandleUpdate");
     SubscribeToEvent("PostUpdate", "HandlePostUpdate");
@@ -103,6 +102,7 @@ void InitScene()
         terrain = terrainNode.CreateComponent("Terrain");
         terrain.patchSize = 64;
         terrain.spacing = Vector3(2, 0.1, 2);
+        terrain.smoothing = true;
         terrain.heightMap = cache.GetResource("Image", "Textures/HeightMap.png");
         terrain.material = cache.GetResource("Material", "Materials/Terrain.xml");
         terrain.occluder = true;
@@ -111,7 +111,6 @@ void InitScene()
         body.collisionLayer = 2;
         CollisionShape@ shape = terrainNode.CreateComponent("CollisionShape");
         shape.SetTerrain();
-        shape.margin = 0.01;
     }
 
     for (uint i = 0; i < 1000; ++i)
@@ -132,8 +131,14 @@ void InitScene()
         RigidBody@ body = objectNode.CreateComponent("RigidBody");
         body.collisionLayer = 2;
         CollisionShape@ shape = objectNode.CreateComponent("CollisionShape");
-        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"), 0);
+        shape.SetTriangleMesh(cache.GetResource("Model", "Models/Mushroom.mdl"));
     }
+
+    vehicleNode = testScene.CreateChild("VehicleHull");
+    vehicleNode.position = Vector3(0, 5, 0);
+
+    Vehicle@ vehicle = cast<Vehicle>(vehicleNode.CreateScriptObject(scriptFile, "Vehicle"));
+    vehicle.Init();
 }
 
 void HandleUpdate(StringHash eventType, VariantMap& eventData)
@@ -148,12 +153,12 @@ void HandlePostUpdate(StringHash eventType, VariantMap& eventData)
     float timeStep = eventData["TimeStep"].GetFloat();
 
     // Physics update has completed. Position camera behind vehicle
-    Quaternion dir(vehicleHullNode.rotation.yaw, Vector3(0, 1, 0));;
+    Quaternion dir(vehicleNode.rotation.yaw, Vector3(0, 1, 0));;
     dir = dir * Quaternion(yaw, Vector3(0, 1, 0));
     dir = dir * Quaternion(pitch, Vector3(1, 0, 0));
 
-    Vector3 cameraTargetPos = vehicleHullNode.position - dir * Vector3(0, 0, 10);
-    Vector3 cameraStartPos = vehicleHullNode.position;
+    Vector3 cameraTargetPos = vehicleNode.position - dir * Vector3(0, 0, 10);
+    Vector3 cameraStartPos = vehicleNode.position;
 
     // Raycast camera against static objects (physics collision mask 2)
     // and move it closer to the vehicle if something in between
@@ -266,66 +271,6 @@ void HandlePostRenderUpdate()
         testScene.physicsWorld.DrawDebugGeometry(true);
 }
 
-void InitVehicle()
-{
-    vehicleHullNode = testScene.CreateChild("VehicleHull");
-    StaticModel@ hullObject = vehicleHullNode.CreateComponent("StaticModel");
-    RigidBody@ hullBody = vehicleHullNode.CreateComponent("RigidBody");
-    CollisionShape@ hullShape = vehicleHullNode.CreateComponent("CollisionShape");
-
-    vehicleHullNode.position = Vector3(0, 5, 0);
-    vehicleHullNode.scale = Vector3(1.5, 1, 3);
-    hullObject.model = cache.GetResource("Model", "Models/Box.mdl");
-    hullObject.material = cache.GetResource("Material", "Materials/Stone.xml");
-    hullObject.castShadows = true;
-    hullShape.SetBox(Vector3(1, 1, 1));
-    hullBody.mass = 3;
-    hullBody.linearDamping = 0.2; // Some air resistance
-    hullBody.collisionLayer = 1;
-
-    Node@ fl = InitVehicleWheel("FrontLeft", vehicleHullNode, Vector3(-0.6, -0.4, 0.3));
-    Node@ fr = InitVehicleWheel("FrontRight", vehicleHullNode, Vector3(0.6, -0.4, 0.3));
-    Node@ rr = InitVehicleWheel("RearLeft", vehicleHullNode, Vector3(-0.6, -0.4, -0.3));
-    Node@ rl = InitVehicleWheel("RearRight", vehicleHullNode, Vector3(0.6, -0.4, -0.3));
-
-    Vehicle@ vehicle = cast<Vehicle>(vehicleHullNode.CreateScriptObject(scriptFile, "Vehicle"));
-    vehicle.SetWheels(fl, fr, rl, rr);
-}
-
-Node@ InitVehicleWheel(String name, Node@ vehicleHullNode, Vector3 offset)
-{
-    Node@ wheelNode = testScene.CreateChild(name);
-    wheelNode.position = vehicleHullNode.LocalToWorld(offset);
-    wheelNode.rotation = vehicleHullNode.worldRotation * (offset.x >= 0.0 ? Quaternion(0, 0, -90) : Quaternion(0, 0, 90));
-    wheelNode.scale = Vector3(0.75, 0.5, 0.75);
-
-    StaticModel@ wheelObject = wheelNode.CreateComponent("StaticModel");
-    RigidBody@ wheelBody = wheelNode.CreateComponent("RigidBody");
-    CollisionShape@ wheelShape = wheelNode.CreateComponent("CollisionShape");
-    Constraint@ wheelConstraint = wheelNode.CreateComponent("Constraint");
-
-    wheelObject.model = cache.GetResource("Model", "Models/Cylinder.mdl");
-    wheelObject.material = cache.GetResource("Material", "Materials/Stone.xml");
-    wheelObject.castShadows = true;
-    wheelShape.SetCylinder(1, 1);
-    wheelBody.friction = 1;
-    wheelBody.mass = 1;
-    wheelBody.linearDamping = 0.2; // Some air resistance
-    wheelBody.angularDamping = 0.75; // Current version of Bullet used by Urho doesn't have rolling friction, so mimic that with
-                                    // some angular damping on the wheels
-    wheelBody.collisionLayer = 1;
-    wheelConstraint.constraintType = CONSTRAINT_HINGE;
-    wheelConstraint.otherBody = vehicleHullNode.GetComponent("RigidBody");
-    wheelConstraint.worldPosition = wheelNode.worldPosition; // Set constraint's both ends at wheel's location
-    wheelConstraint.axis = Vector3(0, 1, 0); // Wheel rotates around its local Y-axis
-    wheelConstraint.otherAxis = offset.x >= 0.0 ? Vector3(1, 0, 0) : Vector3(-1, 0, 0); // Wheel's hull axis points either left or right
-    wheelConstraint.lowLimit = Vector2(-180, 0); // Let the wheel rotate freely around the axis
-    wheelConstraint.highLimit = Vector2(180, 0);
-    wheelConstraint.disableCollision = true; // Let the wheel intersect the vehicle hull
-
-    return wheelNode;
-}
-
 class Vehicle : ScriptObject
 {
     Node@ frontLeft;
@@ -341,18 +286,31 @@ class Vehicle : ScriptObject
     RigidBody@ rearRightBody;
 
     float steering = 0.0;
-    float enginePower = 8.0;
+    float enginePower = 10.0;
     float downForce = 10.0;
     float maxWheelAngle = 22.5;
 
-    void SetWheels(Node@ fl, Node@ fr, Node@ rl, Node@ rr)
+    void Init()
     {
-        frontLeft = fl;
-        frontRight = fr;
-        rearLeft = rl;
-        rearRight = rr;
-
-        hullBody = node.GetComponent("RigidBody");
+        StaticModel@ hullObject = node.CreateComponent("StaticModel");
+        hullBody = node.CreateComponent("RigidBody");
+        CollisionShape@ hullShape = node.CreateComponent("CollisionShape");
+
+        node.scale = Vector3(1.5, 1, 3);
+        hullObject.model = cache.GetResource("Model", "Models/Box.mdl");
+        hullObject.material = cache.GetResource("Material", "Materials/Stone.xml");
+        hullObject.castShadows = true;
+        hullShape.SetBox(Vector3(1, 1, 1));
+        hullBody.mass = 4;
+        hullBody.linearDamping = 0.2; // Some air resistance
+        hullBody.angularDamping = 0.5;
+        hullBody.collisionLayer = 1;
+    
+        frontLeft = InitWheel("FrontLeft", Vector3(-0.6, -0.4, 0.3));
+        frontRight = InitWheel("FrontRight", Vector3(0.6, -0.4, 0.3));
+        rearLeft = InitWheel("RearLeft", Vector3(-0.6, -0.4, -0.3));
+        rearRight = InitWheel("RearRight", Vector3(0.6, -0.4, -0.3));
+        
         frontLeftAxis = frontLeft.GetComponent("Constraint");
         frontRightAxis = frontRight.GetComponent("Constraint");
         frontLeftBody = frontLeft.GetComponent("RigidBody");
@@ -361,6 +319,40 @@ class Vehicle : ScriptObject
         rearRightBody = rearRight.GetComponent("RigidBody");
     }
 
+    Node@ InitWheel(const String&in name, const Vector3&in offset)
+    {
+        Node@ wheelNode = testScene.CreateChild(name);
+        wheelNode.position = node.LocalToWorld(offset);
+        wheelNode.rotation = node.worldRotation * (offset.x >= 0.0 ? Quaternion(0, 0, -90) : Quaternion(0, 0, 90));
+        wheelNode.scale = Vector3(0.8, 0.5, 0.8);
+
+        StaticModel@ wheelObject = wheelNode.CreateComponent("StaticModel");
+        RigidBody@ wheelBody = wheelNode.CreateComponent("RigidBody");
+        CollisionShape@ wheelShape = wheelNode.CreateComponent("CollisionShape");
+        Constraint@ wheelConstraint = wheelNode.CreateComponent("Constraint");
+
+        wheelObject.model = cache.GetResource("Model", "Models/Cylinder.mdl");
+        wheelObject.material = cache.GetResource("Material", "Materials/Stone.xml");
+        wheelObject.castShadows = true;
+        wheelShape.SetSphere(1);
+        wheelBody.friction = 1;
+        wheelBody.mass = 1;
+        wheelBody.linearDamping = 0.2; // Some air resistance
+        wheelBody.angularDamping = 0.75; // Current version of Bullet used by Urho doesn't have rolling friction, so mimic that with
+                                        // some angular damping on the wheels
+        wheelBody.collisionLayer = 1;
+        wheelConstraint.constraintType = CONSTRAINT_HINGE;
+        wheelConstraint.otherBody = node.GetComponent("RigidBody");
+        wheelConstraint.worldPosition = wheelNode.worldPosition; // Set constraint's both ends at wheel's location
+        wheelConstraint.axis = Vector3(0, 1, 0); // Wheel rotates around its local Y-axis
+        wheelConstraint.otherAxis = offset.x >= 0.0 ? Vector3(1, 0, 0) : Vector3(-1, 0, 0); // Wheel's hull axis points either left or right
+        wheelConstraint.lowLimit = Vector2(-180, 0); // Let the wheel rotate freely around the axis
+        wheelConstraint.highLimit = Vector2(180, 0);
+        wheelConstraint.disableCollision = true; // Let the wheel intersect the vehicle hull
+    
+        return wheelNode;
+    }
+
     void FixedUpdate(float timeStep)
     {
         float newSteering = 0.0;
@@ -405,7 +397,7 @@ class Vehicle : ScriptObject
         }
 
         // Apply downforce proportional to velocity
-        Vector3 localVelocity = node.worldRotation.Inverse() * hullBody.linearVelocity;
-        hullBody.ApplyForce(node.worldRotation * Vector3(0, -1, 0) * Abs(localVelocity.z) * downForce);
+        Vector3 localVelocity = hullBody.rotation.Inverse() * hullBody.linearVelocity;
+        hullBody.ApplyForce(hullBody.rotation * Vector3(0, -1, 0) * Abs(localVelocity.z) * downForce);
     }
 }

+ 4 - 2
Docs/ScriptAPI.dox

@@ -2937,6 +2937,7 @@ Properties:<br>
 - uint id (readonly)
 - Node@ node (readonly)
 - Material@ material
+- bool smoothing
 - Image@ heightMap
 - int patchSize
 - Vector3 spacing
@@ -5653,8 +5654,8 @@ Methods:<br>
 - void SetCylinder(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - void SetCapsule(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - 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 SetTriangleMesh(Model@, uint arg1 = 0, const Vector3& arg2 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg3 = Vector3 ( ), const Quaternion& arg4 = Quaternion ( ))
+- void SetConvexHull(Model@, uint arg1 = 0, 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&)
@@ -5710,6 +5711,7 @@ Methods:<br>
 - void ApplyTorqueImpulse(const Vector3&)
 - void ResetForces()
 - void Activate()
+- void ReAddBodyToWorld()
 - Vector3 GetVelocityAtPoint(const Vector3&) const
 
 Properties:<br>

+ 2 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -1034,6 +1034,8 @@ static void RegisterTerrain(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Terrain", "TerrainPatch@+ GetPatch(int, int) const", asMETHODPR(Terrain, GetPatch, (int, int) const, TerrainPatch*), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_material(Material@+)", asMETHOD(Terrain, SetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "Material@+ get_material() const", asMETHOD(Terrain, GetMaterial), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "void set_smoothing(bool)", asMETHOD(Terrain, SetSmoothing), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "bool get_smoothing() const", asMETHOD(Terrain, GetSmoothing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_heightMap(Image@+)", asMETHOD(Terrain, SetHeightMap), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "Image@+ get_heightMap() const", asMETHOD(Terrain, GetHeightMap), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_patchSize(int)", asMETHOD(Terrain, SetPatchSize), asCALL_THISCALL);

+ 3 - 2
Engine/Engine/PhysicsAPI.cpp

@@ -77,8 +77,8 @@ static void RegisterCollisionShape(asIScriptEngine* engine)
     engine->RegisterObjectMethod("CollisionShape", "void SetCylinder(float, float, const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCylinder), asCALL_THISCALL);
     engine->RegisterObjectMethod("CollisionShape", "void SetCapsule(float, float, const Vector3&in pos = Vector3(), const Quaternion&in rot = Quaternion())", asMETHOD(CollisionShape, SetCapsule), asCALL_THISCALL);
     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 SetTriangleMesh(Model@+, uint lodLevel = 0, 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 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 SetTransform(const Vector3&in, const Quaternion&in)", asMETHOD(CollisionShape, SetTransform), asCALL_THISCALL);
@@ -127,6 +127,7 @@ static void RegisterRigidBody(asIScriptEngine* engine)
     engine->RegisterObjectMethod("RigidBody", "void ApplyTorqueImpulse(const Vector3&in)", asMETHOD(RigidBody, ApplyTorqueImpulse), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void ResetForces()", asMETHOD(RigidBody, ResetForces), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void Activate()", asMETHOD(RigidBody, Activate), asCALL_THISCALL);
+    engine->RegisterObjectMethod("RigidBody", "void ReAddBodyToWorld()", asMETHOD(RigidBody, ReAddBodyToWorld), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "Vector3 GetVelocityAtPoint(const Vector3&in) const", asMETHOD(RigidBody, GetVelocityAtPoint), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void set_mass(float)", asMETHOD(RigidBody, SetMass), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "float get_mass() const", asMETHOD(RigidBody, GetMass), asCALL_THISCALL);

+ 45 - 6
Engine/Graphics/Terrain.cpp

@@ -68,6 +68,7 @@ Terrain::Terrain(Context* context) :
     numPatches_(IntVector2::ZERO),
     patchSize_(DEFAULT_PATCH_SIZE),
     numLodLevels_(1),
+    smoothing_(false),
     visible_(true),
     castShadows_(false),
     occluder_(false),
@@ -98,6 +99,7 @@ void Terrain::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Terrain, VAR_RESOURCEREF, "Material", GetMaterialAttr, SetMaterialAttr, ResourceRef, ResourceRef(Material::GetTypeStatic()), AM_DEFAULT);
     ATTRIBUTE(Terrain, VAR_VECTOR3, "Vertex Spacing", spacing_, DEFAULT_SPACING, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_INT, "Patch Size", GetPatchSize, SetPatchSizeAttr, int, DEFAULT_PATCH_SIZE, AM_DEFAULT);
+    ATTRIBUTE(Terrain, VAR_BOOL, "Smooth Height Map", smoothing_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Is Occluder", IsOccluder, SetOccluder, bool,  false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Terrain, VAR_BOOL, "Cast Shadows", GetCastShadows, SetCastShadows, bool, false, AM_DEFAULT);
@@ -137,6 +139,20 @@ void Terrain::OnSetEnabled()
     }
 }
 
+void Terrain::SetPatchSize(int size)
+{
+    if (size < MIN_PATCH_SIZE || size > MAX_PATCH_SIZE || !IsPowerOfTwo(size))
+        return;
+
+    if (size != patchSize_)
+    {
+        patchSize_ = size;
+
+        CreateGeometry();
+        MarkNetworkUpdate();
+    }
+}
+
 void Terrain::SetSpacing(const Vector3& spacing)
 {
     if (spacing != spacing_)
@@ -148,14 +164,11 @@ void Terrain::SetSpacing(const Vector3& spacing)
     }
 }
 
-void Terrain::SetPatchSize(int size)
+void Terrain::SetSmoothing(bool enable)
 {
-    if (size < MIN_PATCH_SIZE || size > MAX_PATCH_SIZE || !IsPowerOfTwo(size))
-        return;
-
-    if (size != patchSize_)
+    if (enable != smoothing_)
     {
-        patchSize_ = size;
+        smoothing_ = enable;
 
         CreateGeometry();
         MarkNetworkUpdate();
@@ -640,6 +653,9 @@ void Terrain::CreateGeometry()
             }
         }
 
+        if (smoothing_)
+            SmoothHeightMap();
+        
         patches_.Reserve(numPatches_.x_ * numPatches_.y_);
 
         bool enabled = IsEnabledEffective();
@@ -703,6 +719,29 @@ void Terrain::CreateGeometry()
     }
 }
 
+void Terrain::SmoothHeightMap()
+{
+    PROFILE(SmoothHeightMap);
+    
+    SharedArrayPtr<float> newHeightData(new float[numVertices_.x_* numVertices_.y_]);
+    
+    for (int z = 0; z < numVertices_.y_; ++z)
+    {
+        for (int x = 0; x < numVertices_.x_; ++x)
+        {
+            float smoothedHeight = (
+                GetRawHeight(x - 1, z - 1) + GetRawHeight(x, z - 1) + GetRawHeight(x + 1, z - 1) +
+                GetRawHeight(x - 1, z) + GetRawHeight(x, z) + GetRawHeight(x + 1, z) +
+                GetRawHeight(x - 1, z + 1) + GetRawHeight(x, z + 1) + GetRawHeight(x + 1, z + 1)
+            ) / 9.0f;
+            
+            newHeightData[z * numVertices_.x_ + x] = smoothedHeight;
+        }
+    }
+    
+    heightData_ = newHeightData;
+}
+
 void Terrain::CreateIndexData()
 {
     PROFILE(CreateIndexData);

+ 8 - 0
Engine/Graphics/Terrain.h

@@ -56,6 +56,8 @@ public:
     void SetPatchSize(int size);
     /// Set vertex (XZ) and height (Y) spacing.
     void SetSpacing(const Vector3& spacing);
+    /// Set smoothing of heightmap.
+    void SetSmoothing(bool enable);
     /// Set heightmap image. Dimensions should be a power of two + 1. Uses 8-bit grayscale, or optionally red as MSB and green as LSB for 16-bit accuracy. Return true if successful.
     bool SetHeightMap(Image* image);
     /// Set material.
@@ -91,6 +93,8 @@ public:
     const IntVector2& GetNumVertices() const { return numVertices_; }
     /// Return heightmap size in patches.
     const IntVector2& GetNumPatches() const { return numPatches_; }
+    /// Return whether smoothing is in use.
+    bool GetSmoothing() const { return smoothing_; }
     /// Return heightmap image.
     Image* GetHeightMap() const;
     /// Return material.
@@ -148,6 +152,8 @@ public:
 private:
     /// Fully regenerate terrain geometry.
     void CreateGeometry();
+    /// Filter the heightmap.
+    void SmoothHeightMap();
     /// Create index data shared by all patches.
     void CreateIndexData();
     /// Return an uninterpolated terrain height value, clamping to edges.
@@ -191,6 +197,8 @@ private:
     int patchSize_;
     /// Number of terrain LOD levels.
     unsigned numLodLevels_;
+    /// Smoothing enable flag.
+    bool smoothing_;
     /// Visible flag.
     bool visible_;
     /// Shadowcaster flag.

+ 2 - 2
Engine/Physics/CollisionShape.h

@@ -155,9 +155,9 @@ public:
     /// 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);
+    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 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);
+    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 terrain. Only works if the same scene node contains a Terrain component.

+ 6 - 0
Engine/Physics/RigidBody.cpp

@@ -550,6 +550,12 @@ void RigidBody::Activate()
         body_->activate(true);
 }
 
+void RigidBody::ReAddBodyToWorld()
+{
+    if (body_ && inWorld_)
+        AddBodyToWorld();
+}
+
 Vector3 RigidBody::GetPosition() const
 {
     if (body_)

+ 2 - 0
Engine/Physics/RigidBody.h

@@ -137,6 +137,8 @@ public:
     void ResetForces();
     /// Activate rigid body if it was resting.
     void Activate();
+    /// Readd rigid body to the physics world to clean up internal state like stale contacts.
+    void ReAddBodyToWorld();
     
     /// Return physics world.
     PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }