RackAndPinionConstraintTest.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/Constraints/RackAndPinionConstraintTest.h>
  6. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  7. #include <Jolt/Physics/Collision/Shape/CylinderShape.h>
  8. #include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
  9. #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
  10. #include <Jolt/Physics/Collision/GroupFilterTable.h>
  11. #include <Jolt/Physics/Constraints/HingeConstraint.h>
  12. #include <Jolt/Physics/Constraints/SliderConstraint.h>
  13. #include <Jolt/Physics/Constraints/RackAndPinionConstraint.h>
  14. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  15. #include <Layers.h>
  16. JPH_IMPLEMENT_RTTI_VIRTUAL(RackAndPinionConstraintTest)
  17. {
  18. JPH_ADD_BASE_CLASS(RackAndPinionConstraintTest, Test)
  19. }
  20. void RackAndPinionConstraintTest::Initialize()
  21. {
  22. // Floor
  23. CreateFloor();
  24. constexpr float cGearRadius = 0.5f;
  25. constexpr float cGearHalfWidth = 0.05f;
  26. constexpr int cGearNumTeeth = 100;
  27. constexpr float cRackLength = 10.0f;
  28. constexpr float cRackHalfHeight = 0.1f;
  29. constexpr float cRackHalfWidth = 0.05f;
  30. constexpr int cRackNumTeeth = int(cRackLength * cGearNumTeeth / (2.0f * JPH_PI * cGearRadius));
  31. constexpr float cToothThicknessBottom = 0.01f;
  32. constexpr float cToothThicknessTop = 0.005f;
  33. constexpr float cToothHeight = 0.02f;
  34. // Create a tooth
  35. Array<Vec3> tooth_points = {
  36. Vec3(0, cGearHalfWidth, cToothThicknessBottom),
  37. Vec3(0, -cGearHalfWidth, cToothThicknessBottom),
  38. Vec3(0, cGearHalfWidth, -cToothThicknessBottom),
  39. Vec3(0, -cGearHalfWidth, -cToothThicknessBottom),
  40. Vec3(cToothHeight, -cGearHalfWidth, cToothThicknessTop),
  41. Vec3(cToothHeight, cGearHalfWidth, cToothThicknessTop),
  42. Vec3(cToothHeight, -cGearHalfWidth, -cToothThicknessTop),
  43. Vec3(cToothHeight, cGearHalfWidth, -cToothThicknessTop),
  44. };
  45. ConvexHullShapeSettings tooth_settings(tooth_points);
  46. tooth_settings.SetEmbedded();
  47. // Create gear
  48. CylinderShapeSettings gear_cylinder(cGearHalfWidth, cGearRadius);
  49. gear_cylinder.SetEmbedded();
  50. StaticCompoundShapeSettings gear_settings;
  51. gear_settings.SetEmbedded();
  52. gear_settings.AddShape(Vec3::sZero(), Quat::sIdentity(), &gear_cylinder);
  53. for (int i = 0; i < cGearNumTeeth; ++i)
  54. {
  55. Quat rotation = Quat::sRotation(Vec3::sAxisY(), 2.0f * JPH_PI * i / cGearNumTeeth);
  56. gear_settings.AddShape(rotation * Vec3(cGearRadius, 0, 0), rotation, &tooth_settings);
  57. }
  58. RVec3 gear_initial_p(0, 2.0f, 0);
  59. Quat gear_initial_r = Quat::sRotation(Vec3::sAxisX(), 0.5f * JPH_PI);
  60. Body *gear = mBodyInterface->CreateBody(BodyCreationSettings(&gear_settings, gear_initial_p, gear_initial_r, EMotionType::Dynamic, Layers::MOVING));
  61. mBodyInterface->AddBody(gear->GetID(), EActivation::Activate);
  62. // Create rack
  63. BoxShapeSettings rack_box(Vec3(cRackHalfHeight, cRackHalfWidth, 0.5f * cRackLength), 0.0f);
  64. rack_box.SetEmbedded();
  65. StaticCompoundShapeSettings rack_settings;
  66. rack_settings.SetEmbedded();
  67. rack_settings.AddShape(Vec3::sZero(), Quat::sIdentity(), &rack_box);
  68. for (int i = 0; i < cRackNumTeeth; ++i)
  69. rack_settings.AddShape(Vec3(cRackHalfHeight, 0, -0.5f * cRackLength + (i + 0.5f) * cRackLength / cRackNumTeeth), Quat::sIdentity(), &tooth_settings);
  70. RVec3 slider_initial_p = gear_initial_p - Vec3(0, cGearRadius + cRackHalfHeight + cToothHeight, 0);
  71. Quat slider_initial_r = Quat::sRotation(Vec3::sAxisZ(), 0.5f * JPH_PI) * gear_initial_r;
  72. Body *rack = mBodyInterface->CreateBody(BodyCreationSettings(&rack_settings, slider_initial_p, slider_initial_r, EMotionType::Dynamic, Layers::MOVING));
  73. mBodyInterface->AddBody(rack->GetID(), EActivation::Activate);
  74. // Create a hinge for the gear
  75. HingeConstraintSettings hinge;
  76. hinge.mPoint1 = hinge.mPoint2 = gear_initial_p;
  77. hinge.mHingeAxis1 = hinge.mHingeAxis2 = Vec3::sAxisZ();
  78. hinge.mNormalAxis1 = hinge.mNormalAxis2 = Vec3::sAxisX();
  79. Constraint *hinge_constraint = hinge.Create(Body::sFixedToWorld, *gear);
  80. mPhysicsSystem->AddConstraint(hinge_constraint);
  81. // Create a slider for the rack
  82. SliderConstraintSettings slider;
  83. slider.mPoint1 = slider.mPoint2 = gear_initial_p;
  84. slider.mSliderAxis1 = slider.mSliderAxis2 = Vec3::sAxisX();
  85. slider.mNormalAxis1 = slider.mNormalAxis2 = Vec3::sAxisZ();
  86. slider.mLimitsMin = -0.5f * cRackLength;
  87. slider.mLimitsMax = 0.5f * cRackLength;
  88. Constraint *slider_constraint = slider.Create(Body::sFixedToWorld, *rack);
  89. mPhysicsSystem->AddConstraint(slider_constraint);
  90. // Disable collision between rack and gear (we want the rack and pinion constraint to take care of the relative movement)
  91. Ref<GroupFilterTable> group_filter = new GroupFilterTable(2);
  92. group_filter->DisableCollision(0, 1);
  93. gear->SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
  94. rack->SetCollisionGroup(CollisionGroup(group_filter, 0, 1));
  95. // Create rack and pinion constraint to constrain the two bodies
  96. RackAndPinionConstraintSettings randp;
  97. randp.mHingeAxis = hinge.mHingeAxis1;
  98. randp.mSliderAxis = slider.mSliderAxis2;
  99. randp.SetRatio(cRackNumTeeth, cRackLength, cGearNumTeeth);
  100. RackAndPinionConstraint *randp_constraint = static_cast<RackAndPinionConstraint *>(randp.Create(*gear, *rack));
  101. randp_constraint->SetConstraints(hinge_constraint, slider_constraint);
  102. mPhysicsSystem->AddConstraint(randp_constraint);
  103. // Give the gear a spin
  104. gear->SetAngularVelocity(Vec3(0, 0, 6.0f));
  105. }