RigidBody.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "CollisionShape.h"
  25. #include "Context.h"
  26. #include "Log.h"
  27. #include "PhysicsWorld.h"
  28. #include "ResourceCache.h"
  29. #include "ResourceEvents.h"
  30. #include "RigidBody.h"
  31. #include "Scene.h"
  32. #include "StringUtils.h"
  33. #include "XMLElement.h"
  34. #include <ode/ode.h>
  35. #include "DebugNew.h"
  36. static const float DEFAULT_MASS = 1.0f;
  37. static const std::string modeNames[] =
  38. {
  39. "static",
  40. "dynamic",
  41. "kinematic"
  42. };
  43. OBJECTTYPESTATIC(RigidBody);
  44. RigidBody::RigidBody(Context* context) :
  45. Component(context),
  46. mass_(DEFAULT_MASS),
  47. body_(0),
  48. inPostStep_(false)
  49. {
  50. }
  51. RigidBody::~RigidBody()
  52. {
  53. ReleaseBody();
  54. if (physicsWorld_)
  55. physicsWorld_->RemoveRigidBody(this);
  56. }
  57. void RigidBody::RegisterObject(Context* context)
  58. {
  59. context->RegisterFactory<RigidBody>();
  60. ATTRIBUTE(RigidBody, VAR_FLOAT, "Mass", mass_, DEFAULT_MASS);
  61. ACCESSOR_ATTRIBUTE_MODE(RigidBody, VAR_VECTOR3, "Physics Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_SERIALIZATION);
  62. ACCESSOR_ATTRIBUTE_MODE(RigidBody, VAR_QUATERNION, "Physics Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_SERIALIZATION);
  63. ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector3, Vector3::ZERO);
  64. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f);
  65. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f);
  66. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Scale", GetLinearDampingScale, SetLinearDampingScale, float, 0.0f);
  67. ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Angular Velocity", GetAngularVelocity, SetAngularVelocity, Vector3, Vector3::ZERO);
  68. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Rest Threshold", GetAngularRestThreshold, SetAngularRestThreshold, float, 0.01f);
  69. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Threshold", GetAngularDampingThreshold, SetAngularDampingThreshold, float, 0.01f);
  70. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Scale", GetAngularDampingScale, SetAngularDampingScale, float, 0.0f);
  71. ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Max Velocity", GetAngularMaxVelocity, SetAngularMaxVelocity, float, M_INFINITY);
  72. ACCESSOR_ATTRIBUTE(RigidBody, VAR_BOOL, "Is Active", IsActive, SetActive, bool, true);
  73. }
  74. void RigidBody::SetMass(float mass)
  75. {
  76. mass_ = Max(mass, 0.0f);
  77. UpdateMass();
  78. }
  79. void RigidBody::SetPosition(Vector3 position)
  80. {
  81. if (body_)
  82. {
  83. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  84. previousPosition_ = position;
  85. }
  86. }
  87. void RigidBody::SetRotation(Quaternion rotation)
  88. {
  89. if (body_)
  90. {
  91. dBodySetQuaternion(body_, rotation.GetData());
  92. previousRotation_ = rotation;
  93. }
  94. }
  95. void RigidBody::SetTransform(const Vector3& position, const Quaternion& rotation)
  96. {
  97. if (body_)
  98. {
  99. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  100. dBodySetQuaternion(body_, rotation.GetData());
  101. previousPosition_ = position;
  102. previousRotation_ = rotation;
  103. }
  104. }
  105. void RigidBody::SetLinearVelocity(Vector3 velocity)
  106. {
  107. if (body_)
  108. dBodySetLinearVel(body_, velocity.x_, velocity.y_, velocity.z_);
  109. }
  110. void RigidBody::SetLinearRestThreshold(float threshold)
  111. {
  112. if (body_)
  113. dBodySetAutoDisableLinearThreshold(body_, threshold);
  114. }
  115. void RigidBody::SetLinearDampingThreshold(float threshold)
  116. {
  117. if (body_)
  118. dBodySetLinearDampingThreshold(body_, threshold);
  119. }
  120. void RigidBody::SetLinearDampingScale(float scale)
  121. {
  122. if (body_)
  123. dBodySetLinearDamping(body_, scale);
  124. }
  125. void RigidBody::SetAngularVelocity(Vector3 velocity)
  126. {
  127. if (body_)
  128. dBodySetAngularVel(body_, velocity.x_, velocity.y_, velocity.z_);
  129. }
  130. void RigidBody::SetAngularRestThreshold(float threshold)
  131. {
  132. if (body_)
  133. dBodySetAutoDisableAngularThreshold(body_, threshold);
  134. }
  135. void RigidBody::SetAngularDampingThreshold(float threshold)
  136. {
  137. if (body_)
  138. dBodySetAngularDampingThreshold(body_, threshold);
  139. }
  140. void RigidBody::SetAngularDampingScale(float scale)
  141. {
  142. if (body_)
  143. dBodySetAngularDamping(body_, scale);
  144. }
  145. void RigidBody::SetAngularMaxVelocity(float velocity)
  146. {
  147. if (body_)
  148. dBodySetMaxAngularSpeed(body_, velocity);
  149. }
  150. void RigidBody::SetActive(bool active)
  151. {
  152. if (body_)
  153. {
  154. if ((active) && (!dBodyIsEnabled(body_)))
  155. dBodyEnable(body_);
  156. else if ((!active) && (dBodyIsEnabled(body_)))
  157. dBodyDisable(body_);
  158. }
  159. }
  160. void RigidBody::ApplyForce(const Vector3& force)
  161. {
  162. if (force == Vector3::ZERO)
  163. return;
  164. if (body_)
  165. {
  166. SetActive(true);
  167. dBodyAddForce(body_, force.x_, force.y_, force.z_);
  168. }
  169. }
  170. void RigidBody::ApplyForceAtPosition(const Vector3& force, const Vector3& position)
  171. {
  172. if (force == Vector3::ZERO)
  173. return;
  174. if (body_)
  175. {
  176. SetActive(true);
  177. dBodyAddForceAtRelPos(body_, force.x_, force.y_, force.z_, position.x_, position.y_, position.z_);
  178. }
  179. }
  180. void RigidBody::ApplyTorque(const Vector3& torque)
  181. {
  182. if (torque == Vector3::ZERO)
  183. return;
  184. if (body_)
  185. {
  186. SetActive(true);
  187. dBodyAddTorque(body_, torque.x_, torque.y_, torque.z_);
  188. }
  189. }
  190. void RigidBody::ResetForces()
  191. {
  192. if (body_)
  193. {
  194. dBodySetForce(body_, 0.0f, 0.0f, 0.0f);
  195. dBodySetTorque(body_, 0.0f, 0.0f, 0.0f);
  196. }
  197. }
  198. Vector3 RigidBody::GetPosition() const
  199. {
  200. if (body_)
  201. {
  202. const dReal* pos = dBodyGetPosition(body_);
  203. return Vector3(pos[0], pos[1], pos[2]);
  204. }
  205. else return node_->GetWorldPosition();
  206. }
  207. Quaternion RigidBody::GetRotation() const
  208. {
  209. if (body_)
  210. {
  211. const dReal* quat = dBodyGetQuaternion(body_);
  212. return Quaternion(quat[0], quat[1], quat[2], quat[3]);
  213. }
  214. else return node_->GetWorldRotation();
  215. }
  216. Vector3 RigidBody::GetLinearVelocity() const
  217. {
  218. if (body_)
  219. {
  220. const dReal* vel = dBodyGetLinearVel(body_);
  221. return Vector3(vel[0], vel[1], vel[2]);
  222. }
  223. else
  224. return Vector3::ZERO;
  225. }
  226. float RigidBody::GetLinearRestThreshold() const
  227. {
  228. if (body_)
  229. return dBodyGetAutoDisableLinearThreshold(body_);
  230. else
  231. return 0.0f;
  232. }
  233. float RigidBody::GetLinearDampingThreshold() const
  234. {
  235. if (body_)
  236. return dBodyGetLinearDampingThreshold(body_);
  237. else
  238. return 0.0f;
  239. }
  240. float RigidBody::GetLinearDampingScale() const
  241. {
  242. if (body_)
  243. return dBodyGetLinearDamping(body_);
  244. else
  245. return 0.0f;
  246. }
  247. Vector3 RigidBody::GetAngularVelocity() const
  248. {
  249. if (body_)
  250. {
  251. const dReal* vel = dBodyGetAngularVel(body_);
  252. return Vector3(vel[0], vel[1], vel[2]);
  253. }
  254. else
  255. return Vector3::ZERO;
  256. }
  257. float RigidBody::GetAngularRestThreshold() const
  258. {
  259. if (body_)
  260. return dBodyGetAutoDisableAngularThreshold(body_);
  261. else
  262. return 0.0f;
  263. }
  264. float RigidBody::GetAngularDampingThreshold() const
  265. {
  266. if (body_)
  267. return dBodyGetAngularDampingThreshold(body_);
  268. else
  269. return 0.0f;
  270. }
  271. float RigidBody::GetAngularDampingScale() const
  272. {
  273. if (body_)
  274. return dBodyGetAngularDamping(body_);
  275. else
  276. return 0.0f;
  277. }
  278. float RigidBody::GetAngularMaxVelocity() const
  279. {
  280. if (body_)
  281. return dBodyGetMaxAngularSpeed(body_);
  282. else
  283. return 0.0f;
  284. }
  285. bool RigidBody::IsActive() const
  286. {
  287. if (body_)
  288. return dBodyIsEnabled(body_) != 0;
  289. else
  290. return false;
  291. }
  292. void RigidBody::OnMarkedDirty(Node* node)
  293. {
  294. // Clear the dirty flag by querying world position; this way we are sure to get the dirty notification immediately
  295. // also the next time the node transform changes
  296. const Vector3& position = node_->GetWorldPosition();
  297. Quaternion rotation = node_->GetWorldRotation();
  298. // Disregard node dirtying during the physics poststep, when rendering transform is synced from physics transform
  299. if (inPostStep_)
  300. return;
  301. if (body_)
  302. {
  303. if ((GetPosition() != position) || (GetRotation() != rotation))
  304. {
  305. SetActive(true);
  306. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  307. dBodySetQuaternion(body_, rotation.GetData());
  308. }
  309. previousPosition_ = position;
  310. previousRotation_ = rotation;
  311. }
  312. }
  313. void RigidBody::OnNodeSet(Node* node)
  314. {
  315. if (node)
  316. {
  317. Scene* scene = node->GetScene();
  318. if (scene)
  319. {
  320. physicsWorld_ = scene->GetComponent<PhysicsWorld>();
  321. if (physicsWorld_)
  322. physicsWorld_->AddRigidBody(this);
  323. CreateBody();
  324. }
  325. node->AddListener(this);
  326. }
  327. }
  328. void RigidBody::PreStep()
  329. {
  330. // Store the previous position for interpolation
  331. if (body_)
  332. {
  333. const dReal* pos = dBodyGetPosition(body_);
  334. const dReal* quat = dBodyGetQuaternion(body_);
  335. previousPosition_ = Vector3(pos[0], pos[1], pos[2]);
  336. previousRotation_ = Quaternion(quat[0], quat[1], quat[2], quat[3]);
  337. }
  338. }
  339. void RigidBody::PostStep(float t)
  340. {
  341. if ((body_) && (IsActive()))
  342. {
  343. inPostStep_ = true;
  344. const dReal* pos = dBodyGetPosition(body_);
  345. const dReal* quat = dBodyGetQuaternion(body_);
  346. Vector3 currentPosition(pos[0], pos[1], pos[2]);
  347. Quaternion currentRotation(quat[0], quat[1], quat[2], quat[3]);
  348. /// \todo If the node is parented, transform will not be set correctly
  349. node_->SetPosition(previousPosition_.Lerp(currentPosition, t));
  350. node_->SetRotation(previousRotation_.Slerp(currentRotation, t));
  351. inPostStep_ = false;
  352. }
  353. }
  354. void RigidBody::CreateBody()
  355. {
  356. if (!physicsWorld_)
  357. {
  358. LOGERROR("Null physics world, can not create body");
  359. return;
  360. }
  361. if (!body_)
  362. {
  363. body_ = dBodyCreate(physicsWorld_->GetWorld());
  364. // Set the user data pointer
  365. dBodySetData(body_, this);
  366. // Set rendering transform as the initial transform
  367. const Vector3& position = node_->GetWorldPosition();
  368. Quaternion rotation = node_->GetWorldRotation();
  369. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  370. dBodySetQuaternion(body_, rotation.GetData());
  371. previousPosition_ = position;
  372. previousRotation_ = rotation;
  373. // Associate geometries with the body
  374. std::vector<CollisionShape*> shapes;
  375. GetComponents<CollisionShape>(shapes);
  376. for (unsigned i = 0; i < shapes.size(); ++i)
  377. shapes[i]->UpdateTransform();
  378. }
  379. UpdateMass();
  380. }
  381. void RigidBody::ReleaseBody()
  382. {
  383. if (!body_)
  384. return;
  385. std::vector<CollisionShape*> shapes;
  386. GetComponents<CollisionShape>(shapes);
  387. // First remove rigid body associations
  388. for (unsigned i = 0; i < shapes.size(); ++i)
  389. {
  390. dGeomID geom = shapes[i]->GetGeometry();
  391. if (geom)
  392. dGeomSetBody(geom, 0);
  393. }
  394. dBodyDestroy(body_);
  395. body_ = 0;
  396. // Then update geometry transforms
  397. for (unsigned i = 0; i < shapes.size(); ++i)
  398. shapes[i]->UpdateTransform();
  399. }
  400. void RigidBody::UpdateMass()
  401. {
  402. if (!body_)
  403. return;
  404. dMass mass;
  405. dMassSetZero(&mass);
  406. float density = 1.0f;
  407. // Get all attached collision shapes to Calculate the mass
  408. std::vector<CollisionShape*> shapes;
  409. GetComponents<CollisionShape>(shapes);
  410. for (unsigned i = 0; i < shapes.size(); ++i)
  411. {
  412. CollisionShape* shape = shapes[i];
  413. dMass subMass;
  414. Vector3 size = shape->GetSize() * GetWorldScale();
  415. Vector3 offset = shape->GetPosition() * GetWorldScale();
  416. switch (shape->GetShapeType())
  417. {
  418. case SHAPE_BOX:
  419. dMassSetBox(&subMass, density, size.x_, size.y_, size.z_);
  420. break;
  421. case SHAPE_SPHERE:
  422. dMassSetSphere(&subMass, density, size.x_);
  423. break;
  424. case SHAPE_CYLINDER:
  425. dMassSetCylinder(&subMass, density, 2, size.x_, size.z_);
  426. break;
  427. case SHAPE_CAPSULE:
  428. dMassSetCapsule(&subMass, density, 2, size.x_, size.z_);
  429. break;
  430. case SHAPE_TRIANGLEMESH:
  431. dMassSetBox(&subMass, density, size.x_, size.y_, size.z_);
  432. break;
  433. }
  434. dMatrix3 rotMatrix;
  435. dRfromQ(rotMatrix, shape->GetRotation().GetData());
  436. dMassTranslate(&subMass, offset.x_, offset.y_, offset.z_);
  437. dMassRotate(&subMass, rotMatrix);
  438. dMassAdd(&mass, &subMass);
  439. }
  440. // If zero mass or no geometries, set kinematic mode
  441. if (mass.mass <= 0.0f)
  442. dBodySetKinematic(body_);
  443. else
  444. {
  445. // Translate final mass to center; anything else is unsupported in ODE
  446. dMassTranslate(&mass, -mass.c[0], -mass.c[1], -mass.c[2]);
  447. dMassAdjust(&mass, mass_);
  448. dBodySetMass(body_, &mass);
  449. }
  450. }