GearConstraintTest.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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/GearConstraintTest.h>
  6. #include <Jolt/Physics/Collision/Shape/CylinderShape.h>
  7. #include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
  8. #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
  9. #include <Jolt/Physics/Collision/GroupFilterTable.h>
  10. #include <Jolt/Physics/Constraints/HingeConstraint.h>
  11. #include <Jolt/Physics/Constraints/GearConstraint.h>
  12. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  13. #include <Layers.h>
  14. JPH_IMPLEMENT_RTTI_VIRTUAL(GearConstraintTest)
  15. {
  16. JPH_ADD_BASE_CLASS(GearConstraintTest, Test)
  17. }
  18. void GearConstraintTest::Initialize()
  19. {
  20. // Floor
  21. CreateFloor();
  22. constexpr float cGearHalfWidth = 0.05f;
  23. constexpr float cGear1Radius = 0.5f;
  24. constexpr int cGear1NumTeeth = 100;
  25. constexpr float cGear2Radius = 2.0f;
  26. constexpr int cGear2NumTeeth = int(cGear1NumTeeth * cGear2Radius / cGear1Radius);
  27. constexpr float cToothThicknessBottom = 0.01f;
  28. constexpr float cToothThicknessTop = 0.005f;
  29. constexpr float cToothHeight = 0.02f;
  30. // Create a tooth
  31. Array<Vec3> tooth_points = {
  32. Vec3(0, cGearHalfWidth, cToothThicknessBottom),
  33. Vec3(0, -cGearHalfWidth, cToothThicknessBottom),
  34. Vec3(0, cGearHalfWidth, -cToothThicknessBottom),
  35. Vec3(0, -cGearHalfWidth, -cToothThicknessBottom),
  36. Vec3(cToothHeight, -cGearHalfWidth, cToothThicknessTop),
  37. Vec3(cToothHeight, cGearHalfWidth, cToothThicknessTop),
  38. Vec3(cToothHeight, -cGearHalfWidth, -cToothThicknessTop),
  39. Vec3(cToothHeight, cGearHalfWidth, -cToothThicknessTop),
  40. };
  41. ConvexHullShapeSettings tooth_settings(tooth_points);
  42. tooth_settings.SetEmbedded();
  43. // Create gear 1
  44. CylinderShapeSettings gear1_cylinder(cGearHalfWidth, cGear1Radius);
  45. gear1_cylinder.SetEmbedded();
  46. StaticCompoundShapeSettings gear1_settings;
  47. gear1_settings.SetEmbedded();
  48. gear1_settings.AddShape(Vec3::sZero(), Quat::sIdentity(), &gear1_cylinder);
  49. for (int i = 0; i < cGear1NumTeeth; ++i)
  50. {
  51. Quat rotation = Quat::sRotation(Vec3::sAxisY(), 2.0f * JPH_PI * i / cGear1NumTeeth);
  52. gear1_settings.AddShape(rotation * Vec3(cGear1Radius, 0, 0), rotation, &tooth_settings);
  53. }
  54. RVec3 gear1_initial_p(0, 3.0f, 0);
  55. Quat gear1_initial_r = Quat::sRotation(Vec3::sAxisX(), 0.5f * JPH_PI);
  56. Body *gear1 = mBodyInterface->CreateBody(BodyCreationSettings(&gear1_settings, gear1_initial_p, gear1_initial_r, EMotionType::Dynamic, Layers::MOVING));
  57. mBodyInterface->AddBody(gear1->GetID(), EActivation::Activate);
  58. // Create gear 2
  59. CylinderShapeSettings gear2_cylinder(cGearHalfWidth, cGear2Radius);
  60. gear2_cylinder.SetEmbedded();
  61. StaticCompoundShapeSettings gear2_settings;
  62. gear2_settings.SetEmbedded();
  63. gear2_settings.AddShape(Vec3::sZero(), Quat::sIdentity(), &gear2_cylinder);
  64. for (int i = 0; i < cGear2NumTeeth; ++i)
  65. {
  66. Quat rotation = Quat::sRotation(Vec3::sAxisY(), 2.0f * JPH_PI * (i + 0.5f) / cGear2NumTeeth);
  67. gear2_settings.AddShape(rotation * Vec3(cGear2Radius, 0, 0), rotation, &tooth_settings);
  68. }
  69. RVec3 gear2_initial_p = gear1_initial_p + Vec3(cGear1Radius + cGear2Radius + cToothHeight, 0, 0);
  70. Quat gear2_initial_r = gear1_initial_r;
  71. Body *gear2 = mBodyInterface->CreateBody(BodyCreationSettings(&gear2_settings, gear2_initial_p, gear2_initial_r, EMotionType::Dynamic, Layers::MOVING));
  72. mBodyInterface->AddBody(gear2->GetID(), EActivation::Activate);
  73. // Create a hinge for gear 1
  74. HingeConstraintSettings hinge1;
  75. hinge1.mPoint1 = hinge1.mPoint2 = gear1_initial_p;
  76. hinge1.mHingeAxis1 = hinge1.mHingeAxis2 = Vec3::sAxisZ();
  77. hinge1.mNormalAxis1 = hinge1.mNormalAxis2 = Vec3::sAxisX();
  78. Constraint *hinge1_constraint = hinge1.Create(Body::sFixedToWorld, *gear1);
  79. mPhysicsSystem->AddConstraint(hinge1_constraint);
  80. // Create a hinge for gear 1
  81. HingeConstraintSettings hinge2;
  82. hinge2.mPoint1 = hinge2.mPoint2 = gear2_initial_p;
  83. hinge2.mHingeAxis1 = hinge2.mHingeAxis2 = Vec3::sAxisZ();
  84. hinge2.mNormalAxis1 = hinge2.mNormalAxis2 = Vec3::sAxisX();
  85. Constraint *hinge2_constraint = hinge2.Create(Body::sFixedToWorld, *gear2);
  86. mPhysicsSystem->AddConstraint(hinge2_constraint);
  87. // Disable collision between gears
  88. Ref<GroupFilterTable> group_filter = new GroupFilterTable(2);
  89. group_filter->DisableCollision(0, 1);
  90. gear1->SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
  91. gear2->SetCollisionGroup(CollisionGroup(group_filter, 0, 1));
  92. // Create gear constraint to constrain the two bodies
  93. GearConstraintSettings gear;
  94. gear.mHingeAxis1 = hinge1.mHingeAxis1;
  95. gear.mHingeAxis2 = hinge2.mHingeAxis1;
  96. gear.SetRatio(cGear1NumTeeth, cGear2NumTeeth);
  97. GearConstraint *gear_constraint = static_cast<GearConstraint *>(gear.Create(*gear1, *gear2));
  98. gear_constraint->SetConstraints(hinge1_constraint, hinge2_constraint);
  99. mPhysicsSystem->AddConstraint(gear_constraint);
  100. // Give the gear a spin
  101. gear2->SetAngularVelocity(Vec3(0, 0, 3.0f));
  102. }