Browse Source

Handle world transform update of parented RigidBodies correctly.
Updated physics documentation.

Lasse Öörni 13 years ago
parent
commit
32fa940130

+ 17 - 9
Docs/Reference.dox

@@ -143,12 +143,12 @@ Urho3D's scene model can be described as a component-based scene graph. The Scen
 Rendering 3D objects, sound playback, physics and scripted logic updates are all enabled by creating different \ref Component "Components" into the nodes by calling \ref Node::CreateComponent "CreateComponent()". As with events, in C++ components are identified by type name hashes, and template forms of the component creation and retrieval functions exist for convenience. For example:
 Rendering 3D objects, sound playback, physics and scripted logic updates are all enabled by creating different \ref Component "Components" into the nodes by calling \ref Node::CreateComponent "CreateComponent()". As with events, in C++ components are identified by type name hashes, and template forms of the component creation and retrieval functions exist for convenience. For example:
 
 
 \code
 \code
-Light* light = lightNode->CreateComponent<Light>();
+Light* light = node->CreateComponent<Light>();
 \endcode
 \endcode
 
 
 In script, strings are used to identify component types instead, so the same code would look like:
 In script, strings are used to identify component types instead, so the same code would look like:
 \code
 \code
-Light@ light = lightNode.CreateComponent("Light");
+Light@ light = node.CreateComponent("Light");
 \endcode
 \endcode
 
 
 Because components are created using \ref ObjectTypes "object factories", a factory must be registered for each component type.
 Because components are created using \ref ObjectTypes "object factories", a factory must be registered for each component type.
@@ -177,7 +177,7 @@ It is also legal to create a Node that does not belong to a scene. This is parti
 
 
 \section SceneModel_Update Scene updates and serialization
 \section SceneModel_Update Scene updates and serialization
 
 
-A Scene can be either active or inactive (paused.) Active scenes will be automatically updated on each main loop iteration. 
+A Scene can be either active or inactive (paused.) Active scenes will be automatically updated on each main loop iteration. See \ref Scene::SetActive "SetActive()".
 
 
 Scenes can be loaded and saved in either binary or XML format; see \ref Serialization "Serialization" for details.
 Scenes can be loaded and saved in either binary or XML format; see \ref Serialization "Serialization" for details.
 
 
@@ -814,19 +814,27 @@ The %Physics library in Urho3D implements rigid body physics simulation using th
 
 
 To use, a PhysicsWorld component must first be created to the Scene.
 To use, a PhysicsWorld component must first be created to the Scene.
 
 
-The physics simulation has its own, fixed update rate. By default it is 60Hz. For higher rendering frame rates, physics motion is interpolated so that it always appears smooth. The update rate can be changed with \ref PhysicsWorld::SetFps "SetFps()" function. The physics update rate also determines the frequency of fixed timestep scene logic updates.
+The physics simulation has its own fixed update rate, which by default is 60Hz. When the rendering framerate is higher than the physics update rate, physics motion is interpolated so that it always appears smooth. The update rate can be changed with \ref PhysicsWorld::SetFps "SetFps()" function. The physics update rate also determines the frequency of fixed timestep scene logic updates.
 
 
 The other physics components are:
 The other physics components are:
 
 
-- CollisionShape: defines physics collision geometry. The supported shapes are sphere, box, cylinder, capsule, triangle mesh, convex hull and heightfield.
-- RigidBody: a physics object instance. Instantiates all the physics geometries in the same Node. Its parameters include mass and linear/angular velocities.
+- RigidBody: a physics object instance. Its parameters include mass, linear/angular velocities, friction and restitution.
+- CollisionShape: defines physics collision geometry. The supported shapes are box, sphere, cylinder, capsule, cone, triangle mesh and convex hull.
 - Joint: connects two RigidBodies together, or one RigidBody to a static point in the world. Currently ball and hinge joints are supported.
 - Joint: connects two RigidBodies together, or one RigidBody to a static point in the world. Currently ball and hinge joints are supported.
 
 
-Triangle meshes, convex hulls and heightfields are created by specifying a Model resource.
+Both a RigidBody and at least one CollisionShape component must exist in a scene node for it to behave physically (a collision shape by itself does nothing.) Several collision shapes may exist in the same node to create compound shapes. An offset position and rotation relative to the node's transform can be specified for each. Triangle mesh and convex hull geometries require specifying a Model resource and the LOD level to use.
 
 
-Several collision shapes may exist in the same scene node to create compound shapes. An offset position and rotation relative to the node's transform can be specified for each. The shape (instead of RigidBody) also contains collision behaviour parameters: which other objects to collide with (see \ref CollisionShape::SetCollisionLayer "SetCollisionLayer()" and \ref CollisionShape::SetCollisionMask "SetCollisionMask()"), the friction coefficient, and the bounce coefficient.
+CollisionShape provides two APIs for defining the collision geometry. Either setting individual properties such as the \ref CollisionShape::SetShapeType "shape type" or \ref CollisionShape::SetSize "size", or specifying both the shape type and all its properties at once: see for example \ref CollisionShape::SetBox "SetBox()", \ref CollisionShape::SetCapsule "SetCapsule()" or \ref CollisionShape::SetTriangleMesh "SetTriangleMesh()".
 
 
-The physics simulation does all calculations in world space. Therefore nodes containing a RigidBody component should only be parented to the Scene (root node) to operate correctly.
+RigidBodies can be either static or moving. A body is static if its mass is 0, and moving if the mass is greater than 0.
+
+The collision behaviour of a rigid body is controlled by several variables. First, the collision layer and mask define which other objects to collide with: see \ref RigidBody::SetCollisionLayer "SetCollisionLayer()" and \ref RigidBody::SetCollisionMask "SetCollisionMask()". By default a rigid body is on layer 1; the layer will be ANDed with the other body's collision mask to see if the collision should be reported. A rigid body can also be set to \ref RigidBody::SetPhantom "phantom mode" to only report collisions without actually applying collision forces. Finally, the \ref RigidBody::SetFriction "friction" and \ref RigidBody::SetRestitution "restitution" coefficients (between 0 - 1) control how kinetic energy is transferred in the collisions.
+
+For continuous collision detection of fast moving bodies, the Bullet library approximates them as swept spheres; use \ref RigidBody::SetCcdRadius "SetCcdRadius()" to control the size. The swept sphere should not be larger than the collision geometries attached to the rigid body. By default the radius is 0.
+
+By default rigid bodies can move and rotate about all 3 coordinate axes when forces are applied. To limit the movement, use \ref RigidBody::SetLinearFactor "SetLinearFactor()" and \ref RigidBody::SetAngularFactor "SetAngularFactor()" and set the axes you wish to use to 1 and those you do not wish to use to 0. For example moving humanoid characters are often represented by a capsule shape: to ensure they stay upright and only rotate when you explicitly set the rotation in code, set the angular factor to 0, 0, 0.
+
+The physics simulation does all calculations in world space. Nodes containing a RigidBody component should be parented to the Scene (root node) to ensure correct operation.
 
 
 The physics world sends 3 types of events during its update step:
 The physics world sends 3 types of events during its update step:
 
 

