OffsetCenterOfMassShapeTests.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include "UnitTestFramework.h"
  4. #include "PhysicsTestContext.h"
  5. #include "Layers.h"
  6. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  7. #include <Jolt/Physics/Collision/Shape/OffsetCenterOfMassShape.h>
  8. TEST_SUITE("OffsetCenterOfMassShapeTests")
  9. {
  10. TEST_CASE("TestAddAngularImpulseCOMZero")
  11. {
  12. PhysicsTestContext c;
  13. c.ZeroGravity();
  14. // Create box
  15. const Vec3 cHalfExtent = Vec3(0.5f, 1.0f, 1.5f);
  16. BoxShapeSettings box(cHalfExtent);
  17. box.SetEmbedded();
  18. // Create body with COM offset 0
  19. OffsetCenterOfMassShapeSettings com(Vec3::sZero(), &box);
  20. com.SetEmbedded();
  21. Body &body = c.CreateBody(&com, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::DontActivate);
  22. // Check mass and inertia calculated correctly
  23. float mass = (8.0f * cHalfExtent.GetX() * cHalfExtent.GetY() * cHalfExtent.GetZ()) * box.mDensity;
  24. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseMass(), 1.0f / mass);
  25. float inertia_y = mass / 12.0f * (Square(2.0f * cHalfExtent.GetX()) + Square(2.0f * cHalfExtent.GetZ())); // See: https://en.wikipedia.org/wiki/List_of_moments_of_inertia
  26. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseInertiaForRotation(Mat44::sIdentity())(1, 1), 1.0f / inertia_y);
  27. // Add impulse
  28. Vec3 cImpulse(0, 10000, 0);
  29. CHECK(!body.IsActive());
  30. c.GetBodyInterface().AddAngularImpulse(body.GetID(), cImpulse);
  31. CHECK(body.IsActive());
  32. // Check resulting velocity change
  33. // dv = I^-1 * L
  34. float delta_v = (1.0f / inertia_y) * cImpulse.GetY();
  35. CHECK_APPROX_EQUAL(body.GetLinearVelocity(), Vec3::sZero());
  36. CHECK_APPROX_EQUAL(body.GetAngularVelocity(), Vec3(0, delta_v, 0));
  37. }
  38. TEST_CASE("TestAddAngularImpulseCOMOffset")
  39. {
  40. PhysicsTestContext c;
  41. c.ZeroGravity();
  42. // Create box
  43. const Vec3 cHalfExtent = Vec3(0.5f, 1.0f, 1.5f);
  44. BoxShapeSettings box(cHalfExtent);
  45. box.SetEmbedded();
  46. // Create body with COM offset
  47. const Vec3 cCOMOffset(5.0f, 0, 0);
  48. OffsetCenterOfMassShapeSettings com(cCOMOffset, &box);
  49. com.SetEmbedded();
  50. Body &body = c.CreateBody(&com, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::DontActivate);
  51. // Check mass and inertia calculated correctly
  52. float mass = (8.0f * cHalfExtent.GetX() * cHalfExtent.GetY() * cHalfExtent.GetZ()) * box.mDensity;
  53. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseMass(), 1.0f / mass);
  54. float inertia_y = mass / 12.0f * (Square(2.0f * cHalfExtent.GetX()) + Square(2.0f * cHalfExtent.GetZ())) + mass * Square(cCOMOffset.GetX()); // See: https://en.wikipedia.org/wiki/List_of_moments_of_inertia & https://en.wikipedia.org/wiki/Parallel_axis_theorem
  55. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseInertiaForRotation(Mat44::sIdentity())(1, 1), 1.0f / inertia_y);
  56. // Add impulse
  57. Vec3 cImpulse(0, 10000, 0);
  58. CHECK(!body.IsActive());
  59. c.GetBodyInterface().AddAngularImpulse(body.GetID(), cImpulse);
  60. CHECK(body.IsActive());
  61. // Check resulting velocity change
  62. // dv = I^-1 * L
  63. float delta_v = (1.0f / inertia_y) * cImpulse.GetY();
  64. CHECK_APPROX_EQUAL(body.GetLinearVelocity(), Vec3::sZero());
  65. CHECK_APPROX_EQUAL(body.GetAngularVelocity(), Vec3(0, delta_v, 0));
  66. }
  67. TEST_CASE("TestAddTorqueCOMZero")
  68. {
  69. PhysicsTestContext c;
  70. c.ZeroGravity();
  71. // Create box
  72. const Vec3 cHalfExtent = Vec3(0.5f, 1.0f, 1.5f);
  73. BoxShapeSettings box(cHalfExtent);
  74. box.SetEmbedded();
  75. // Create body with COM offset 0
  76. OffsetCenterOfMassShapeSettings com(Vec3::sZero(), &box);
  77. com.SetEmbedded();
  78. Body &body = c.CreateBody(&com, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::DontActivate);
  79. // Check mass and inertia calculated correctly
  80. float mass = (8.0f * cHalfExtent.GetX() * cHalfExtent.GetY() * cHalfExtent.GetZ()) * box.mDensity;
  81. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseMass(), 1.0f / mass);
  82. float inertia_y = mass / 12.0f * (Square(2.0f * cHalfExtent.GetX()) + Square(2.0f * cHalfExtent.GetZ())); // See: https://en.wikipedia.org/wiki/List_of_moments_of_inertia
  83. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseInertiaForRotation(Mat44::sIdentity())(1, 1), 1.0f / inertia_y);
  84. // Add torque
  85. Vec3 cTorque(0, 100000, 0);
  86. CHECK(!body.IsActive());
  87. c.GetBodyInterface().AddTorque(body.GetID(), cTorque);
  88. CHECK(body.IsActive());
  89. CHECK(body.GetAngularVelocity() == Vec3::sZero()); // Angular velocity change should come after the next time step
  90. c.SimulateSingleStep();
  91. // Check resulting velocity change
  92. // dv = I^-1 * T * dt
  93. float delta_v = (1.0f / inertia_y) * cTorque.GetY() * c.GetDeltaTime();
  94. CHECK_APPROX_EQUAL(body.GetLinearVelocity(), Vec3::sZero());
  95. CHECK_APPROX_EQUAL(body.GetAngularVelocity(), Vec3(0, delta_v, 0));
  96. }
  97. TEST_CASE("TestAddTorqueCOMOffset")
  98. {
  99. PhysicsTestContext c;
  100. c.ZeroGravity();
  101. // Create box
  102. const Vec3 cHalfExtent = Vec3(0.5f, 1.0f, 1.5f);
  103. BoxShapeSettings box(cHalfExtent);
  104. box.SetEmbedded();
  105. // Create body with COM offset
  106. const Vec3 cCOMOffset(5.0f, 0, 0);
  107. OffsetCenterOfMassShapeSettings com(cCOMOffset, &box);
  108. com.SetEmbedded();
  109. Body &body = c.CreateBody(&com, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, EActivation::DontActivate);
  110. // Check mass and inertia calculated correctly
  111. float mass = (8.0f * cHalfExtent.GetX() * cHalfExtent.GetY() * cHalfExtent.GetZ()) * box.mDensity;
  112. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseMass(), 1.0f / mass);
  113. float inertia_y = mass / 12.0f * (Square(2.0f * cHalfExtent.GetX()) + Square(2.0f * cHalfExtent.GetZ())) + mass * Square(cCOMOffset.GetX()); // See: https://en.wikipedia.org/wiki/List_of_moments_of_inertia & https://en.wikipedia.org/wiki/Parallel_axis_theorem
  114. CHECK_APPROX_EQUAL(body.GetMotionProperties()->GetInverseInertiaForRotation(Mat44::sIdentity())(1, 1), 1.0f / inertia_y);
  115. // Add torque
  116. Vec3 cTorque(0, 100000, 0);
  117. CHECK(!body.IsActive());
  118. c.GetBodyInterface().AddTorque(body.GetID(), cTorque);
  119. CHECK(body.IsActive());
  120. CHECK(body.GetAngularVelocity() == Vec3::sZero()); // Angular velocity change should come after the next time step
  121. c.SimulateSingleStep();
  122. // Check resulting velocity change
  123. // dv = I^-1 * T * dt
  124. float delta_v = (1.0f / inertia_y) * cTorque.GetY() * c.GetDeltaTime();
  125. CHECK_APPROX_EQUAL(body.GetLinearVelocity(), Vec3::sZero());
  126. CHECK_APPROX_EQUAL(body.GetAngularVelocity(), Vec3(0, delta_v, 0));
  127. }
  128. }