RigidBody.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. ID_ATTRIBUTE_MODE(RigidBody, VAR_VECTOR3, "Physics Position", ATTR_POSITION, Vector3::ZERO, AM_SERIALIZATION);
  62. ID_ATTRIBUTE_MODE(RigidBody, VAR_QUATERNION, "Physics Rotation", ATTR_ROTATION, Quaternion::IDENTITY, AM_SERIALIZATION);
  63. ID_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Linear Velocity", ATTR_LIN_VELOCITY, Vector3::ZERO);
  64. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Rest Threshold", ATTR_LIN_RESTTHRESHOLD, 0.01f);
  65. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Threshold", ATTR_LIN_DAMPINGTHRESHOLD, 0.01f);
  66. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Scale", ATTR_LIN_DAMPINGSCALE, 0.0f);
  67. ID_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Angular Velocity", ATTR_ANG_VELOCITY, Vector3::ZERO);
  68. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Rest Threshold", ATTR_ANG_RESTTHRESHOLD, 0.01f);
  69. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Threshold", ATTR_ANG_DAMPINGTHRESHOLD, 0.01f);
  70. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Scale", ATTR_ANG_DAMPINGSCALE, 0.0f);
  71. ID_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Max Velocity", ATTR_ANG_MAXVELOCITY, M_INFINITY);
  72. ID_ATTRIBUTE(RigidBody, VAR_BOOL, "Is Active", ATTR_ACTIVE, true);
  73. }
  74. void RigidBody::OnSetAttribute(const AttributeInfo& attr, const Variant& value)
  75. {
  76. switch (attr.offset_)
  77. {
  78. case offsetof(RigidBody, mass_):
  79. SetMass(value.GetFloat());
  80. break;
  81. case ATTR_POSITION:
  82. SetPosition(value.GetVector3());
  83. break;
  84. case ATTR_ROTATION:
  85. SetRotation(value.GetQuaternion());
  86. break;
  87. case ATTR_LIN_VELOCITY:
  88. SetLinearVelocity(value.GetVector3());
  89. break;
  90. case ATTR_LIN_RESTTHRESHOLD:
  91. SetLinearRestThreshold(value.GetFloat());
  92. break;
  93. case ATTR_LIN_DAMPINGTHRESHOLD:
  94. SetLinearDampingThreshold(value.GetFloat());
  95. break;
  96. case ATTR_LIN_DAMPINGSCALE:
  97. SetLinearDampingScale(value.GetFloat());
  98. break;
  99. case ATTR_ANG_RESTTHRESHOLD:
  100. SetAngularRestThreshold(value.GetFloat());
  101. break;
  102. case ATTR_ANG_VELOCITY:
  103. SetAngularVelocity(value.GetVector3());
  104. break;
  105. case ATTR_ANG_DAMPINGTHRESHOLD:
  106. SetAngularDampingThreshold(value.GetFloat());
  107. break;
  108. case ATTR_ANG_DAMPINGSCALE:
  109. SetAngularDampingScale(value.GetFloat());
  110. break;
  111. case ATTR_ANG_MAXVELOCITY:
  112. SetAngularMaxVelocity(value.GetFloat());
  113. break;
  114. case ATTR_ACTIVE:
  115. SetActive(value.GetBool());
  116. break;
  117. default:
  118. Serializable::OnSetAttribute(attr, value);
  119. break;
  120. }
  121. }
  122. Variant RigidBody::OnGetAttribute(const AttributeInfo& attr)
  123. {
  124. switch (attr.offset_)
  125. {
  126. case ATTR_POSITION:
  127. return GetPosition();
  128. case ATTR_ROTATION:
  129. return GetRotation();
  130. case ATTR_LIN_VELOCITY:
  131. return GetLinearVelocity();
  132. case ATTR_LIN_RESTTHRESHOLD:
  133. return GetLinearRestThreshold();
  134. case ATTR_LIN_DAMPINGTHRESHOLD:
  135. return GetLinearDampingThreshold();
  136. case ATTR_LIN_DAMPINGSCALE:
  137. return GetLinearDampingScale();
  138. case ATTR_ANG_VELOCITY:
  139. return GetAngularVelocity();
  140. case ATTR_ANG_RESTTHRESHOLD:
  141. return GetAngularRestThreshold();
  142. case ATTR_ANG_DAMPINGTHRESHOLD:
  143. return GetAngularDampingThreshold();
  144. case ATTR_ANG_DAMPINGSCALE:
  145. return GetAngularDampingScale();
  146. case ATTR_ANG_MAXVELOCITY:
  147. return GetAngularMaxVelocity();
  148. case ATTR_ACTIVE:
  149. return IsActive();
  150. default:
  151. return Serializable::OnGetAttribute(attr);
  152. }
  153. }
  154. void RigidBody::SetMass(float mass)
  155. {
  156. mass_ = Max(mass, 0.0f);
  157. UpdateMass();
  158. }
  159. void RigidBody::SetPosition(const Vector3& position)
  160. {
  161. if (body_)
  162. {
  163. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  164. previousPosition_ = position;
  165. }
  166. }
  167. void RigidBody::SetRotation(const Quaternion& rotation)
  168. {
  169. if (body_)
  170. {
  171. dBodySetQuaternion(body_, rotation.GetData());
  172. previousRotation_ = rotation;
  173. }
  174. }
  175. void RigidBody::SetTransform(const Vector3& position, const Quaternion& rotation)
  176. {
  177. if (body_)
  178. {
  179. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  180. dBodySetQuaternion(body_, rotation.GetData());
  181. previousPosition_ = position;
  182. previousRotation_ = rotation;
  183. }
  184. }
  185. void RigidBody::SetLinearVelocity(const Vector3& velocity)
  186. {
  187. if (body_)
  188. dBodySetLinearVel(body_, velocity.x_, velocity.y_, velocity.z_);
  189. }
  190. void RigidBody::SetLinearRestThreshold(float threshold)
  191. {
  192. if (body_)
  193. dBodySetAutoDisableLinearThreshold(body_, threshold);
  194. }
  195. void RigidBody::SetLinearDampingThreshold(float threshold)
  196. {
  197. if (body_)
  198. dBodySetLinearDampingThreshold(body_, threshold);
  199. }
  200. void RigidBody::SetLinearDampingScale(float scale)
  201. {
  202. if (body_)
  203. dBodySetLinearDamping(body_, scale);
  204. }
  205. void RigidBody::SetAngularVelocity(const Vector3& velocity)
  206. {
  207. if (body_)
  208. dBodySetAngularVel(body_, velocity.x_, velocity.y_, velocity.z_);
  209. }
  210. void RigidBody::SetAngularRestThreshold(float threshold)
  211. {
  212. if (body_)
  213. dBodySetAutoDisableAngularThreshold(body_, threshold);
  214. }
  215. void RigidBody::SetAngularDampingThreshold(float threshold)
  216. {
  217. if (body_)
  218. dBodySetAngularDampingThreshold(body_, threshold);
  219. }
  220. void RigidBody::SetAngularDampingScale(float scale)
  221. {
  222. if (body_)
  223. dBodySetAngularDamping(body_, scale);
  224. }
  225. void RigidBody::SetAngularMaxVelocity(float velocity)
  226. {
  227. if (body_)
  228. dBodySetMaxAngularSpeed(body_, velocity);
  229. }
  230. void RigidBody::SetActive(bool active)
  231. {
  232. if (body_)
  233. {
  234. if ((active) && (!dBodyIsEnabled(body_)))
  235. dBodyEnable(body_);
  236. else if ((!active) && (dBodyIsEnabled(body_)))
  237. dBodyDisable(body_);
  238. }
  239. }
  240. void RigidBody::ApplyForce(const Vector3& force)
  241. {
  242. if (force == Vector3::ZERO)
  243. return;
  244. if (body_)
  245. {
  246. SetActive(true);
  247. dBodyAddForce(body_, force.x_, force.y_, force.z_);
  248. }
  249. }
  250. void RigidBody::ApplyForceAtPosition(const Vector3& force, const Vector3& position)
  251. {
  252. if (force == Vector3::ZERO)
  253. return;
  254. if (body_)
  255. {
  256. SetActive(true);
  257. dBodyAddForceAtRelPos(body_, force.x_, force.y_, force.z_, position.x_, position.y_, position.z_);
  258. }
  259. }
  260. void RigidBody::ApplyTorque(const Vector3& torque)
  261. {
  262. if (torque == Vector3::ZERO)
  263. return;
  264. if (body_)
  265. {
  266. SetActive(true);
  267. dBodyAddTorque(body_, torque.x_, torque.y_, torque.z_);
  268. }
  269. }
  270. void RigidBody::ResetForces()
  271. {
  272. if (body_)
  273. {
  274. dBodySetForce(body_, 0.0f, 0.0f, 0.0f);
  275. dBodySetTorque(body_, 0.0f, 0.0f, 0.0f);
  276. }
  277. }
  278. Vector3 RigidBody::GetPosition() const
  279. {
  280. if (body_)
  281. {
  282. const dReal* pos = dBodyGetPosition(body_);
  283. return Vector3(pos[0], pos[1], pos[2]);
  284. }
  285. else return node_->GetWorldPosition();
  286. }
  287. Quaternion RigidBody::GetRotation() const
  288. {
  289. if (body_)
  290. {
  291. const dReal* quat = dBodyGetQuaternion(body_);
  292. return Quaternion(quat[0], quat[1], quat[2], quat[3]);
  293. }
  294. else return node_->GetWorldRotation();
  295. }
  296. Vector3 RigidBody::GetLinearVelocity() const
  297. {
  298. if (body_)
  299. {
  300. const dReal* vel = dBodyGetLinearVel(body_);
  301. return Vector3(vel[0], vel[1], vel[2]);
  302. }
  303. else
  304. return Vector3::ZERO;
  305. }
  306. float RigidBody::GetLinearRestThreshold() const
  307. {
  308. if (body_)
  309. return dBodyGetAutoDisableLinearThreshold(body_);
  310. else
  311. return 0.0f;
  312. }
  313. float RigidBody::GetLinearDampingThreshold() const
  314. {
  315. if (body_)
  316. return dBodyGetLinearDampingThreshold(body_);
  317. else
  318. return 0.0f;
  319. }
  320. float RigidBody::GetLinearDampingScale() const
  321. {
  322. if (body_)
  323. return dBodyGetLinearDamping(body_);
  324. else
  325. return 0.0f;
  326. }
  327. Vector3 RigidBody::GetAngularVelocity() const
  328. {
  329. if (body_)
  330. {
  331. const dReal* vel = dBodyGetAngularVel(body_);
  332. return Vector3(vel[0], vel[1], vel[2]);
  333. }
  334. else
  335. return Vector3::ZERO;
  336. }
  337. float RigidBody::GetAngularRestThreshold() const
  338. {
  339. if (body_)
  340. return dBodyGetAutoDisableAngularThreshold(body_);
  341. else
  342. return 0.0f;
  343. }
  344. float RigidBody::GetAngularDampingThreshold() const
  345. {
  346. if (body_)
  347. return dBodyGetAngularDampingThreshold(body_);
  348. else
  349. return 0.0f;
  350. }
  351. float RigidBody::GetAngularDampingScale() const
  352. {
  353. if (body_)
  354. return dBodyGetAngularDamping(body_);
  355. else
  356. return 0.0f;
  357. }
  358. float RigidBody::GetAngularMaxVelocity() const
  359. {
  360. if (body_)
  361. return dBodyGetMaxAngularSpeed(body_);
  362. else
  363. return 0.0f;
  364. }
  365. bool RigidBody::IsActive() const
  366. {
  367. if (body_)
  368. return dBodyIsEnabled(body_) != 0;
  369. else
  370. return false;
  371. }
  372. void RigidBody::OnMarkedDirty(Node* node)
  373. {
  374. // Clear the dirty flag by querying world position; this way we are sure to get the dirty notification immediately
  375. // also the next time the node transform changes
  376. const Vector3& position = node_->GetWorldPosition();
  377. Quaternion rotation = node_->GetWorldRotation();
  378. // Disregard node dirtying during the physics poststep, when rendering transform is synced from physics transform
  379. if (inPostStep_)
  380. return;
  381. if (body_)
  382. {
  383. if ((GetPosition() != position) || (GetRotation() != rotation))
  384. {
  385. SetActive(true);
  386. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  387. dBodySetQuaternion(body_, rotation.GetData());
  388. }
  389. previousPosition_ = position;
  390. previousRotation_ = rotation;
  391. }
  392. }
  393. void RigidBody::OnNodeSet(Node* node)
  394. {
  395. if (node)
  396. {
  397. Scene* scene = node->GetScene();
  398. if (scene)
  399. {
  400. physicsWorld_ = scene->GetComponent<PhysicsWorld>();
  401. if (physicsWorld_)
  402. physicsWorld_->AddRigidBody(this);
  403. CreateBody();
  404. }
  405. node->AddListener(this);
  406. }
  407. }
  408. void RigidBody::PreStep()
  409. {
  410. // Store the previous position for interpolation
  411. if (body_)
  412. {
  413. const dReal* pos = dBodyGetPosition(body_);
  414. const dReal* quat = dBodyGetQuaternion(body_);
  415. previousPosition_ = Vector3(pos[0], pos[1], pos[2]);
  416. previousRotation_ = Quaternion(quat[0], quat[1], quat[2], quat[3]);
  417. }
  418. }
  419. void RigidBody::PostStep(float t)
  420. {
  421. if ((body_) && (IsActive()))
  422. {
  423. inPostStep_ = true;
  424. const dReal* pos = dBodyGetPosition(body_);
  425. const dReal* quat = dBodyGetQuaternion(body_);
  426. Vector3 currentPosition(pos[0], pos[1], pos[2]);
  427. Quaternion currentRotation(quat[0], quat[1], quat[2], quat[3]);
  428. /// \todo If the node is parented, transform will not be set correctly
  429. node_->SetPosition(previousPosition_.Lerp(currentPosition, t));
  430. node_->SetRotation(previousRotation_.Slerp(currentRotation, t));
  431. inPostStep_ = false;
  432. }
  433. }
  434. void RigidBody::CreateBody()
  435. {
  436. if (!physicsWorld_)
  437. {
  438. LOGERROR("Null physics world, can not create body");
  439. return;
  440. }
  441. if (!body_)
  442. {
  443. body_ = dBodyCreate(physicsWorld_->GetWorld());
  444. // Set the user data pointer
  445. dBodySetData(body_, this);
  446. // Set rendering transform as the initial transform
  447. const Vector3& position = node_->GetWorldPosition();
  448. Quaternion rotation = node_->GetWorldRotation();
  449. dBodySetPosition(body_, position.x_, position.y_, position.z_);
  450. dBodySetQuaternion(body_, rotation.GetData());
  451. previousPosition_ = position;
  452. previousRotation_ = rotation;
  453. // Associate geometries with the body
  454. std::vector<CollisionShape*> shapes;
  455. GetComponents<CollisionShape>(shapes);
  456. for (unsigned i = 0; i < shapes.size(); ++i)
  457. shapes[i]->UpdateTransform();
  458. }
  459. UpdateMass();
  460. }
  461. void RigidBody::ReleaseBody()
  462. {
  463. if (!body_)
  464. return;
  465. std::vector<CollisionShape*> shapes;
  466. GetComponents<CollisionShape>(shapes);
  467. // First remove rigid body associations
  468. for (unsigned i = 0; i < shapes.size(); ++i)
  469. {
  470. dGeomID geom = shapes[i]->GetGeometry();
  471. if (geom)
  472. dGeomSetBody(geom, 0);
  473. }
  474. dBodyDestroy(body_);
  475. body_ = 0;
  476. // Then update geometry transforms
  477. for (unsigned i = 0; i < shapes.size(); ++i)
  478. shapes[i]->UpdateTransform();
  479. }
  480. void RigidBody::UpdateMass()
  481. {
  482. if (!body_)
  483. return;
  484. dMass mass;
  485. dMassSetZero(&mass);
  486. float density = 1.0f;
  487. // Get all attached collision shapes to Calculate the mass
  488. std::vector<CollisionShape*> shapes;
  489. GetComponents<CollisionShape>(shapes);
  490. for (unsigned i = 0; i < shapes.size(); ++i)
  491. {
  492. CollisionShape* shape = shapes[i];
  493. dMass subMass;
  494. Vector3 size = shape->GetSize() * GetWorldScale();
  495. Vector3 offset = shape->GetPosition() * GetWorldScale();
  496. switch (shape->GetShapeType())
  497. {
  498. case SHAPE_BOX:
  499. dMassSetBox(&subMass, density, size.x_, size.y_, size.z_);
  500. break;
  501. case SHAPE_SPHERE:
  502. dMassSetSphere(&subMass, density, size.x_);
  503. break;
  504. case SHAPE_CYLINDER:
  505. dMassSetCylinder(&subMass, density, 2, size.x_, size.z_);
  506. break;
  507. case SHAPE_CAPSULE:
  508. dMassSetCapsule(&subMass, density, 2, size.x_, size.z_);
  509. break;
  510. case SHAPE_TRIANGLEMESH:
  511. dMassSetBox(&subMass, density, size.x_, size.y_, size.z_);
  512. break;
  513. }
  514. dMatrix3 rotMatrix;
  515. dRfromQ(rotMatrix, shape->GetRotation().GetData());
  516. dMassTranslate(&subMass, offset.x_, offset.y_, offset.z_);
  517. dMassRotate(&subMass, rotMatrix);
  518. dMassAdd(&mass, &subMass);
  519. }
  520. // If zero mass or no geometries, set kinematic mode
  521. if (mass.mass <= 0.0f)
  522. dBodySetKinematic(body_);
  523. else
  524. {
  525. // Translate final mass to center; anything else is unsupported in ODE
  526. dMassTranslate(&mass, -mass.c[0], -mass.c[1], -mass.c[2]);
  527. dMassAdjust(&mass, mass_);
  528. dBodySetMass(body_, &mass);
  529. }
  530. }