1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Core/Context.h"
26 #include "../Core/Profiler.h"
27 #include "../IO/Log.h"
28 #include "../IO/MemoryBuffer.h"
29 #include "../Physics/CollisionShape.h"
30 #include "../Physics/Constraint.h"
31 #include "../Physics/PhysicsUtils.h"
32 #include "../Physics/PhysicsWorld.h"
33 #include "../Physics/RigidBody.h"
34 #include "../Resource/ResourceCache.h"
35 #include "../Resource/ResourceEvents.h"
36 #include "../Scene/Scene.h"
37 #include "../Scene/SceneEvents.h"
38 #include "../Scene/SmoothedTransform.h"
39 
40 #include <Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
41 #include <Bullet/BulletDynamics/Dynamics/btRigidBody.h>
42 #include <Bullet/BulletCollision/CollisionShapes/btCompoundShape.h>
43 
44 namespace Urho3D
45 {
46 
47 static const float DEFAULT_MASS = 0.0f;
48 static const float DEFAULT_FRICTION = 0.5f;
49 static const float DEFAULT_RESTITUTION = 0.0f;
50 static const float DEFAULT_ROLLING_FRICTION = 0.0f;
51 static const unsigned DEFAULT_COLLISION_LAYER = 0x1;
52 static const unsigned DEFAULT_COLLISION_MASK = M_MAX_UNSIGNED;
53 
54 static const char* collisionEventModeNames[] =
55 {
56     "Never",
57     "When Active",
58     "Always",
59     0
60 };
61 
62 extern const char* PHYSICS_CATEGORY;
63 
RigidBody(Context * context)64 RigidBody::RigidBody(Context* context) :
65     Component(context),
66     gravityOverride_(Vector3::ZERO),
67     centerOfMass_(Vector3::ZERO),
68     mass_(DEFAULT_MASS),
69     collisionLayer_(DEFAULT_COLLISION_LAYER),
70     collisionMask_(DEFAULT_COLLISION_MASK),
71     collisionEventMode_(COLLISION_ACTIVE),
72     lastPosition_(Vector3::ZERO),
73     lastRotation_(Quaternion::IDENTITY),
74     kinematic_(false),
75     trigger_(false),
76     useGravity_(true),
77     readdBody_(false),
78     inWorld_(false),
79     enableMassUpdate_(true),
80     hasSimulated_(false)
81 {
82     compoundShape_ = new btCompoundShape();
83     shiftedCompoundShape_ = new btCompoundShape();
84 }
85 
~RigidBody()86 RigidBody::~RigidBody()
87 {
88     ReleaseBody();
89 
90     if (physicsWorld_)
91         physicsWorld_->RemoveRigidBody(this);
92 }
93 
RegisterObject(Context * context)94 void RigidBody::RegisterObject(Context* context)
95 {
96     context->RegisterFactory<RigidBody>(PHYSICS_CATEGORY);
97 
98     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
99     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Physics Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE | AM_NOEDIT);
100     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Physics Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE | AM_NOEDIT);
101     URHO3D_ATTRIBUTE("Mass", float, mass_, DEFAULT_MASS, AM_DEFAULT);
102     URHO3D_ACCESSOR_ATTRIBUTE("Friction", GetFriction, SetFriction, float, DEFAULT_FRICTION, AM_DEFAULT);
103     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Anisotropic Friction", GetAnisotropicFriction, SetAnisotropicFriction, Vector3, Vector3::ONE,
104         AM_DEFAULT);
105     URHO3D_ACCESSOR_ATTRIBUTE("Rolling Friction", GetRollingFriction, SetRollingFriction, float, DEFAULT_ROLLING_FRICTION, AM_DEFAULT);
106     URHO3D_ACCESSOR_ATTRIBUTE("Restitution", GetRestitution, SetRestitution, float, DEFAULT_RESTITUTION, AM_DEFAULT);
107     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector3, Vector3::ZERO,
108         AM_DEFAULT | AM_LATESTDATA);
109     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Angular Velocity", GetAngularVelocity, SetAngularVelocity, Vector3, Vector3::ZERO, AM_FILE);
110     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Linear Factor", GetLinearFactor, SetLinearFactor, Vector3, Vector3::ONE, AM_DEFAULT);
111     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Angular Factor", GetAngularFactor, SetAngularFactor, Vector3, Vector3::ONE, AM_DEFAULT);
112     URHO3D_ACCESSOR_ATTRIBUTE("Linear Damping", GetLinearDamping, SetLinearDamping, float, 0.0f, AM_DEFAULT);
113     URHO3D_ACCESSOR_ATTRIBUTE("Angular Damping", GetAngularDamping, SetAngularDamping, float, 0.0f, AM_DEFAULT);
114     URHO3D_ACCESSOR_ATTRIBUTE("Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.8f, AM_DEFAULT);
115     URHO3D_ACCESSOR_ATTRIBUTE("Angular Rest Threshold", GetAngularRestThreshold, SetAngularRestThreshold, float, 1.0f, AM_DEFAULT);
116     URHO3D_ATTRIBUTE("Collision Layer", int, collisionLayer_, DEFAULT_COLLISION_LAYER, AM_DEFAULT);
117     URHO3D_ATTRIBUTE("Collision Mask", int, collisionMask_, DEFAULT_COLLISION_MASK, AM_DEFAULT);
118     URHO3D_ACCESSOR_ATTRIBUTE("Contact Threshold", GetContactProcessingThreshold, SetContactProcessingThreshold, float, BT_LARGE_FLOAT,
119         AM_DEFAULT);
120     URHO3D_ACCESSOR_ATTRIBUTE("CCD Radius", GetCcdRadius, SetCcdRadius, float, 0.0f, AM_DEFAULT);
121     URHO3D_ACCESSOR_ATTRIBUTE("CCD Motion Threshold", GetCcdMotionThreshold, SetCcdMotionThreshold, float, 0.0f, AM_DEFAULT);
122     URHO3D_ACCESSOR_ATTRIBUTE("Network Angular Velocity", GetNetAngularVelocityAttr, SetNetAngularVelocityAttr, PODVector<unsigned char>,
123         Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
124     URHO3D_ENUM_ATTRIBUTE("Collision Event Mode", collisionEventMode_, collisionEventModeNames, COLLISION_ACTIVE, AM_DEFAULT);
125     URHO3D_ACCESSOR_ATTRIBUTE("Use Gravity", GetUseGravity, SetUseGravity, bool, true, AM_DEFAULT);
126     URHO3D_ATTRIBUTE("Is Kinematic", bool, kinematic_, false, AM_DEFAULT);
127     URHO3D_ATTRIBUTE("Is Trigger", bool, trigger_, false, AM_DEFAULT);
128     URHO3D_ACCESSOR_ATTRIBUTE("Gravity Override", GetGravityOverride, SetGravityOverride, Vector3, Vector3::ZERO, AM_DEFAULT);
129 }
130 
OnSetAttribute(const AttributeInfo & attr,const Variant & src)131 void RigidBody::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
132 {
133     Serializable::OnSetAttribute(attr, src);
134 
135     // Change of any non-accessor attribute requires the rigid body to be re-added to the physics world
136     if (!attr.accessor_)
137         readdBody_ = true;
138 }
139 
ApplyAttributes()140 void RigidBody::ApplyAttributes()
141 {
142     if (readdBody_)
143         AddBodyToWorld();
144 }
145 
OnSetEnabled()146 void RigidBody::OnSetEnabled()
147 {
148     bool enabled = IsEnabledEffective();
149 
150     if (enabled && !inWorld_)
151         AddBodyToWorld();
152     else if (!enabled && inWorld_)
153         RemoveBodyFromWorld();
154 }
155 
getWorldTransform(btTransform & worldTrans) const156 void RigidBody::getWorldTransform(btTransform& worldTrans) const
157 {
158     // We may be in a pathological state where a RigidBody exists without a scene node when this callback is fired,
159     // so check to be sure
160     if (node_)
161     {
162         lastPosition_ = node_->GetWorldPosition();
163         lastRotation_ = node_->GetWorldRotation();
164         worldTrans.setOrigin(ToBtVector3(lastPosition_ + lastRotation_ * centerOfMass_));
165         worldTrans.setRotation(ToBtQuaternion(lastRotation_));
166     }
167 
168     hasSimulated_ = true;
169 }
170 
setWorldTransform(const btTransform & worldTrans)171 void RigidBody::setWorldTransform(const btTransform& worldTrans)
172 {
173     Quaternion newWorldRotation = ToQuaternion(worldTrans.getRotation());
174     Vector3 newWorldPosition = ToVector3(worldTrans.getOrigin()) - newWorldRotation * centerOfMass_;
175     RigidBody* parentRigidBody = 0;
176 
177     // It is possible that the RigidBody component has been kept alive via a shared pointer,
178     // while its scene node has already been destroyed
179     if (node_)
180     {
181         // If the rigid body is parented to another rigid body, can not set the transform immediately.
182         // In that case store it to PhysicsWorld for delayed assignment
183         Node* parent = node_->GetParent();
184         if (parent != GetScene() && parent)
185             parentRigidBody = parent->GetComponent<RigidBody>();
186 
187         if (!parentRigidBody)
188             ApplyWorldTransform(newWorldPosition, newWorldRotation);
189         else
190         {
191             DelayedWorldTransform delayed;
192             delayed.rigidBody_ = this;
193             delayed.parentRigidBody_ = parentRigidBody;
194             delayed.worldPosition_ = newWorldPosition;
195             delayed.worldRotation_ = newWorldRotation;
196             physicsWorld_->AddDelayedWorldTransform(delayed);
197         }
198 
199         MarkNetworkUpdate();
200     }
201 
202     hasSimulated_ = true;
203 }
204 
DrawDebugGeometry(DebugRenderer * debug,bool depthTest)205 void RigidBody::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
206 {
207     if (debug && physicsWorld_ && body_ && IsEnabledEffective())
208     {
209         physicsWorld_->SetDebugRenderer(debug);
210         physicsWorld_->SetDebugDepthTest(depthTest);
211 
212         btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
213         world->debugDrawObject(body_->getWorldTransform(), shiftedCompoundShape_.Get(), IsActive() ? btVector3(1.0f, 1.0f, 1.0f) :
214             btVector3(0.0f, 1.0f, 0.0f));
215 
216         physicsWorld_->SetDebugRenderer(0);
217     }
218 }
219 
SetMass(float mass)220 void RigidBody::SetMass(float mass)
221 {
222     mass = Max(mass, 0.0f);
223 
224     if (mass != mass_)
225     {
226         mass_ = mass;
227         AddBodyToWorld();
228         MarkNetworkUpdate();
229     }
230 }
231 
SetPosition(const Vector3 & position)232 void RigidBody::SetPosition(const Vector3& position)
233 {
234     if (body_)
235     {
236         btTransform& worldTrans = body_->getWorldTransform();
237         worldTrans.setOrigin(ToBtVector3(position + ToQuaternion(worldTrans.getRotation()) * centerOfMass_));
238 
239         // When forcing the physics position, set also interpolated position so that there is no jitter
240         // When not inside the simulation loop, this may lead to erratic movement of parented rigidbodies
241         // so skip in that case. Exception made before first simulation tick so that interpolation position
242         // of e.g. instantiated prefabs will be correct from the start
243         if (!hasSimulated_ || physicsWorld_->IsSimulating())
244         {
245             btTransform interpTrans = body_->getInterpolationWorldTransform();
246             interpTrans.setOrigin(worldTrans.getOrigin());
247             body_->setInterpolationWorldTransform(interpTrans);
248         }
249 
250         Activate();
251         MarkNetworkUpdate();
252     }
253 }
254 
SetRotation(const Quaternion & rotation)255 void RigidBody::SetRotation(const Quaternion& rotation)
256 {
257     if (body_)
258     {
259         Vector3 oldPosition = GetPosition();
260         btTransform& worldTrans = body_->getWorldTransform();
261         worldTrans.setRotation(ToBtQuaternion(rotation));
262         if (!centerOfMass_.Equals(Vector3::ZERO))
263             worldTrans.setOrigin(ToBtVector3(oldPosition + rotation * centerOfMass_));
264 
265         if (!hasSimulated_ || physicsWorld_->IsSimulating())
266         {
267             btTransform interpTrans = body_->getInterpolationWorldTransform();
268             interpTrans.setRotation(worldTrans.getRotation());
269             if (!centerOfMass_.Equals(Vector3::ZERO))
270                 interpTrans.setOrigin(worldTrans.getOrigin());
271             body_->setInterpolationWorldTransform(interpTrans);
272         }
273 
274         body_->updateInertiaTensor();
275 
276         Activate();
277         MarkNetworkUpdate();
278     }
279 }
280 
SetTransform(const Vector3 & position,const Quaternion & rotation)281 void RigidBody::SetTransform(const Vector3& position, const Quaternion& rotation)
282 {
283     if (body_)
284     {
285         btTransform& worldTrans = body_->getWorldTransform();
286         worldTrans.setRotation(ToBtQuaternion(rotation));
287         worldTrans.setOrigin(ToBtVector3(position + rotation * centerOfMass_));
288 
289         if (!hasSimulated_ || physicsWorld_->IsSimulating())
290         {
291             btTransform interpTrans = body_->getInterpolationWorldTransform();
292             interpTrans.setOrigin(worldTrans.getOrigin());
293             interpTrans.setRotation(worldTrans.getRotation());
294             body_->setInterpolationWorldTransform(interpTrans);
295         }
296 
297         body_->updateInertiaTensor();
298 
299         Activate();
300         MarkNetworkUpdate();
301     }
302 }
303 
SetLinearVelocity(const Vector3 & velocity)304 void RigidBody::SetLinearVelocity(const Vector3& velocity)
305 {
306     if (body_)
307     {
308         body_->setLinearVelocity(ToBtVector3(velocity));
309         if (velocity != Vector3::ZERO)
310             Activate();
311         MarkNetworkUpdate();
312     }
313 }
314 
SetLinearFactor(const Vector3 & factor)315 void RigidBody::SetLinearFactor(const Vector3& factor)
316 {
317     if (body_)
318     {
319         body_->setLinearFactor(ToBtVector3(factor));
320         MarkNetworkUpdate();
321     }
322 }
323 
SetLinearRestThreshold(float threshold)324 void RigidBody::SetLinearRestThreshold(float threshold)
325 {
326     if (body_)
327     {
328         body_->setSleepingThresholds(threshold, body_->getAngularSleepingThreshold());
329         MarkNetworkUpdate();
330     }
331 }
332 
SetLinearDamping(float damping)333 void RigidBody::SetLinearDamping(float damping)
334 {
335     if (body_)
336     {
337         body_->setDamping(damping, body_->getAngularDamping());
338         MarkNetworkUpdate();
339     }
340 }
341 
SetAngularVelocity(const Vector3 & velocity)342 void RigidBody::SetAngularVelocity(const Vector3& velocity)
343 {
344     if (body_)
345     {
346         body_->setAngularVelocity(ToBtVector3(velocity));
347         if (velocity != Vector3::ZERO)
348             Activate();
349         MarkNetworkUpdate();
350     }
351 }
352 
SetAngularFactor(const Vector3 & factor)353 void RigidBody::SetAngularFactor(const Vector3& factor)
354 {
355     if (body_)
356     {
357         body_->setAngularFactor(ToBtVector3(factor));
358         MarkNetworkUpdate();
359     }
360 }
361 
SetAngularRestThreshold(float threshold)362 void RigidBody::SetAngularRestThreshold(float threshold)
363 {
364     if (body_)
365     {
366         body_->setSleepingThresholds(body_->getLinearSleepingThreshold(), threshold);
367         MarkNetworkUpdate();
368     }
369 }
370 
SetAngularDamping(float damping)371 void RigidBody::SetAngularDamping(float damping)
372 {
373     if (body_)
374     {
375         body_->setDamping(body_->getLinearDamping(), damping);
376         MarkNetworkUpdate();
377     }
378 }
379 
SetFriction(float friction)380 void RigidBody::SetFriction(float friction)
381 {
382     if (body_)
383     {
384         body_->setFriction(friction);
385         MarkNetworkUpdate();
386     }
387 }
388 
SetAnisotropicFriction(const Vector3 & friction)389 void RigidBody::SetAnisotropicFriction(const Vector3& friction)
390 {
391     if (body_)
392     {
393         body_->setAnisotropicFriction(ToBtVector3(friction));
394         MarkNetworkUpdate();
395     }
396 }
397 
SetRollingFriction(float friction)398 void RigidBody::SetRollingFriction(float friction)
399 {
400     if (body_)
401     {
402         body_->setRollingFriction(friction);
403         MarkNetworkUpdate();
404     }
405 }
406 
SetRestitution(float restitution)407 void RigidBody::SetRestitution(float restitution)
408 {
409     if (body_)
410     {
411         body_->setRestitution(restitution);
412         MarkNetworkUpdate();
413     }
414 }
415 
SetContactProcessingThreshold(float threshold)416 void RigidBody::SetContactProcessingThreshold(float threshold)
417 {
418     if (body_)
419     {
420         body_->setContactProcessingThreshold(threshold);
421         MarkNetworkUpdate();
422     }
423 }
424 
SetCcdRadius(float radius)425 void RigidBody::SetCcdRadius(float radius)
426 {
427     radius = Max(radius, 0.0f);
428     if (body_)
429     {
430         body_->setCcdSweptSphereRadius(radius);
431         MarkNetworkUpdate();
432     }
433 }
434 
SetCcdMotionThreshold(float threshold)435 void RigidBody::SetCcdMotionThreshold(float threshold)
436 {
437     threshold = Max(threshold, 0.0f);
438     if (body_)
439     {
440         body_->setCcdMotionThreshold(threshold);
441         MarkNetworkUpdate();
442     }
443 }
444 
SetUseGravity(bool enable)445 void RigidBody::SetUseGravity(bool enable)
446 {
447     if (enable != useGravity_)
448     {
449         useGravity_ = enable;
450         UpdateGravity();
451         MarkNetworkUpdate();
452     }
453 }
454 
SetGravityOverride(const Vector3 & gravity)455 void RigidBody::SetGravityOverride(const Vector3& gravity)
456 {
457     if (gravity != gravityOverride_)
458     {
459         gravityOverride_ = gravity;
460         UpdateGravity();
461         MarkNetworkUpdate();
462     }
463 }
464 
SetKinematic(bool enable)465 void RigidBody::SetKinematic(bool enable)
466 {
467     if (enable != kinematic_)
468     {
469         kinematic_ = enable;
470         AddBodyToWorld();
471         MarkNetworkUpdate();
472     }
473 }
474 
SetTrigger(bool enable)475 void RigidBody::SetTrigger(bool enable)
476 {
477     if (enable != trigger_)
478     {
479         trigger_ = enable;
480         AddBodyToWorld();
481         MarkNetworkUpdate();
482     }
483 }
484 
SetCollisionLayer(unsigned layer)485 void RigidBody::SetCollisionLayer(unsigned layer)
486 {
487     if (layer != collisionLayer_)
488     {
489         collisionLayer_ = layer;
490         AddBodyToWorld();
491         MarkNetworkUpdate();
492     }
493 }
494 
SetCollisionMask(unsigned mask)495 void RigidBody::SetCollisionMask(unsigned mask)
496 {
497     if (mask != collisionMask_)
498     {
499         collisionMask_ = mask;
500         AddBodyToWorld();
501         MarkNetworkUpdate();
502     }
503 }
504 
SetCollisionLayerAndMask(unsigned layer,unsigned mask)505 void RigidBody::SetCollisionLayerAndMask(unsigned layer, unsigned mask)
506 {
507     if (layer != collisionLayer_ || mask != collisionMask_)
508     {
509         collisionLayer_ = layer;
510         collisionMask_ = mask;
511         AddBodyToWorld();
512         MarkNetworkUpdate();
513     }
514 }
515 
SetCollisionEventMode(CollisionEventMode mode)516 void RigidBody::SetCollisionEventMode(CollisionEventMode mode)
517 {
518     collisionEventMode_ = mode;
519     MarkNetworkUpdate();
520 }
521 
ApplyForce(const Vector3 & force)522 void RigidBody::ApplyForce(const Vector3& force)
523 {
524     if (body_ && force != Vector3::ZERO)
525     {
526         Activate();
527         body_->applyCentralForce(ToBtVector3(force));
528     }
529 }
530 
ApplyForce(const Vector3 & force,const Vector3 & position)531 void RigidBody::ApplyForce(const Vector3& force, const Vector3& position)
532 {
533     if (body_ && force != Vector3::ZERO)
534     {
535         Activate();
536         body_->applyForce(ToBtVector3(force), ToBtVector3(position - centerOfMass_));
537     }
538 }
539 
ApplyTorque(const Vector3 & torque)540 void RigidBody::ApplyTorque(const Vector3& torque)
541 {
542     if (body_ && torque != Vector3::ZERO)
543     {
544         Activate();
545         body_->applyTorque(ToBtVector3(torque));
546     }
547 }
548 
ApplyImpulse(const Vector3 & impulse)549 void RigidBody::ApplyImpulse(const Vector3& impulse)
550 {
551     if (body_ && impulse != Vector3::ZERO)
552     {
553         Activate();
554         body_->applyCentralImpulse(ToBtVector3(impulse));
555     }
556 }
557 
ApplyImpulse(const Vector3 & impulse,const Vector3 & position)558 void RigidBody::ApplyImpulse(const Vector3& impulse, const Vector3& position)
559 {
560     if (body_ && impulse != Vector3::ZERO)
561     {
562         Activate();
563         body_->applyImpulse(ToBtVector3(impulse), ToBtVector3(position - centerOfMass_));
564     }
565 }
566 
ApplyTorqueImpulse(const Vector3 & torque)567 void RigidBody::ApplyTorqueImpulse(const Vector3& torque)
568 {
569     if (body_ && torque != Vector3::ZERO)
570     {
571         Activate();
572         body_->applyTorqueImpulse(ToBtVector3(torque));
573     }
574 }
575 
ResetForces()576 void RigidBody::ResetForces()
577 {
578     if (body_)
579         body_->clearForces();
580 }
581 
Activate()582 void RigidBody::Activate()
583 {
584     if (body_ && mass_ > 0.0f)
585         body_->activate(true);
586 }
587 
ReAddBodyToWorld()588 void RigidBody::ReAddBodyToWorld()
589 {
590     if (body_ && inWorld_)
591         AddBodyToWorld();
592 }
593 
DisableMassUpdate()594 void RigidBody::DisableMassUpdate()
595 {
596     enableMassUpdate_ = false;
597 }
598 
EnableMassUpdate()599 void RigidBody::EnableMassUpdate()
600 {
601     if (!enableMassUpdate_)
602     {
603         enableMassUpdate_ = true;
604         UpdateMass();
605     }
606 }
607 
GetPosition() const608 Vector3 RigidBody::GetPosition() const
609 {
610     if (body_)
611     {
612         const btTransform& transform = body_->getWorldTransform();
613         return ToVector3(transform.getOrigin()) - ToQuaternion(transform.getRotation()) * centerOfMass_;
614     }
615     else
616         return Vector3::ZERO;
617 }
618 
GetRotation() const619 Quaternion RigidBody::GetRotation() const
620 {
621     return body_ ? ToQuaternion(body_->getWorldTransform().getRotation()) : Quaternion::IDENTITY;
622 }
623 
GetLinearVelocity() const624 Vector3 RigidBody::GetLinearVelocity() const
625 {
626     return body_ ? ToVector3(body_->getLinearVelocity()) : Vector3::ZERO;
627 }
628 
GetLinearFactor() const629 Vector3 RigidBody::GetLinearFactor() const
630 {
631     return body_ ? ToVector3(body_->getLinearFactor()) : Vector3::ZERO;
632 }
633 
GetVelocityAtPoint(const Vector3 & position) const634 Vector3 RigidBody::GetVelocityAtPoint(const Vector3& position) const
635 {
636     return body_ ? ToVector3(body_->getVelocityInLocalPoint(ToBtVector3(position - centerOfMass_))) : Vector3::ZERO;
637 }
638 
GetLinearRestThreshold() const639 float RigidBody::GetLinearRestThreshold() const
640 {
641     return body_ ? body_->getLinearSleepingThreshold() : 0.0f;
642 }
643 
GetLinearDamping() const644 float RigidBody::GetLinearDamping() const
645 {
646     return body_ ? body_->getLinearDamping() : 0.0f;
647 }
648 
GetAngularVelocity() const649 Vector3 RigidBody::GetAngularVelocity() const
650 {
651     return body_ ? ToVector3(body_->getAngularVelocity()) : Vector3::ZERO;
652 }
653 
GetAngularFactor() const654 Vector3 RigidBody::GetAngularFactor() const
655 {
656     return body_ ? ToVector3(body_->getAngularFactor()) : Vector3::ZERO;
657 }
658 
GetAngularRestThreshold() const659 float RigidBody::GetAngularRestThreshold() const
660 {
661     return body_ ? body_->getAngularSleepingThreshold() : 0.0f;
662 }
663 
GetAngularDamping() const664 float RigidBody::GetAngularDamping() const
665 {
666     return body_ ? body_->getAngularDamping() : 0.0f;
667 }
668 
GetFriction() const669 float RigidBody::GetFriction() const
670 {
671     return body_ ? body_->getFriction() : 0.0f;
672 }
673 
GetAnisotropicFriction() const674 Vector3 RigidBody::GetAnisotropicFriction() const
675 {
676     return body_ ? ToVector3(body_->getAnisotropicFriction()) : Vector3::ZERO;
677 }
678 
GetRollingFriction() const679 float RigidBody::GetRollingFriction() const
680 {
681     return body_ ? body_->getRollingFriction() : 0.0f;
682 }
683 
GetRestitution() const684 float RigidBody::GetRestitution() const
685 {
686     return body_ ? body_->getRestitution() : 0.0f;
687 }
688 
GetContactProcessingThreshold() const689 float RigidBody::GetContactProcessingThreshold() const
690 {
691     return body_ ? body_->getContactProcessingThreshold() : 0.0f;
692 }
693 
GetCcdRadius() const694 float RigidBody::GetCcdRadius() const
695 {
696     return body_ ? body_->getCcdSweptSphereRadius() : 0.0f;
697 }
698 
GetCcdMotionThreshold() const699 float RigidBody::GetCcdMotionThreshold() const
700 {
701     return body_ ? body_->getCcdMotionThreshold() : 0.0f;
702 }
703 
IsActive() const704 bool RigidBody::IsActive() const
705 {
706     return body_ ? body_->isActive() : false;
707 }
708 
GetCollidingBodies(PODVector<RigidBody * > & result) const709 void RigidBody::GetCollidingBodies(PODVector<RigidBody*>& result) const
710 {
711     if (physicsWorld_)
712         physicsWorld_->GetCollidingBodies(result, this);
713     else
714         result.Clear();
715 }
716 
ApplyWorldTransform(const Vector3 & newWorldPosition,const Quaternion & newWorldRotation)717 void RigidBody::ApplyWorldTransform(const Vector3& newWorldPosition, const Quaternion& newWorldRotation)
718 {
719     // In case of holding an extra reference to the RigidBody, this could be called in a situation
720     // where node is already null
721     if (!node_ || !physicsWorld_)
722         return;
723 
724     physicsWorld_->SetApplyingTransforms(true);
725 
726     // Apply transform to the SmoothedTransform component instead of node transform if available
727     if (smoothedTransform_)
728     {
729         smoothedTransform_->SetTargetWorldPosition(newWorldPosition);
730         smoothedTransform_->SetTargetWorldRotation(newWorldRotation);
731         lastPosition_ = newWorldPosition;
732         lastRotation_ = newWorldRotation;
733     }
734     else
735     {
736         node_->SetWorldPosition(newWorldPosition);
737         node_->SetWorldRotation(newWorldRotation);
738         lastPosition_ = node_->GetWorldPosition();
739         lastRotation_ = node_->GetWorldRotation();
740     }
741 
742     physicsWorld_->SetApplyingTransforms(false);
743 }
744 
UpdateMass()745 void RigidBody::UpdateMass()
746 {
747     if (!body_ || !enableMassUpdate_)
748         return;
749 
750     btTransform principal;
751     principal.setRotation(btQuaternion::getIdentity());
752     principal.setOrigin(btVector3(0.0f, 0.0f, 0.0f));
753 
754     // Calculate center of mass shift from all the collision shapes
755     unsigned numShapes = (unsigned)compoundShape_->getNumChildShapes();
756     if (numShapes)
757     {
758         PODVector<float> masses(numShapes);
759         for (unsigned i = 0; i < numShapes; ++i)
760         {
761             // The actual mass does not matter, divide evenly between child shapes
762             masses[i] = 1.0f;
763         }
764 
765         btVector3 inertia(0.0f, 0.0f, 0.0f);
766         compoundShape_->calculatePrincipalAxisTransform(&masses[0], principal, inertia);
767     }
768 
769     // Add child shapes to shifted compound shape with adjusted offset
770     while (shiftedCompoundShape_->getNumChildShapes())
771         shiftedCompoundShape_->removeChildShapeByIndex(shiftedCompoundShape_->getNumChildShapes() - 1);
772     for (unsigned i = 0; i < numShapes; ++i)
773     {
774         btTransform adjusted = compoundShape_->getChildTransform(i);
775         adjusted.setOrigin(adjusted.getOrigin() - principal.getOrigin());
776         shiftedCompoundShape_->addChildShape(adjusted, compoundShape_->getChildShape(i));
777     }
778 
779     // If shifted compound shape has only one child with no offset/rotation, use the child shape
780     // directly as the rigid body collision shape for better collision detection performance
781     bool useCompound = !numShapes || numShapes > 1;
782     if (!useCompound)
783     {
784         const btTransform& childTransform = shiftedCompoundShape_->getChildTransform(0);
785         if (!ToVector3(childTransform.getOrigin()).Equals(Vector3::ZERO) ||
786             !ToQuaternion(childTransform.getRotation()).Equals(Quaternion::IDENTITY))
787             useCompound = true;
788     }
789 
790     btCollisionShape* oldCollisionShape = body_->getCollisionShape();
791     body_->setCollisionShape(useCompound ? shiftedCompoundShape_.Get() : shiftedCompoundShape_->getChildShape(0));
792 
793     // If we have one shape and this is a triangle mesh, we use a custom material callback in order to adjust internal edges
794     if (!useCompound && body_->getCollisionShape()->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE &&
795         physicsWorld_->GetInternalEdge())
796         body_->setCollisionFlags(body_->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
797     else
798         body_->setCollisionFlags(body_->getCollisionFlags() & ~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
799 
800     // Reapply rigid body position with new center of mass shift
801     Vector3 oldPosition = GetPosition();
802     centerOfMass_ = ToVector3(principal.getOrigin());
803     SetPosition(oldPosition);
804 
805     // Calculate final inertia
806     btVector3 localInertia(0.0f, 0.0f, 0.0f);
807     if (mass_ > 0.0f)
808         shiftedCompoundShape_->calculateLocalInertia(mass_, localInertia);
809     body_->setMassProps(mass_, localInertia);
810     body_->updateInertiaTensor();
811 
812     // Reapply constraint positions for new center of mass shift
813     if (node_)
814     {
815         for (PODVector<Constraint*>::Iterator i = constraints_.Begin(); i != constraints_.End(); ++i)
816             (*i)->ApplyFrames();
817     }
818 
819     // Readd body to world to reset Bullet collision cache if collision shape was changed (issue #2064)
820     if (inWorld_ && body_->getCollisionShape() != oldCollisionShape && physicsWorld_)
821     {
822         btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
823         world->removeRigidBody(body_.Get());
824         world->addRigidBody(body_.Get(), (short)collisionLayer_, (short)collisionMask_);
825     }
826 }
827 
UpdateGravity()828 void RigidBody::UpdateGravity()
829 {
830     if (physicsWorld_ && body_)
831     {
832         btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
833 
834         int flags = body_->getFlags();
835         if (useGravity_ && gravityOverride_ == Vector3::ZERO)
836             flags &= ~BT_DISABLE_WORLD_GRAVITY;
837         else
838             flags |= BT_DISABLE_WORLD_GRAVITY;
839         body_->setFlags(flags);
840 
841         if (useGravity_)
842         {
843             // If override vector is zero, use world's gravity
844             if (gravityOverride_ == Vector3::ZERO)
845                 body_->setGravity(world->getGravity());
846             else
847                 body_->setGravity(ToBtVector3(gravityOverride_));
848         }
849         else
850             body_->setGravity(btVector3(0.0f, 0.0f, 0.0f));
851     }
852 }
853 
SetNetAngularVelocityAttr(const PODVector<unsigned char> & value)854 void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
855 {
856     float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
857     MemoryBuffer buf(value);
858     SetAngularVelocity(buf.ReadPackedVector3(maxVelocity));
859 }
860 
GetNetAngularVelocityAttr() const861 const PODVector<unsigned char>& RigidBody::GetNetAngularVelocityAttr() const
862 {
863     float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
864     attrBuffer_.Clear();
865     attrBuffer_.WritePackedVector3(GetAngularVelocity(), maxVelocity);
866     return attrBuffer_.GetBuffer();
867 }
868 
AddConstraint(Constraint * constraint)869 void RigidBody::AddConstraint(Constraint* constraint)
870 {
871     constraints_.Push(constraint);
872 }
873 
RemoveConstraint(Constraint * constraint)874 void RigidBody::RemoveConstraint(Constraint* constraint)
875 {
876     constraints_.Remove(constraint);
877     // A constraint being removed should possibly cause the object to eg. start falling, so activate
878     Activate();
879 }
880 
ReleaseBody()881 void RigidBody::ReleaseBody()
882 {
883     if (body_)
884     {
885         // Release all constraints which refer to this body
886         // Make a copy for iteration
887         PODVector<Constraint*> constraints = constraints_;
888         for (PODVector<Constraint*>::Iterator i = constraints.Begin(); i != constraints.End(); ++i)
889             (*i)->ReleaseConstraint();
890 
891         RemoveBodyFromWorld();
892 
893         body_.Reset();
894     }
895 }
896 
OnMarkedDirty(Node * node)897 void RigidBody::OnMarkedDirty(Node* node)
898 {
899     // If node transform changes, apply it back to the physics transform. However, do not do this when a SmoothedTransform
900     // is in use, because in that case the node transform will be constantly updated into smoothed, possibly non-physical
901     // states; rather follow the SmoothedTransform target transform directly
902     // Also, for kinematic objects Bullet asks the position from us, so we do not need to apply ourselves
903     // (exception: initial setting of transform)
904     if ((!kinematic_ || !hasSimulated_) && (!physicsWorld_ || !physicsWorld_->IsApplyingTransforms()) && !smoothedTransform_)
905     {
906         // Physics operations are not safe from worker threads
907         Scene* scene = GetScene();
908         if (scene && scene->IsThreadedUpdate())
909         {
910             scene->DelayedMarkedDirty(this);
911             return;
912         }
913 
914         // Check if transform has changed from the last one set in ApplyWorldTransform()
915         Vector3 newPosition = node_->GetWorldPosition();
916         Quaternion newRotation = node_->GetWorldRotation();
917 
918         if (!newRotation.Equals(lastRotation_))
919         {
920             lastRotation_ = newRotation;
921             SetRotation(newRotation);
922         }
923         if (!newPosition.Equals(lastPosition_))
924         {
925             lastPosition_ = newPosition;
926             SetPosition(newPosition);
927         }
928     }
929 }
930 
OnNodeSet(Node * node)931 void RigidBody::OnNodeSet(Node* node)
932 {
933     if (node)
934         node->AddListener(this);
935 }
936 
OnSceneSet(Scene * scene)937 void RigidBody::OnSceneSet(Scene* scene)
938 {
939     if (scene)
940     {
941         if (scene == node_)
942             URHO3D_LOGWARNING(GetTypeName() + " should not be created to the root scene node");
943 
944         physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
945         physicsWorld_->AddRigidBody(this);
946 
947         AddBodyToWorld();
948     }
949     else
950     {
951         ReleaseBody();
952 
953         if (physicsWorld_)
954             physicsWorld_->RemoveRigidBody(this);
955     }
956 }
957 
AddBodyToWorld()958 void RigidBody::AddBodyToWorld()
959 {
960     if (!physicsWorld_)
961         return;
962 
963     URHO3D_PROFILE(AddBodyToWorld);
964 
965     if (mass_ < 0.0f)
966         mass_ = 0.0f;
967 
968     if (body_)
969         RemoveBodyFromWorld();
970     else
971     {
972         // Correct inertia will be calculated below
973         btVector3 localInertia(0.0f, 0.0f, 0.0f);
974         body_ = new btRigidBody(mass_, this, shiftedCompoundShape_.Get(), localInertia);
975         body_->setUserPointer(this);
976 
977         // Check for existence of the SmoothedTransform component, which should be created by now in network client mode.
978         // If it exists, subscribe to its change events
979         smoothedTransform_ = GetComponent<SmoothedTransform>();
980         if (smoothedTransform_)
981         {
982             SubscribeToEvent(smoothedTransform_, E_TARGETPOSITION, URHO3D_HANDLER(RigidBody, HandleTargetPosition));
983             SubscribeToEvent(smoothedTransform_, E_TARGETROTATION, URHO3D_HANDLER(RigidBody, HandleTargetRotation));
984         }
985 
986         // Check if CollisionShapes already exist in the node and add them to the compound shape.
987         // Do not update mass yet, but do it once all shapes have been added
988         PODVector<CollisionShape*> shapes;
989         node_->GetComponents<CollisionShape>(shapes);
990         for (PODVector<CollisionShape*>::Iterator i = shapes.Begin(); i != shapes.End(); ++i)
991             (*i)->NotifyRigidBody(false);
992 
993         // Check if this node contains Constraint components that were waiting for the rigid body to be created, and signal them
994         // to create themselves now
995         PODVector<Constraint*> constraints;
996         node_->GetComponents<Constraint>(constraints);
997         for (PODVector<Constraint*>::Iterator i = constraints.Begin(); i != constraints.End(); ++i)
998             (*i)->CreateConstraint();
999     }
1000 
1001     UpdateMass();
1002     UpdateGravity();
1003 
1004     int flags = body_->getCollisionFlags();
1005     if (trigger_)
1006         flags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
1007     else
1008         flags &= ~btCollisionObject::CF_NO_CONTACT_RESPONSE;
1009     if (kinematic_)
1010         flags |= btCollisionObject::CF_KINEMATIC_OBJECT;
1011     else
1012         flags &= ~btCollisionObject::CF_KINEMATIC_OBJECT;
1013     body_->setCollisionFlags(flags);
1014     body_->forceActivationState(kinematic_ ? DISABLE_DEACTIVATION : ISLAND_SLEEPING);
1015 
1016     if (!IsEnabledEffective())
1017         return;
1018 
1019     btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
1020     world->addRigidBody(body_.Get(), (short)collisionLayer_, (short)collisionMask_);
1021     inWorld_ = true;
1022     readdBody_ = false;
1023     hasSimulated_ = false;
1024 
1025     if (mass_ > 0.0f)
1026         Activate();
1027     else
1028     {
1029         SetLinearVelocity(Vector3::ZERO);
1030         SetAngularVelocity(Vector3::ZERO);
1031     }
1032 }
1033 
RemoveBodyFromWorld()1034 void RigidBody::RemoveBodyFromWorld()
1035 {
1036     if (physicsWorld_ && body_ && inWorld_)
1037     {
1038         btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld();
1039         world->removeRigidBody(body_.Get());
1040         inWorld_ = false;
1041     }
1042 }
1043 
HandleTargetPosition(StringHash eventType,VariantMap & eventData)1044 void RigidBody::HandleTargetPosition(StringHash eventType, VariantMap& eventData)
1045 {
1046     // Copy the smoothing target position to the rigid body
1047     if (!physicsWorld_ || !physicsWorld_->IsApplyingTransforms())
1048         SetPosition(static_cast<SmoothedTransform*>(GetEventSender())->GetTargetWorldPosition());
1049 }
1050 
HandleTargetRotation(StringHash eventType,VariantMap & eventData)1051 void RigidBody::HandleTargetRotation(StringHash eventType, VariantMap& eventData)
1052 {
1053     // Copy the smoothing target rotation to the rigid body
1054     if (!physicsWorld_ || !physicsWorld_->IsApplyingTransforms())
1055         SetRotation(static_cast<SmoothedTransform*>(GetEventSender())->GetTargetWorldRotation());
1056 }
1057 
1058 }
1059