FixedConstraintTest.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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/FixedConstraintTest.h>
  6. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  7. #include <Jolt/Physics/Collision/GroupFilterTable.h>
  8. #include <Jolt/Physics/Constraints/FixedConstraint.h>
  9. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  10. #include <Layers.h>
  11. JPH_IMPLEMENT_RTTI_VIRTUAL(FixedConstraintTest)
  12. {
  13. JPH_ADD_BASE_CLASS(FixedConstraintTest, Test)
  14. }
  15. void FixedConstraintTest::Initialize()
  16. {
  17. // Floor
  18. CreateFloor();
  19. float box_size = 4.0f;
  20. RefConst<Shape> box = new BoxShape(Vec3::sReplicate(0.5f * box_size));
  21. const int num_bodies = 10;
  22. // Build a collision group filter that disables collision between adjacent bodies
  23. Ref<GroupFilterTable> group_filter = new GroupFilterTable(num_bodies);
  24. for (CollisionGroup::SubGroupID i = 0; i < num_bodies - 1; ++i)
  25. group_filter->DisableCollision(i, i + 1);
  26. // Bodies attached through fixed constraints
  27. for (int randomness = 0; randomness < 2; ++randomness)
  28. {
  29. CollisionGroup::GroupID group_id = CollisionGroup::GroupID(randomness);
  30. RVec3 position(0, 25.0f, -randomness * 20.0f);
  31. Body &top = *mBodyInterface->CreateBody(BodyCreationSettings(box, position, Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING));
  32. top.SetCollisionGroup(CollisionGroup(group_filter, group_id, 0));
  33. mBodyInterface->AddBody(top.GetID(), EActivation::DontActivate);
  34. default_random_engine random;
  35. uniform_real_distribution<float> displacement(-1.0f, 1.0f);
  36. Body *prev = &top;
  37. for (int i = 1; i < num_bodies; ++i)
  38. {
  39. Quat rotation;
  40. if (randomness == 0)
  41. {
  42. position += Vec3(box_size, 0, 0);
  43. rotation = Quat::sIdentity();
  44. }
  45. else
  46. {
  47. position += Vec3(box_size + abs(displacement(random)), displacement(random), displacement(random));
  48. rotation = Quat::sRandom(random);
  49. }
  50. Body &segment = *mBodyInterface->CreateBody(BodyCreationSettings(box, position, rotation, EMotionType::Dynamic, Layers::MOVING));
  51. segment.SetCollisionGroup(CollisionGroup(group_filter, group_id, CollisionGroup::SubGroupID(i)));
  52. mBodyInterface->AddBody(segment.GetID(), EActivation::Activate);
  53. FixedConstraintSettings settings;
  54. settings.mAutoDetectPoint = true;
  55. Ref<Constraint> c = settings.Create(*prev, segment);
  56. mPhysicsSystem->AddConstraint(c);
  57. prev = &segment;
  58. }
  59. }
  60. {
  61. // Two light bodies attached to a heavy body (gives issues if the wrong anchor point is chosen)
  62. Body *light1 = mBodyInterface->CreateBody(BodyCreationSettings(new BoxShape(Vec3::sReplicate(0.1f)), RVec3(-5.0f, 7.0f, -5.2f), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING));
  63. mBodyInterface->AddBody(light1->GetID(), EActivation::Activate);
  64. Body *heavy = mBodyInterface->CreateBody(BodyCreationSettings(new BoxShape(Vec3::sReplicate(5.0f)), RVec3(-5.0f, 7.0f, 0.0f), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING));
  65. mBodyInterface->AddBody(heavy->GetID(), EActivation::Activate);
  66. Body *light2 = mBodyInterface->CreateBody(BodyCreationSettings(new BoxShape(Vec3::sReplicate(0.1f)), RVec3(-5.0f, 7.0f, 5.2f), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING));
  67. mBodyInterface->AddBody(light2->GetID(), EActivation::Activate);
  68. FixedConstraintSettings light1_heavy;
  69. light1_heavy.mAutoDetectPoint = true;
  70. mPhysicsSystem->AddConstraint(light1_heavy.Create(*light1, *heavy));
  71. FixedConstraintSettings heavy_light2;
  72. heavy_light2.mAutoDetectPoint = true;
  73. mPhysicsSystem->AddConstraint(heavy_light2.Create(*heavy, *light2));
  74. }
  75. {
  76. // A tower of beams and crossbeams (note that it is not recommended to make constructs with this many fixed constraints, this is not always stable)
  77. RVec3 base_position(0, 25, -40.0f);
  78. Quat base_rotation = Quat::sRotation(Vec3::sAxisZ(), -0.5f * JPH_PI);
  79. Ref<BoxShape> pillar = new BoxShape(Vec3(0.1f, 1.0f, 0.1f), 0.0f);
  80. Ref<BoxShape> beam = new BoxShape(Vec3(0.01f, 1.5f, 0.1f), 0.0f);
  81. Body *prev_pillars[4] = { &Body::sFixedToWorld, &Body::sFixedToWorld, &Body::sFixedToWorld, &Body::sFixedToWorld };
  82. Vec3 center = Vec3::sZero();
  83. for (int y = 0; y < 10; ++y)
  84. {
  85. // Create pillars
  86. Body *pillars[4];
  87. for (int i = 0; i < 4; ++i)
  88. {
  89. Quat rotation = Quat::sRotation(Vec3::sAxisY(), i * 0.5f * JPH_PI);
  90. pillars[i] = mBodyInterface->CreateBody(BodyCreationSettings(pillar, base_position + base_rotation * (center + rotation * Vec3(1.0f, 1.0f, 1.0f)), base_rotation, EMotionType::Dynamic, Layers::MOVING));
  91. pillars[i]->SetCollisionGroup(CollisionGroup(group_filter, 0, 0)); // For convenience, we disable collisions between all objects in the tower
  92. mBodyInterface->AddBody(pillars[i]->GetID(), EActivation::Activate);
  93. }
  94. for (int i = 0; i < 4; ++i)
  95. {
  96. Quat rotation = Quat::sRotation(Vec3::sAxisY(), i * 0.5f * JPH_PI);
  97. // Create cross beam
  98. Body *cross = mBodyInterface->CreateBody(BodyCreationSettings(beam, base_position + base_rotation * (center + rotation * Vec3(1.105f, 1.0f, 0.0f)), base_rotation * rotation * Quat::sRotation(Vec3::sAxisX(), 0.3f * JPH_PI), EMotionType::Dynamic, Layers::MOVING));
  99. cross->SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
  100. mBodyInterface->AddBody(cross->GetID(), EActivation::Activate);
  101. // Attach cross beam to pillars
  102. for (int j = 0; j < 2; ++j)
  103. {
  104. FixedConstraintSettings constraint;
  105. constraint.mAutoDetectPoint = true;
  106. constraint.mNumVelocityStepsOverride = 64; // This structure needs more solver steps to be stable
  107. constraint.mNumPositionStepsOverride = JPH_IF_NOT_DEBUG(64) JPH_IF_DEBUG(8); // In debug mode use less steps to preserve framerate (at the cost of stability)
  108. mPhysicsSystem->AddConstraint(constraint.Create(*pillars[(i + j) % 4], *cross));
  109. }
  110. // Attach to previous pillar
  111. if (prev_pillars[i] != nullptr)
  112. {
  113. FixedConstraintSettings constraint;
  114. constraint.mAutoDetectPoint = true;
  115. constraint.mNumVelocityStepsOverride = 64;
  116. constraint.mNumPositionStepsOverride = JPH_IF_NOT_DEBUG(64) JPH_IF_DEBUG(8);
  117. mPhysicsSystem->AddConstraint(constraint.Create(*prev_pillars[i], *pillars[i]));
  118. }
  119. prev_pillars[i] = pillars[i];
  120. }
  121. center += Vec3(0.0f, 2.0f, 0.0f);
  122. }
  123. // Create top
  124. Body *top = mBodyInterface->CreateBody(BodyCreationSettings(new BoxShape(Vec3(1.2f, 0.1f, 1.2f)), base_position + base_rotation * (center + Vec3(0.0f, 0.1f, 0.0f)), base_rotation, EMotionType::Dynamic, Layers::MOVING));
  125. top->SetCollisionGroup(CollisionGroup(group_filter, 0, 0));
  126. mBodyInterface->AddBody(top->GetID(), EActivation::Activate);
  127. // Attach top to pillars
  128. for (int i = 0; i < 4; ++i)
  129. {
  130. FixedConstraintSettings constraint;
  131. constraint.mAutoDetectPoint = true;
  132. mPhysicsSystem->AddConstraint(constraint.Create(*prev_pillars[i], *top));
  133. }
  134. }
  135. }