+ 63 - 56
Docs/ScriptAPI.dox

@@ -1210,13 +1210,9 @@ Methods:<br>
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&, float)
 - void SetTransform(const Vector3&, const Quaternion&, float)
 - void SetTransform(const Vector3&, const Quaternion&, const Vector3&)
 - void SetTransform(const Vector3&, const Quaternion&, const Vector3&)
-- void SnapPosition(const Vector3&)
-- void SnapRotation(const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&, float)
 - void SetWorldTransform(const Vector3&, const Quaternion&, float)
 - void SetWorldTransform(const Vector3&, const Quaternion&, const Vector3&)
 - void SetWorldTransform(const Vector3&, const Quaternion&, const Vector3&)
-- void SnapWorldPosition(const Vector3&)
-- void SnapWorldRotation(const Quaternion&)
 - void Translate(const Vector3&)
 - void Translate(const Vector3&)
 - void TranslateRelative(const Vector3&)
 - void TranslateRelative(const Vector3&)
 - void Rotate(const Quaternion&, bool arg1 = false)
 - void Rotate(const Quaternion&, bool arg1 = false)
@@ -1268,14 +1264,8 @@ Properties:<br>
 - Quaternion worldRotation
 - Quaternion worldRotation
 - Vector3 worldDirection
 - Vector3 worldDirection
 - Vector3 worldScale
 - Vector3 worldScale
-- Vector3& targetPosition (readonly)
-- Quaternion& targetRotation (readonly)
-- Vector3 worldTargetPosition (readonly)
-- Quaternion worldTargetRotation (readonly)
 - Matrix3x4 transform (readonly)
 - Matrix3x4 transform (readonly)
-- Matrix3x4 targetTransform (readonly)
 - Matrix3x4& worldTransform (readonly)
 - Matrix3x4& worldTransform (readonly)
-- bool smoothing
 - uint id (readonly)
 - uint id (readonly)
 - uint numChildren (readonly)
 - uint numChildren (readonly)
 - uint numAllChildren (readonly)
 - uint numAllChildren (readonly)
@@ -1290,6 +1280,34 @@ Properties:<br>
 - VariantMap vars
 - VariantMap vars
 
 
 
 
+SmoothedTransform
+
+Methods:<br>
+- bool Load(File@)
+- bool Save(File@)
+- bool LoadXML(const XMLElement&)
+- bool SaveXML(XMLElement&)
+- void ApplyAttributes()
+- bool SetAttribute(const String&, const Variant&)
+- Variant GetAttribute(const String&)
+- void Remove()
+- void Update(float, float)
+
+Properties:<br>
+- ShortStringHash type (readonly)
+- String& typeName (readonly)
+- uint numAttributes (readonly)
+- Variant[] attributes
+- AttributeInfo&[] attributeInfos (readonly)
+- uint id (readonly)
+- Node@ node (readonly)
+- Vector3& targetPosition
+- Quaternion& targetRotation
+- Vector3 targetWorldPosition
+- Quaternion targetWorldRotation
+- bool active (readonly)
+
+
 Scene
 Scene
 
 
 Methods:<br>
 Methods:<br>
@@ -1304,13 +1322,9 @@ Methods:<br>
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&, float)
 - void SetTransform(const Vector3&, const Quaternion&, float)
 - void SetTransform(const Vector3&, const Quaternion&, const Vector3&)
 - void SetTransform(const Vector3&, const Quaternion&, const Vector3&)
-- void SnapPosition(const Vector3&)
-- void SnapRotation(const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&)
 - void SetWorldTransform(const Vector3&, const Quaternion&, float)
 - void SetWorldTransform(const Vector3&, const Quaternion&, float)
 - void SetWorldTransform(const Vector3&, const Quaternion&, const Vector3&)
 - void SetWorldTransform(const Vector3&, const Quaternion&, const Vector3&)
-- void SnapWorldPosition(const Vector3&)
-- void SnapWorldRotation(const Quaternion&)
 - void Translate(const Vector3&)
 - void Translate(const Vector3&)
 - void TranslateRelative(const Vector3&)
 - void TranslateRelative(const Vector3&)
 - void Rotate(const Quaternion&, bool arg1 = false)
 - void Rotate(const Quaternion&, bool arg1 = false)
@@ -1375,14 +1389,8 @@ Properties:<br>
 - Quaternion worldRotation
 - Quaternion worldRotation
 - Vector3 worldDirection
 - Vector3 worldDirection
 - Vector3 worldScale
 - Vector3 worldScale
-- Vector3& targetPosition (readonly)
-- Quaternion& targetRotation (readonly)
-- Vector3 worldTargetPosition (readonly)
-- Quaternion worldTargetRotation (readonly)
 - Matrix3x4 transform (readonly)
 - Matrix3x4 transform (readonly)
