PhysicsConstraint.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include "Base.h"
  2. #include "PhysicsConstraint.h"
  3. #include "Game.h"
  4. #include "Node.h"
  5. #include "PhysicsRigidBody.h"
  6. namespace gameplay
  7. {
  8. PhysicsConstraint::PhysicsConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
  9. : _a(a), _b(b), _constraint(NULL)
  10. {
  11. }
  12. PhysicsConstraint::~PhysicsConstraint()
  13. {
  14. // Remove the physics rigid bodies' references to this constraint.
  15. if (_a)
  16. _a->removeConstraint(this);
  17. if (_b)
  18. _b->removeConstraint(this);
  19. // Remove the constraint from the physics world and delete the Bullet object.
  20. GP_ASSERT(Game::getInstance()->getPhysicsController());
  21. Game::getInstance()->getPhysicsController()->removeConstraint(this);
  22. SAFE_DELETE(_constraint);
  23. }
  24. Vector3 PhysicsConstraint::centerOfMassMidpoint(const Node* a, const Node* b)
  25. {
  26. GP_ASSERT(a);
  27. GP_ASSERT(b);
  28. Vector3 tA, tB;
  29. a->getWorldMatrix().getTranslation(&tA);
  30. b->getWorldMatrix().getTranslation(&tB);
  31. tA = getWorldCenterOfMass(a->getModel());
  32. tB = getWorldCenterOfMass(b->getModel());
  33. Vector3 d(tA, tB);
  34. d.scale(0.5f);
  35. Vector3 c(tA);
  36. c.add(d);
  37. return c;
  38. }
  39. Quaternion PhysicsConstraint::getRotationOffset(const Node* node, const Vector3& point)
  40. {
  41. GP_ASSERT(node);
  42. // Create a translation matrix that translates to the given origin.
  43. Matrix m;
  44. Matrix::createTranslation(point, &m);
  45. // Calculate the rotation offset to the rigid body by transforming
  46. // the translation matrix above into the rigid body's local space
  47. // (multiply by the inverse world matrix) and extracting the rotation.
  48. Matrix mi;
  49. node->getWorldMatrix().invert(&mi);
  50. mi.multiply(m);
  51. Quaternion r;
  52. mi.getRotation(&r);
  53. return r;
  54. }
  55. Vector3 PhysicsConstraint::getTranslationOffset(const Node* node, const Vector3& point)
  56. {
  57. GP_ASSERT(node);
  58. // Create a translation matrix that translates to the given origin.
  59. Matrix m;
  60. Matrix::createTranslation(point, &m);
  61. // Calculate the translation offset to the rigid body by transforming
  62. // the translation matrix above into the rigid body's local space
  63. // (multiply by the inverse world matrix) and extracting the translation.
  64. Matrix mi;
  65. node->getWorldMatrix().invert(&mi);
  66. mi.multiply(m);
  67. Vector3 t;
  68. mi.getTranslation(&t);
  69. Vector3 s;
  70. node->getWorldMatrix().getScale(&s);
  71. t.x *= s.x;
  72. t.y *= s.y;
  73. t.z *= s.z;
  74. t = offsetByCenterOfMass(node, t);
  75. return t;
  76. }
  77. btTransform PhysicsConstraint::getTransformOffset(const Node* node, const Vector3& origin)
  78. {
  79. GP_ASSERT(node);
  80. // Create a translation matrix that translates to the given origin.
  81. Matrix m;
  82. Matrix::createTranslation(origin, &m);
  83. // Calculate the translation and rotation offset to the rigid body
  84. // by transforming the translation matrix above into the rigid body's
  85. // local space (multiply by the inverse world matrix and extract components).
  86. Matrix mi;
  87. node->getWorldMatrix().invert(&mi);
  88. mi.multiply(m);
  89. Quaternion r;
  90. mi.getRotation(&r);
  91. Vector3 t;
  92. mi.getTranslation(&t);
  93. Vector3 s;
  94. node->getWorldMatrix().getScale(&s);
  95. t.x *= s.x;
  96. t.y *= s.y;
  97. t.z *= s.z;
  98. t = offsetByCenterOfMass(node, t);
  99. return btTransform(BQ(r), BV(t));
  100. }
  101. Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)
  102. {
  103. GP_ASSERT(model && model->getMesh() && model->getNode());
  104. Vector3 center;
  105. const BoundingBox& box = model->getMesh()->getBoundingBox();
  106. if (!(box.min.isZero() && box.max.isZero()))
  107. {
  108. Vector3 bMin, bMax;
  109. model->getNode()->getWorldMatrix().transformPoint(box.min, &bMin);
  110. model->getNode()->getWorldMatrix().transformPoint(box.max, &bMax);
  111. center.set(bMin, bMax);
  112. center.scale(0.5f);
  113. center.add(bMin);
  114. }
  115. else
  116. {
  117. const BoundingSphere& sphere = model->getMesh()->getBoundingSphere();
  118. if (!(sphere.center.isZero() && sphere.radius == 0))
  119. {
  120. model->getNode()->getWorldMatrix().transformPoint(sphere.center, &center);
  121. }
  122. else
  123. {
  124. // Warn the user that the model has no bounding volume.
  125. GP_WARN("Model '%s' has no bounding volume - center of mass is defaulting to local coordinate origin.", model->getNode()->getId());
  126. model->getNode()->getWorldMatrix().transformPoint(&center);
  127. }
  128. }
  129. return center;
  130. }
  131. Vector3 PhysicsConstraint::offsetByCenterOfMass(const Node* node, const Vector3& v)
  132. {
  133. GP_ASSERT(node && node->getCollisionObject() && node->getCollisionObject()->_motionState);
  134. btVector3 centerOfMassOffset = node->getCollisionObject()->_motionState->_centerOfMassOffset.getOrigin();
  135. return Vector3(v.x + centerOfMassOffset.x(), v.y + centerOfMassOffset.y(), v.z + centerOfMassOffset.z());
  136. }
  137. }