SoftBodyBendConstraintTest.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/SoftBody/SoftBodyBendConstraintTest.h>
  6. #include <Jolt/Physics/SoftBody/SoftBodyCreationSettings.h>
  7. #include <Utils/SoftBodyCreator.h>
  8. #include <Layers.h>
  9. #include <Renderer/DebugRendererImp.h>
  10. JPH_IMPLEMENT_RTTI_VIRTUAL(SoftBodyBendConstraintTest)
  11. {
  12. JPH_ADD_BASE_CLASS(SoftBodyBendConstraintTest, Test)
  13. }
  14. void SoftBodyBendConstraintTest::Initialize()
  15. {
  16. CreateFloor();
  17. default_random_engine random;
  18. uniform_real_distribution<float> random_float(-0.1f, 0.1f);
  19. auto inv_mass = [](uint, uint inZ) { return inZ < 2? 0.0f : 1.0f; };
  20. auto perturbation = [&random, &random_float](uint, uint inZ) { return Vec3(random_float(random), (inZ & 1)? 0.1f : -0.1f, random_float(random)); };
  21. {
  22. random.seed(1234);
  23. // Cloth without bend constraints
  24. Ref<SoftBodySharedSettings> cloth_settings = SoftBodyCreator::CreateCloth(cNumVerticesX, cNumVerticesZ, cVertexSpacing, inv_mass, perturbation, SoftBodySharedSettings::EBendType::None);
  25. SoftBodyCreationSettings cloth(cloth_settings, RVec3(-5.0f, 5.0f, 0), Quat::sIdentity(), Layers::MOVING);
  26. mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
  27. }
  28. {
  29. random.seed(1234);
  30. // Cloth with distance bend constraints
  31. Ref<SoftBodySharedSettings> cloth_settings = SoftBodyCreator::CreateCloth(cNumVerticesX, cNumVerticesZ, cVertexSpacing, inv_mass, perturbation, SoftBodySharedSettings::EBendType::Distance);
  32. SoftBodyCreationSettings cloth(cloth_settings, RVec3(0.0f, 5.0f, 0), Quat::sIdentity(), Layers::MOVING);
  33. mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
  34. }
  35. {
  36. random.seed(1234);
  37. // Cloth with dihedral bend constraints
  38. Ref<SoftBodySharedSettings> cloth_settings = SoftBodyCreator::CreateCloth(cNumVerticesX, cNumVerticesZ, cVertexSpacing, inv_mass, perturbation, SoftBodySharedSettings::EBendType::Dihedral);
  39. SoftBodyCreationSettings cloth(cloth_settings, RVec3(5.0f, 5.0f, 0), Quat::sIdentity(), Layers::MOVING);
  40. mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
  41. }
  42. {
  43. random.seed(1234);
  44. // Cloth with Cosserat rod constraints
  45. Ref<SoftBodySharedSettings> cloth_settings = SoftBodyCreator::CreateCloth(cNumVerticesX, cNumVerticesZ, cVertexSpacing, inv_mass, perturbation, SoftBodySharedSettings::EBendType::None);
  46. // Get rid of created edges, we're replacing them with rods
  47. cloth_settings->mEdgeConstraints.clear();
  48. // Copy of SoftBodyCreator::CreateCloth: Function to get the vertex index of a point on the cloth
  49. auto vertex_index = [](uint inX, uint inY)
  50. {
  51. return inX + inY * cNumVerticesX;
  52. };
  53. // Create bend twist constraints
  54. constexpr float cCompliance = 1.0e-5f;
  55. auto get_rod = [&constraints = cloth_settings->mRodStretchShearConstraints, vertex_index, cCompliance](uint inX1, uint inZ1, uint inX2, uint inZ2)
  56. {
  57. uint32 v0 = vertex_index(inX1, inZ1);
  58. uint32 v1 = vertex_index(inX2, inZ2);
  59. JPH_ASSERT(v0 < v1);
  60. for (uint i = 0; i < uint(constraints.size()); ++i)
  61. if (constraints[i].mVertex[0] == v0 && constraints[i].mVertex[1] == v1)
  62. return i;
  63. constraints.emplace_back(v0, v1, cCompliance);
  64. return uint(constraints.size() - 1);
  65. };
  66. for (uint z = 1; z < cNumVerticesZ - 1; ++z)
  67. for (uint x = 0; x < cNumVerticesX - 1; ++x)
  68. {
  69. if (z > 1 && x < cNumVerticesX - 2)
  70. cloth_settings->mRodBendTwistConstraints.emplace_back(get_rod(x, z, x + 1, z), get_rod(x + 1, z, x + 2, z), cCompliance);
  71. if (z < cNumVerticesZ - 2)
  72. cloth_settings->mRodBendTwistConstraints.emplace_back(get_rod(x, z, x, z + 1), get_rod(x, z + 1, x, z + 2), cCompliance);
  73. if (x < cNumVerticesX - 2 && z < cNumVerticesZ - 2)
  74. {
  75. cloth_settings->mRodBendTwistConstraints.emplace_back(get_rod(x, z, x + 1, z + 1), get_rod(x + 1, z + 1, x + 2, z + 2), cCompliance);
  76. cloth_settings->mRodBendTwistConstraints.emplace_back(get_rod(x + 2, z, x + 1, z + 1), get_rod(x + 1, z + 1, x, z + 2), cCompliance);
  77. }
  78. }
  79. cloth_settings->CalculateRodProperties();
  80. // Optimize the settings
  81. cloth_settings->Optimize();
  82. SoftBodyCreationSettings cloth(cloth_settings, RVec3(10.0f, 5.0f, 0), Quat::sIdentity(), Layers::MOVING);
  83. mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
  84. }
  85. {
  86. // Create sphere
  87. SoftBodyCreationSettings sphere(SoftBodyCreator::CreateSphere(1.0f, 10, 20, SoftBodySharedSettings::EBendType::None), RVec3(-5.0f, 5.0f, 10.0f), Quat::sIdentity(), Layers::MOVING);
  88. mBodyInterface->CreateAndAddSoftBody(sphere, EActivation::Activate);
  89. }
  90. {
  91. // Create sphere with distance bend constraints
  92. SoftBodyCreationSettings sphere(SoftBodyCreator::CreateSphere(1.0f, 10, 20, SoftBodySharedSettings::EBendType::Distance), RVec3(0.0f, 5.0f, 10.0f), Quat::sIdentity(), Layers::MOVING);
  93. mBodyInterface->CreateAndAddSoftBody(sphere, EActivation::Activate);
  94. }
  95. {
  96. // Create sphere with dihedral bend constraints
  97. SoftBodyCreationSettings sphere(SoftBodyCreator::CreateSphere(1.0f, 10, 20, SoftBodySharedSettings::EBendType::Dihedral), RVec3(5.0f, 5.0f, 10.0f), Quat::sIdentity(), Layers::MOVING);
  98. mBodyInterface->CreateAndAddSoftBody(sphere, EActivation::Activate);
  99. }
  100. {
  101. // Create sphere with Cosserat rod constraints
  102. uint cNumTheta = 10;
  103. uint cNumPhi = 20;
  104. Ref<SoftBodySharedSettings> sphere_settings = SoftBodyCreator::CreateSphere(1.0f, cNumTheta, cNumPhi, SoftBodySharedSettings::EBendType::None);
  105. // Get rid of created edges, we're replacing them with rods
  106. sphere_settings->mEdgeConstraints.clear();
  107. // Copy of SoftBodyCreator::CreateSphere: Function to get the vertex index of a point on the sphere
  108. auto vertex_index = [cNumTheta, cNumPhi](uint inTheta, uint inPhi) -> uint
  109. {
  110. if (inTheta == 0)
  111. return 0;
  112. else if (inTheta == cNumTheta - 1)
  113. return 1;
  114. else
  115. return 2 + (inTheta - 1) * cNumPhi + inPhi % cNumPhi;
  116. };
  117. // Create bend twist constraints
  118. constexpr float cCompliance = 1.0e-4f;
  119. auto get_rod = [&constraints = sphere_settings->mRodStretchShearConstraints, vertex_index, cCompliance](uint inTheta1, uint inPhi1, uint inTheta2, uint inPhi2)
  120. {
  121. uint32 v0 = vertex_index(inTheta1, inPhi1);
  122. uint32 v1 = vertex_index(inTheta2, inPhi2);
  123. JPH_ASSERT(v0 != v1);
  124. for (uint i = 0; i < uint(constraints.size()); ++i)
  125. if ((constraints[i].mVertex[0] == v0 && constraints[i].mVertex[1] == v1)
  126. || (constraints[i].mVertex[0] == v1 && constraints[i].mVertex[1] == v0))
  127. return i;
  128. constraints.emplace_back(v0, v1, cCompliance);
  129. return uint(constraints.size() - 1);
  130. };
  131. // Rings along the side
  132. for (uint phi = 0; phi < cNumPhi; ++phi)
  133. for (uint theta = 0; theta < cNumTheta - 1; ++theta)
  134. {
  135. if (theta < cNumTheta - 2)
  136. sphere_settings->mRodBendTwistConstraints.emplace_back(get_rod(theta, phi, theta + 1, phi), get_rod(theta + 1, phi, theta + 2, phi), cCompliance);
  137. if (theta > 0 && phi < cNumPhi - 1)
  138. sphere_settings->mRodBendTwistConstraints.emplace_back(get_rod(theta, phi, theta, phi + 1), get_rod(theta, phi + 1, theta, (phi + 2) % cNumPhi), cCompliance);
  139. }
  140. // Close the caps
  141. for (uint phi1 = 0, phi2 = cNumPhi / 2; phi1 < cNumPhi / 2; ++phi1, phi2 = (phi2 + 1) % cNumPhi)
  142. {
  143. sphere_settings->mRodBendTwistConstraints.emplace_back(get_rod(0, phi1, 1, phi1), get_rod(0, phi2, 1, phi2), cCompliance);
  144. sphere_settings->mRodBendTwistConstraints.emplace_back(get_rod(cNumTheta - 2, phi1, cNumTheta - 1, phi1), get_rod(cNumTheta - 2, phi2, cNumTheta - 1, phi2), cCompliance);
  145. }
  146. sphere_settings->CalculateRodProperties();
  147. // Optimize the settings
  148. sphere_settings->Optimize();
  149. SoftBodyCreationSettings sphere(sphere_settings, RVec3(10.0f, 5.0f, 10.0f), Quat::sIdentity(), Layers::MOVING);
  150. mBodyInterface->CreateAndAddSoftBody(sphere, EActivation::Activate);
  151. }
  152. }
  153. void SoftBodyBendConstraintTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  154. {
  155. mDebugRenderer->DrawText3D(RVec3(-5.0f, 7.5f, 0), "No bend constraints", Color::sWhite);
  156. mDebugRenderer->DrawText3D(RVec3(0.0f, 7.5f, 0), "Distance bend constraints", Color::sWhite);
  157. mDebugRenderer->DrawText3D(RVec3(5.0f, 7.5f, 0), "Dihedral angle bend constraints", Color::sWhite);
  158. mDebugRenderer->DrawText3D(RVec3(10.0f, 7.5f, 0), "Cosserat rod constraints", Color::sWhite);
  159. }