-- Matrix3x4 targetTransform (readonly)
 - Matrix3x4& worldTransform (readonly)
 - Matrix3x4& worldTransform (readonly)
-- bool smoothing
 - uint id (readonly)
 - uint id (readonly)
 - uint numChildren (readonly)
 - uint numChildren (readonly)
 - uint numAllChildren (readonly)
 - uint numAllChildren (readonly)
@@ -3918,14 +3926,13 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
-- void Clear()
 - void SetSphere(float, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetSphere(float, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetBox(const Vector3&, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetBox(const Vector3&, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetCylinder(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - 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 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 SetTriangleMesh(Model@, uint, const Vector3& arg2 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg3 = Vector3 ( ), const Quaternion& arg4 = Quaternion ( ))
-- void SetHeightfield(Model@, uint, uint, float, uint, const Vector3& arg5 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg6 = Vector3 ( ), const Quaternion& arg7 = Quaternion ( ))
-- void SetConvexHull(Model@, float, uint, const Vector3& arg3 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg4 = Vector3 ( ), const Quaternion& arg5 = Quaternion ( ))
+- void SetConvexHull(Model@, uint, const Vector3& arg2 = Vector3 ( 1 , 1 , 1 ), const Vector3& arg3 = Vector3 ( ), const Quaternion& arg4 = Quaternion ( ))
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
@@ -3937,16 +3944,13 @@ Properties:<br>
 - AttributeInfo&[] attributeInfos (readonly)
 - AttributeInfo&[] attributeInfos (readonly)
 - uint id (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - Node@ node (readonly)
-- Model@ model (readonly)
-- ShapeType shapeType (readonly)
+- ShapeType shapeType
+- Vector3& size
 - Vector3& position
 - Vector3& position
 - Quaternion& rotation
 - Quaternion& rotation
-- uint collisionLayer
-- uint collisionMask
-- float friction
-- float bounce
-- bool phantom
-- BoundingBox worldBoundingBox (readonly)
+- float margin
+- Model@ model
+- uint lodLevel
 
 
 
 
 RigidBody
 RigidBody
@@ -3961,10 +3965,16 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&)
+- void SetCollisionLayerAndMask(uint, uint)
 - void ApplyForce(const Vector3&)
 - void ApplyForce(const Vector3&)
-- void ApplyForceAtPosition(const Vector3&, const Vector3&)
+- void ApplyForce(const Vector3&, const Vector3&)
 - void ApplyTorque(const Vector3&)
 - void ApplyTorque(const Vector3&)
+- void ApplyImpulse(const Vector3&)
+- void ApplyImpulse(const Vector3&, const Vector3&)
+- void ApplyTorqueImpulse(const Vector3&)
 - void ResetForces()
 - void ResetForces()
+- void Activate()
+- void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
 - ShortStringHash type (readonly)
 - ShortStringHash type (readonly)
@@ -3975,20 +3985,26 @@ Properties:<br>
 - uint id (readonly)
 - uint id (readonly)
 - Node@ node (readonly)
 - Node@ node (readonly)
 - float mass
 - float mass
-- int massAxis
-- Vector3& linearVelocity
+- Vector3 position
+- Quaternion rotation
+- Vector3 linearVelocity
+- Vector3 linearFactor
 - float linearRestThreshold
 - float linearRestThreshold
-- Vector3& angularVelocity
+- float linearDamping
+- Vector3 angularVelocity
+- Vector3 angularFactor
 - float angularRestThreshold
 - float angularRestThreshold
-- float angularMaxVelocity
+- float angularDamping
+- float friction
+- float restitution
 - bool useGravity
 - bool useGravity
-- bool active
-- Vector3& position
-- Quaternion& rotation
-- float linearDampingThreshold
-- float linearDampingScale
-- float angularDampingThreshold
-- float angularDampingScale
+- bool phantom
+- bool kinematic
+- bool active (readonly)
+- float ccdRadius
+- uint collisionLayer
+- uint collisionMask
+- CollisionEventMode collisionEventMode
 
 
 
 
 Joint
 Joint
@@ -4023,7 +4039,7 @@ Properties:<br>
 PhysicsRaycastResult
 PhysicsRaycastResult
 
 
 Properties:<br>
 Properties:<br>
-- CollisionShape@ collisionShape (readonly)
+- RigidBody@ body (readonly)
 - Vector3 position
 - Vector3 position
 - Vector3 normal
 - Vector3 normal
 - float distance
 - float distance
@@ -4041,7 +4057,9 @@ Methods:<br>
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
 - void Update(float)
 - void Update(float)
-- PhysicsRaycastResult[]@ Raycast(const Ray&, float arg1 = M_INFINITY, uint arg2 = 0xffffffff)
+- void UpdateCollisions()
+- PhysicsRaycastResult[]@ Raycast(const Ray&, float arg1 = M_INFINITY, uint arg2 = 0xffff)
+- PhysicsRaycastResult RaycastSingle(const Ray&, float arg1 = M_INFINITY, uint arg2 = 0xffff)
 - void DrawDebugGeometry(bool)
 - void DrawDebugGeometry(bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -4054,18 +4072,7 @@ Properties:<br>
 - Node@ node (readonly)
 - Node@ node (readonly)
 - Vector3 gravity
 - Vector3 gravity
 - int fps
 - int fps
-- uint maxContacts
 - bool interpolation
 - bool interpolation
-- float linearRestThreshold
-- float angularRestThreshold
-- float bounceThreshold
-- float erp
-- float cfm
-- float contactSurfaceLayer
-- float linearDampingThreshold
-- float linearDampingScale
-- float angularDampingThreshold
-- float angularDampingScale
 
 
 
 
 ScriptFile
 ScriptFile

+ 10 - 0
Engine/Core/Object.cpp

@@ -302,6 +302,16 @@ Object* Object::GetSubsystem(ShortStringHash type) const
     return context_->GetSubsystem(type);
     return context_->GetSubsystem(type);
 }
 }
 
 
+Object* Object::GetEventSender() const
+{
+    return context_->GetEventSender();
+}
+
+EventHandler* Object::GetEventHandler() const
+{
+    return context_->GetEventHandler();
+}
+
 bool Object::HasSubscribedToEvent(StringHash eventType) const
 bool Object::HasSubscribedToEvent(StringHash eventType) const
 {
 {
     return eventHandlers_.Find(MakePair((Object*)0, eventType)) != eventHandlers_.End();
     return eventHandlers_.Find(MakePair((Object*)0, eventType)) != eventHandlers_.End();

+ 4 - 0
Engine/Core/Object.h

@@ -75,6 +75,10 @@ public:
     Context* GetContext() const { return context_; }
     Context* GetContext() const { return context_; }
     /// Return subsystem by type.
     /// Return subsystem by type.
     Object* GetSubsystem(ShortStringHash type) const;
     Object* GetSubsystem(ShortStringHash type) const;
+    /// Return active event sender. Null outside event handling.
+    Object* GetEventSender() const;
+    /// Return active event handler. Null outside event handling.
+    EventHandler* GetEventHandler() const;
     /// Return whether has subscribed to an event without specific sender.
     /// Return whether has subscribed to an event without specific sender.
     bool HasSubscribedToEvent(StringHash eventType) const;
     bool HasSubscribedToEvent(StringHash eventType) const;
     /// Return whether has subscribed to a specific sender's event.
     /// Return whether has subscribed to a specific sender's event.

+ 3 - 3
Engine/Graphics/OpenGL/OGLRenderSurface.h

@@ -42,11 +42,11 @@ public:
     /// Destruct.
     /// Destruct.
     ~RenderSurface();
     ~RenderSurface();
     
     
-    /// Set viewport for auxiliary view rendering.
+    /// %Set viewport for auxiliary view rendering.
     void SetViewport(Viewport* viewport);
     void SetViewport(Viewport* viewport);
-    /// Set linked color rendertarget.
+    /// %Set linked color rendertarget.
     void SetLinkedRenderTarget(RenderSurface* renderTarget);
     void SetLinkedRenderTarget(RenderSurface* renderTarget);
-    /// Set linked depth-stencil surface.
+    /// %Set linked depth-stencil surface.
     void SetLinkedDepthStencil(RenderSurface* depthStencil);
     void SetLinkedDepthStencil(RenderSurface* depthStencil);
     /// Create a renderbuffer. Return true if successful.
     /// Create a renderbuffer. Return true if successful.
     bool CreateRenderBuffer(unsigned width, unsigned height, unsigned format);
     bool CreateRenderBuffer(unsigned width, unsigned height, unsigned format);

+ 6 - 4
Engine/Physics/CollisionShape.cpp

@@ -310,7 +310,7 @@ void CollisionShape::SetCone(float diameter, float height, const Vector3& positi
     NotifyRigidBody();
     NotifyRigidBody();
 }
 }
 
 
-void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& size, const Vector3& position, const Quaternion& rotation)
+void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
 {
 {
     if (!model)
     if (!model)
     {
     {
@@ -321,7 +321,7 @@ void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vect
     shapeType_ = SHAPE_TRIANGLEMESH;
     shapeType_ = SHAPE_TRIANGLEMESH;
     model_ = model;
     model_ = model;
     lodLevel_ = lodLevel;
     lodLevel_ = lodLevel;
-    size_ = size.Abs();
+    size_ = scale;
     position_ = position;
     position_ = position;
     rotation_ = rotation;
     rotation_ = rotation;
     
     
@@ -329,7 +329,7 @@ void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vect
     NotifyRigidBody();
     NotifyRigidBody();
 }
 }
 
 
-void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector3& size, const Vector3& position, const Quaternion& rotation)
+void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
 {
 {
     if (!model)
     if (!model)
     {
     {
@@ -340,7 +340,7 @@ void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector
     shapeType_ = SHAPE_CONVEXHULL;
     shapeType_ = SHAPE_CONVEXHULL;
     model_ = model;
     model_ = model;
     lodLevel_ = lodLevel;
     lodLevel_ = lodLevel;
-    size_ = size.Abs();
+    size_ = scale;
     position_ = position;
     position_ = position;
     rotation_ = rotation;
     rotation_ = rotation;
     
     
@@ -583,6 +583,7 @@ void CollisionShape::UpdateShape()
             break;
             break;
             
             
         case SHAPE_TRIANGLEMESH:
         case SHAPE_TRIANGLEMESH:
+            size_ = size_.Abs();
             if (model_)
             if (model_)
             {
             {
                 // Check the geometry cache
                 // Check the geometry cache
@@ -604,6 +605,7 @@ void CollisionShape::UpdateShape()
             break;
             break;
             
             
         case SHAPE_CONVEXHULL:
         case SHAPE_CONVEXHULL:
+            size_ = size_.Abs();
             if (model_)
             if (model_)
             {
             {
                 // Check the geometry cache
                 // Check the geometry cache

+ 2 - 2
Engine/Physics/CollisionShape.h

@@ -115,9 +115,9 @@ public:
    /// %Set as a cone.
    /// %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.
     /// %Set as a triangle mesh.
-    void SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& size = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
+    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.
-    void SetConvexHull(Model* model, unsigned lodLevel, const Vector3& size = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
+    void SetConvexHull(Model* model, unsigned lodLevel, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// %Set shape type.
     /// %Set shape type.
     void SetShapeType(ShapeType type);
     void SetShapeType(ShapeType type);
     /// %Set shape size.
     /// %Set shape size.

+ 26 - 1
Engine/Physics/PhysicsWorld.cpp

@@ -286,6 +286,11 @@ void PhysicsWorld::RemoveJoint(Joint* joint)
         joints_.Erase(i);
         joints_.Erase(i);
 }
 }
 
 
+void PhysicsWorld::AddDelayedWorldTransform(const DelayedWorldTransform& transform)
+{
+    delayedWorldTransforms_[transform.rigidBody_] = transform;
+}
+
 void PhysicsWorld::DrawDebugGeometry(bool depthTest)
 void PhysicsWorld::DrawDebugGeometry(bool depthTest)
 {
 {
     debugDepthTest_ = depthTest;
     debugDepthTest_ = depthTest;
@@ -343,6 +348,8 @@ void PhysicsWorld::PreStep(float timeStep)
     eventData[P_TIMESTEP] = timeStep;
     eventData[P_TIMESTEP] = timeStep;
     SendEvent(E_PHYSICSPRESTEP, eventData);
     SendEvent(E_PHYSICSPRESTEP, eventData);
     
     
+    delayedWorldTransforms_.Clear();
+    
     // Start profiling block for the actual simulation step
     // Start profiling block for the actual simulation step
 #ifdef ENABLE_PROFILING
 #ifdef ENABLE_PROFILING
     Profiler* profiler = GetSubsystem<Profiler>();
     Profiler* profiler = GetSubsystem<Profiler>();
@@ -357,6 +364,24 @@ void PhysicsWorld::PostStep(float timeStep)
     GetSubsystem<Profiler>()->EndBlock();
     GetSubsystem<Profiler>()->EndBlock();
 #endif
 #endif
     
     
+    // Apply delayed (parented) world transforms now
+    while (!delayedWorldTransforms_.Empty())
+    {
+        for (HashMap<RigidBody*, DelayedWorldTransform>::Iterator i = delayedWorldTransforms_.Begin();
+            i != delayedWorldTransforms_.End(); )
+        {
+            HashMap<RigidBody*, DelayedWorldTransform>::Iterator current = i++;
+            const DelayedWorldTransform& transform = current->second_;
+            
+            // If parent's transform has already been assigned, can proceed
+            if (!delayedWorldTransforms_.Contains(transform.parentRigidBody_))
+            {
+                transform.rigidBody_->ApplyWorldTransform(transform.worldPosition_, transform.worldRotation_);
+                delayedWorldTransforms_.Erase(current);
+            }
+        }
+    }
+    
     SendCollisionEvents();
     SendCollisionEvents();
     
     
     // Send post-step event
     // Send post-step event
@@ -387,7 +412,7 @@ void PhysicsWorld::SendCollisionEvents()
         {
         {
             btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
             btPersistentManifold* contactManifold = collisionDispatcher_->getManifoldByIndexInternal(i);
             int numContacts = contactManifold->getNumContacts();
             int numContacts = contactManifold->getNumContacts();
-            // First check that there are actual contacts
+            // First check that there are actual contacts, as the manifold exists also when objects are close but not touching
             if (!numContacts)
             if (!numContacts)
                 continue;
                 continue;
             
             

+ 19 - 4
Engine/Physics/PhysicsWorld.h

@@ -67,6 +67,19 @@ struct PhysicsRaycastResult
     RigidBody* body_;
     RigidBody* body_;
 };
 };
 
 
+/// Delayed world transform assignment for parented rigidbodies.
+struct DelayedWorldTransform
+{
+    /// Rigid body.
+    RigidBody* rigidBody_;
+    /// Parent rigid body.
+    RigidBody* parentRigidBody_;
+    /// New world position.
+    Vector3 worldPosition_;
+    /// New world rotation.
+    Quaternion worldRotation_;
+};
+
 static const float DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY = 100.0f;
 static const float DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY = 100.0f;
 
 
 /// Physics simulation world component. Should be added only to the root scene node.
 /// Physics simulation world component. Should be added only to the root scene node.
@@ -140,11 +153,13 @@ public:
     void AddJoint(Joint* joint);
     void AddJoint(Joint* joint);
     /// Remove a joint. Called by Joint.
     /// Remove a joint. Called by Joint.
     void RemoveJoint(Joint* joint);
     void RemoveJoint(Joint* joint);
+    /// Add a delayed world transform assignment. Called by RigidBody.
+    void AddDelayedWorldTransform(const DelayedWorldTransform& transform);
     /// Add debug geometry to the debug renderer.
     /// Add debug geometry to the debug renderer.
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
-    /// Set debug renderer to use. Called both by PhysicsWorld itself and physics components.
+    /// %Set debug renderer to use. Called both by PhysicsWorld itself and physics components.
     void SetDebugRenderer(DebugRenderer* debug);
     void SetDebugRenderer(DebugRenderer* debug);
-    /// Set debug geometry depth test mode. Called both by PhysicsWorld itself and physics components.
+    /// %Set debug geometry depth test mode. Called both by PhysicsWorld itself and physics components.
     void SetDebugDepthTest(bool enable);
     void SetDebugDepthTest(bool enable);
     
     
     /// Return the Bullet physics world.
     /// Return the Bullet physics world.
@@ -190,8 +205,8 @@ private:
     HashSet<Pair<RigidBody*, RigidBody*> > currentCollisions_;
     HashSet<Pair<RigidBody*, RigidBody*> > currentCollisions_;
     /// Collision pairs on the previous frame. Used to check if a collision is "new."
     /// Collision pairs on the previous frame. Used to check if a collision is "new."
     HashSet<Pair<RigidBody*, RigidBody*> > previousCollisions_;
     HashSet<Pair<RigidBody*, RigidBody*> > previousCollisions_;
-    /// Already processed rigid bodies during a poststep.
-    HashSet<RigidBody*> processedBodies_;
+    /// Delayed (parented) world transform assignments.
+    HashMap<RigidBody*, DelayedWorldTransform> delayedWorldTransforms_;
     /// Cache for collision geometry data.
     /// Cache for collision geometry data.
     Map<String, SharedPtr<CollisionGeometryData> > geometryCache_;
     Map<String, SharedPtr<CollisionGeometryData> > geometryCache_;
     /// Simulation steps per second.
     /// Simulation steps per second.

+ 91 - 61
Engine/Physics/RigidBody.cpp

@@ -69,7 +69,8 @@ RigidBody::RigidBody(Context* context) :
     collisionEventMode_(COLLISION_ACTIVE),
     collisionEventMode_(COLLISION_ACTIVE),
     lastPosition_(Vector3::ZERO),
     lastPosition_(Vector3::ZERO),
     lastRotation_(Quaternion::IDENTITY),
     lastRotation_(Quaternion::IDENTITY),
-    inSetTransform_(false)
+    inSetTransform_(false),
+    hasSmoothedTransform_(false)
 {
 {
     compoundShape_ = new btCompoundShape();
     compoundShape_ = new btCompoundShape();
 }
 }
@@ -114,39 +115,34 @@ void RigidBody::RegisterObject(Context* context)
 
 
 void RigidBody::getWorldTransform(btTransform &worldTrans) const
 void RigidBody::getWorldTransform(btTransform &worldTrans) const
 {
 {
-    if (node_)
-    {
-        lastPosition_ = node_->GetWorldPosition();
-        lastRotation_ = node_->GetWorldRotation();
-        worldTrans.setOrigin(ToBtVector3(lastPosition_));
-        worldTrans.setRotation(ToBtQuaternion(lastRotation_));
-    }
+    lastPosition_ = node_->GetWorldPosition();
+    lastRotation_ = node_->GetWorldRotation();
+    worldTrans.setOrigin(ToBtVector3(lastPosition_));
+    worldTrans.setRotation(ToBtQuaternion(lastRotation_));
 }
 }
 
 
 void RigidBody::setWorldTransform(const btTransform &worldTrans)
 void RigidBody::setWorldTransform(const btTransform &worldTrans)
 {
 {
-    /// \todo If rigid body is parented, should set the transforms in hierarchy order (parent first)
-    if (node_)
+    Vector3 newWorldPosition = ToVector3(worldTrans.getOrigin());
+    Quaternion newWorldRotation = ToQuaternion(worldTrans.getRotation());
+    RigidBody* parentRigidBody = 0;
+    
+    // If the rigid body is parented to another rigid body, can not set the transform immediately.
+    // In that case store it to PhysicsWorld for delayed assignment
+    Node* parent = node_->GetParent();
+    if (parent && parent != node_->GetScene())
+        parentRigidBody = parent->GetComponent<RigidBody>();
+    
+    if (!parentRigidBody)
+        ApplyWorldTransform(newWorldPosition, newWorldRotation);
+    else
     {
     {
-        inSetTransform_ = true;
-        
-        // Apply transform to the SmoothedTransform component instead of rendering transform if available
-        if (!smoothedTransform_)
-        {
-            node_->SetWorldPosition(ToVector3(worldTrans.getOrigin()));
-            node_->SetWorldRotation(ToQuaternion(worldTrans.getRotation()));
-            lastPosition_ = node_->GetWorldPosition();
-            lastRotation_ = node_->GetWorldRotation();
-        }
-        else
-        {
-            lastPosition_ = ToVector3(worldTrans.getOrigin());
-            lastRotation_ = ToQuaternion(worldTrans.getRotation());
-            smoothedTransform_->SetTargetWorldPosition(lastPosition_);
-            smoothedTransform_->SetTargetWorldRotation(lastRotation_);
-        }
-        
-        inSetTransform_ = false;
+        DelayedWorldTransform delayed;
+        delayed.rigidBody_ = this;
+        delayed.parentRigidBody_ = parentRigidBody;
+        delayed.worldPosition_ = newWorldPosition;
+        delayed.worldRotation_ = newWorldRotation;
+        physicsWorld_->AddDelayedWorldTransform(delayed);
     }
     }
 }
 }
 
 
@@ -573,6 +569,33 @@ float RigidBody::GetCcdRadius() const
         return 0.0f;
         return 0.0f;
 }
 }
 
 
+void RigidBody::ApplyWorldTransform(const Vector3& newWorldPosition, const Quaternion& newWorldRotation)
+{
+    inSetTransform_ = true;
+    
+    // Apply transform to the SmoothedTransform component instead of node transform if available
+    SmoothedTransform* transform = 0;
+    if (hasSmoothedTransform_)
+        transform = GetComponent<SmoothedTransform>();
+    
+    if (transform)
+    {
+        transform->SetTargetWorldPosition(newWorldPosition);
+        transform->SetTargetWorldRotation(newWorldRotation);
+        lastPosition_ = newWorldPosition;
+        lastRotation_ = newWorldRotation;
+    }
+    else
+    {
+        node_->SetWorldPosition(newWorldPosition);
+        node_->SetWorldRotation(newWorldRotation);
+        lastPosition_ = node_->GetWorldPosition();
+        lastRotation_ = node_->GetWorldRotation();
+    }
+    
+    inSetTransform_ = false;
+}
+
 void RigidBody::UpdateMass()
 void RigidBody::UpdateMass()
 {
 {
     if (body_)
     if (body_)
@@ -584,21 +607,6 @@ void RigidBody::UpdateMass()
     }
     }
 }
 }
 
 
-void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
-{
-    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
-    MemoryBuffer buf(value);
-    SetAngularVelocity(buf.ReadPackedVector3(maxVelocity));
-}
-
-const PODVector<unsigned char>& RigidBody::GetNetAngularVelocityAttr() const
-{
-    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
-    attrBuffer_.Clear();
-    attrBuffer_.WritePackedVector3(GetAngularVelocity(), maxVelocity);
-    return attrBuffer_.GetBuffer();
-}
-
 void RigidBody::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 void RigidBody::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 {
 {
     if (debug && physicsWorld_ && body_)
     if (debug && physicsWorld_ && body_)
@@ -614,12 +622,27 @@ void RigidBody::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
     }
     }
 }
 }
 
 
+void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
+{
+    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
+    MemoryBuffer buf(value);
+    SetAngularVelocity(buf.ReadPackedVector3(maxVelocity));
+}
+
+const PODVector<unsigned char>& RigidBody::GetNetAngularVelocityAttr() const
+{
+    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
+    attrBuffer_.Clear();
+    attrBuffer_.WritePackedVector3(GetAngularVelocity(), maxVelocity);
+    return attrBuffer_.GetBuffer();
+}
+
 void RigidBody::OnMarkedDirty(Node* node)
 void RigidBody::OnMarkedDirty(Node* node)
 {
 {
-    // If rendering transform changes, apply it back to the physics transform. However, do not do this when a SmoothedTransform
-    // is in use, because in that case it will be constantly updated into possibly non-physical states; rather follow the
-    // SmoothedTransform target transform directly
-    if (!inSetTransform_ && !smoothedTransform_)
+    // If node transform changes, apply it back to the physics transform. However, do not do this when a SmoothedTransform
+    // is in use, because in that case the node transform will be constantly updated into smoothed, possibly non-physical
+    // states; rather follow the SmoothedTransform target transform directly
+    if (!inSetTransform_ && !hasSmoothedTransform_)
     {
     {
         // Physics operations are not safe from worker threads
         // Physics operations are not safe from worker threads
         Scene* scene = node->GetScene();
         Scene* scene = node->GetScene();
@@ -629,7 +652,7 @@ void RigidBody::OnMarkedDirty(Node* node)
             return;
             return;
         }
         }
         
         
-        // Check if transform has changed from the one set at end of simulation step
+        // Check if transform has changed from the last one set in ApplyWorldTransform()
         Vector3 newPosition = node_->GetWorldPosition();
         Vector3 newPosition = node_->GetWorldPosition();
         Quaternion newRotation = node_->GetWorldRotation();
         Quaternion newRotation = node_->GetWorldRotation();
         
         
@@ -670,6 +693,8 @@ void RigidBody::AddBodyToWorld()
     if (!physicsWorld_)
     if (!physicsWorld_)
         return;
         return;
     
     
+    bool massUpdated = false;
+    
     btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
     btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
     if (body_)
     if (body_)
         world->removeRigidBody(body_);
         world->removeRigidBody(body_);
@@ -680,24 +705,29 @@ void RigidBody::AddBodyToWorld()
         body_ = new btRigidBody(mass_, this, compoundShape_, localInertia);
         body_ = new btRigidBody(mass_, this, compoundShape_, localInertia);
         body_->setUserPointer(this);
         body_->setUserPointer(this);
         
         
-        // Check for existence of the SmoothedTransform component, which should be created by now if we are a network client node
-        smoothedTransform_ = GetComponent<SmoothedTransform>();
-        if (smoothedTransform_)
+        // Check for existence of the SmoothedTransform component, which should be created by now in network client mode.
+        // If it exists, subscribe to its change events
+        SmoothedTransform* transform = GetComponent<SmoothedTransform>();
+        if (transform)
         {
         {
-            // If SmoothedTransform exists, subscribe to its changes
-            SubscribeToEvent(smoothedTransform_, E_TARGETPOSITION, HANDLER(RigidBody, HandleTargetPosition));
-            SubscribeToEvent(smoothedTransform_, E_TARGETROTATION, HANDLER(RigidBody, HandleTargetRotation));
+            hasSmoothedTransform_ = true;
+            SubscribeToEvent(transform, E_TARGETPOSITION, HANDLER(RigidBody, HandleTargetPosition));
+            SubscribeToEvent(transform, E_TARGETROTATION, HANDLER(RigidBody, HandleTargetRotation));
         }
         }
         
         
-        // Check if CollisionShapes already exist in the node and add them to the compound shape
+        // Check if CollisionShapes already exist in the node and add them to the compound shape.
         // Note: NotifyRigidBody() will cause mass to be updated
         // Note: NotifyRigidBody() will cause mass to be updated
         PODVector<CollisionShape*> shapes;
         PODVector<CollisionShape*> shapes;
         node_->GetDerivedComponents<CollisionShape>(shapes);
         node_->GetDerivedComponents<CollisionShape>(shapes);
         for (PODVector<CollisionShape*>::Iterator i = shapes.Begin(); i != shapes.End(); ++i)
         for (PODVector<CollisionShape*>::Iterator i = shapes.Begin(); i != shapes.End(); ++i)
+        {
+            massUpdated = true;
             (*i)->NotifyRigidBody();
             (*i)->NotifyRigidBody();
+        }
     }
     }
     
     
-    UpdateMass();
+    if (!massUpdated)
+        UpdateMass();
     
     
     world->addRigidBody(body_, collisionLayer_, collisionMask_);
     world->addRigidBody(body_, collisionLayer_, collisionMask_);
 }
 }
@@ -720,13 +750,13 @@ void RigidBody::ReleaseBody()
 void RigidBody::HandleTargetPosition(StringHash eventType, VariantMap& eventData)
 void RigidBody::HandleTargetPosition(StringHash eventType, VariantMap& eventData)
 {
 {
     // Copy the smoothing target position to the rigid body
     // Copy the smoothing target position to the rigid body
-    if (!inSetTransform_ && smoothedTransform_)
-        SetPosition(smoothedTransform_->GetTargetWorldPosition());
+    if (!inSetTransform_)
+        SetPosition(static_cast<SmoothedTransform*>(GetEventSender())->GetTargetWorldPosition());
 }
 }
 
 
 void RigidBody::HandleTargetRotation(StringHash eventType, VariantMap& eventData)
 void RigidBody::HandleTargetRotation(StringHash eventType, VariantMap& eventData)
 {
 {
     // Copy the smoothing target rotation to the rigid body
     // Copy the smoothing target rotation to the rigid body
-    if (!inSetTransform_ && smoothedTransform_)
-        SetRotation(smoothedTransform_->GetTargetWorldRotation());
+    if (!inSetTransform_)
+        SetRotation(static_cast<SmoothedTransform*>(GetEventSender())->GetTargetWorldRotation());
 }
 }

+ 13 - 12
Engine/Physics/RigidBody.h

@@ -95,7 +95,7 @@ public:
     void SetUseGravity(bool enable);
     void SetUseGravity(bool enable);
     /// %Set rigid body kinematic mode. In kinematic mode forces are not applied to the rigid body.
     /// %Set rigid body kinematic mode. In kinematic mode forces are not applied to the rigid body.
     void SetKinematic(bool enable);
     void SetKinematic(bool enable);
-    /// %Set rigid body phantom mode. In phantom mode collisions are registered but do not apply forces.
+    /// %Set rigid body phantom mode. In phantom mode collisions are reported but do not apply forces.
     void SetPhantom(bool enable);
     void SetPhantom(bool enable);
     /// %Set continuous collision detection radius.
     /// %Set continuous collision detection radius.
     void SetCcdRadius(float radius);
     void SetCcdRadius(float radius);
@@ -124,6 +124,12 @@ public:
     /// Activate rigid body if it was resting.
     /// Activate rigid body if it was resting.
     void Activate();
     void Activate();
     
     
+    /// Return physics world.
+    PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
+    /// Return Bullet rigid body.
+    btRigidBody* GetBody() const { return body_; }
+    /// Return Bullet compound collision shape.
+    btCompoundShape* GetCompoundShape() const { return compoundShape_; }
     /// Return mass.
     /// Return mass.
     float GetMass() const { return mass_; }
     float GetMass() const { return mass_; }
     /// Return rigid body world-space position.
     /// Return rigid body world-space position.
@@ -171,22 +177,17 @@ public:
     /// Return collision event signaling mode.
     /// Return collision event signaling mode.
     CollisionEventMode GetCollisionEventMode() const { return collisionEventMode_; }
     CollisionEventMode GetCollisionEventMode() const { return collisionEventMode_; }
     
     
-    /// Return physics world.
-    PhysicsWorld* GetPhysicsWorld() const { return physicsWorld_; }
-    /// Return Bullet rigid body.
-    btRigidBody* GetBody() const { return body_; }
-    /// Return Bullet compound collision shape.
-    btCompoundShape* GetCompoundShape() const { return compoundShape_; }
+    /// Apply new world transform after a simulation step. Called internally.
+    void ApplyWorldTransform(const Vector3& newWorldPosition, const Quaternion& newWorldRotation);
     /// Update mass and inertia of rigid body.
     /// Update mass and inertia of rigid body.
     void UpdateMass();
     void UpdateMass();
+    /// Add debug geometry to the debug renderer.
+    void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
     /// %Set network angular velocity attribute.
     /// %Set network angular velocity attribute.
     void SetNetAngularVelocityAttr(const PODVector<unsigned char>& value);
     void SetNetAngularVelocityAttr(const PODVector<unsigned char>& value);
     /// Return network angular velocity attribute.
     /// Return network angular velocity attribute.
     const PODVector<unsigned char>& GetNetAngularVelocityAttr() const;
     const PODVector<unsigned char>& GetNetAngularVelocityAttr() const;
     
     
-    /// Add debug geometry to the debug renderer.
-    void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
-    
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
@@ -209,8 +210,6 @@ private:
     btCompoundShape* compoundShape_;
     btCompoundShape* compoundShape_;
     /// Physics world.
     /// Physics world.
     WeakPtr<PhysicsWorld> physicsWorld_;
     WeakPtr<PhysicsWorld> physicsWorld_;
-    /// Cached SmoothedTransform component, if exists.
-    WeakPtr<SmoothedTransform> smoothedTransform_;
     /// Mass.
     /// Mass.
     float mass_;
     float mass_;
     /// Attribute buffer for network replication.
     /// Attribute buffer for network replication.
@@ -227,4 +226,6 @@ private:
     mutable Quaternion lastRotation_;
     mutable Quaternion lastRotation_;
     /// Whether is in Bullet's transform update. Node dirtying is ignored at this point to prevent endless recursion.
     /// Whether is in Bullet's transform update. Node dirtying is ignored at this point to prevent endless recursion.
     bool inSetTransform_;
     bool inSetTransform_;
+    /// Smoothed transform mode.
+    bool hasSmoothedTransform_;
 };
 };

+ 1 - 1
Engine/Script/ScriptFile.cpp

@@ -548,7 +548,7 @@ void ScriptFile::HandleScriptEvent(StringHash eventType, VariantMap& eventData)
     if (!compiled_)
     if (!compiled_)
         return;
         return;
     
     
-    asIScriptFunction* function = static_cast<asIScriptFunction*>(context_->GetEventHandler()->GetUserData());
+    asIScriptFunction* function = static_cast<asIScriptFunction*>(GetEventHandler()->GetUserData());
     
     
     VariantVector parameters;
     VariantVector parameters;
     if (function->GetParamCount() > 0)
     if (function->GetParamCount() > 0)

+ 1 - 1
Engine/Script/ScriptInstance.cpp

@@ -481,7 +481,7 @@ void ScriptInstance::HandleScriptEvent(StringHash eventType, VariantMap& eventDa
     if (!active_ || !scriptFile_ || !scriptObject_)
     if (!active_ || !scriptFile_ || !scriptObject_)
         return;
         return;
     
     
-    asIScriptFunction* method = static_cast<asIScriptFunction*>(context_->GetEventHandler()->GetUserData());
+    asIScriptFunction* method = static_cast<asIScriptFunction*>(GetEventHandler()->GetUserData());
     
     
     VariantVector parameters;
     VariantVector parameters;
     if (method->GetParamCount() > 0)
     if (method->GetParamCount() > 0)