SoftBodyCosseratRodConstraintTest.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/SoftBody/SoftBodyCosseratRodConstraintTest.h>
  6. #include <Jolt/Physics/SoftBody/SoftBodyCreationSettings.h>
  7. #include <Jolt/Physics/SoftBody/SoftBodyMotionProperties.h>
  8. #include <Utils/SoftBodyCreator.h>
  9. #include <Layers.h>
  10. #include <Renderer/DebugRendererImp.h>
  11. JPH_IMPLEMENT_RTTI_VIRTUAL(SoftBodyCosseratRodConstraintTest)
  12. {
  13. JPH_ADD_BASE_CLASS(SoftBodyCosseratRodConstraintTest, Test)
  14. }
  15. void SoftBodyCosseratRodConstraintTest::Initialize()
  16. {
  17. CreateFloor();
  18. // Create a hanging helix
  19. {
  20. constexpr float cRadius = 0.5f;
  21. constexpr int cNumVertices = 128;
  22. constexpr float cHeight = 5.0f;
  23. constexpr float cNumCycles = 10;
  24. Ref<SoftBodySharedSettings> helix_settings = new SoftBodySharedSettings;
  25. for (int i = 0; i < cNumVertices; ++i)
  26. {
  27. float fraction = float(i) / (cNumVertices - 1);
  28. SoftBodySharedSettings::Vertex v;
  29. float alpha = cNumCycles * 2.0f * JPH_PI * fraction;
  30. v.mPosition = Float3(cRadius * Sin(alpha), 0.5f * (1.0f - fraction * cHeight), cRadius * Cos(alpha));
  31. v.mInvMass = i == 0? 0.0f : 1.0e-2f;
  32. helix_settings->mVertices.push_back(v);
  33. if (i > 0)
  34. helix_settings->mRodStretchShearConstraints.push_back(SoftBodySharedSettings::RodStretchShear(i - 1, i));
  35. if (i > 1)
  36. helix_settings->mRodBendTwistConstraints.push_back(SoftBodySharedSettings::RodBendTwist(i - 2, i - 1));
  37. }
  38. helix_settings->CalculateRodProperties();
  39. helix_settings->Optimize();
  40. SoftBodyCreationSettings helix(helix_settings, RVec3(0, 10, 0), Quat::sIdentity(), Layers::MOVING);
  41. mSoftBodies.push_back(mBodyInterface->CreateAndAddSoftBody(helix, EActivation::Activate));
  42. }
  43. // Create a tree with a static root
  44. {
  45. // Root particle
  46. Ref<SoftBodySharedSettings> tree_settings = new SoftBodySharedSettings;
  47. SoftBodySharedSettings::Vertex v;
  48. v.mPosition = Float3(0, 0, 0);
  49. v.mInvMass = 0.0f;
  50. tree_settings->mVertices.push_back(v);
  51. // Create branches
  52. struct Branch
  53. {
  54. uint32 mPreviousVertex;
  55. uint32 mPreviousRod;
  56. Vec3 mDirection;
  57. uint32 mDepth;
  58. };
  59. Array<Branch> branches;
  60. branches.push_back({ 0, uint32(-1), Vec3::sAxisY(), 0 });
  61. while (!branches.empty())
  62. {
  63. // Take the next branch
  64. Branch branch = branches.front();
  65. branches.erase(branches.begin());
  66. // Create vertex
  67. SoftBodySharedSettings::Vertex &previous_vertex = tree_settings->mVertices[branch.mPreviousVertex];
  68. (Vec3(previous_vertex.mPosition) + branch.mDirection).StoreFloat3(&v.mPosition);
  69. v.mInvMass = branch.mDepth > 0? 2.0f * previous_vertex.mInvMass : 1.0e-3f;
  70. uint32 new_vertex = uint32(tree_settings->mVertices.size());
  71. tree_settings->mVertices.push_back(v);
  72. // Create rod
  73. uint32 new_rod = uint32(tree_settings->mRodStretchShearConstraints.size());
  74. tree_settings->mRodStretchShearConstraints.push_back(SoftBodySharedSettings::RodStretchShear(branch.mPreviousVertex, new_vertex));
  75. if (branch.mPreviousRod != uint32(-1))
  76. tree_settings->mRodBendTwistConstraints.push_back(SoftBodySharedSettings::RodBendTwist(branch.mPreviousRod, new_rod));
  77. // Create sub branches
  78. if (branch.mDepth < 10)
  79. for (uint32 i = 0; i < 2; ++i)
  80. {
  81. // Determine new child direction
  82. float angle = DegreesToRadians(-15.0f + i * 30.0f);
  83. Vec3 new_direction = Quat::sRotation(branch.mDepth & 1? Vec3::sAxisZ() : Vec3::sAxisX(), angle) * branch.mDirection;
  84. // Create new branch
  85. branches.push_back({ new_vertex, new_rod, new_direction, branch.mDepth + 1 });
  86. }
  87. }
  88. tree_settings->CalculateRodProperties();
  89. tree_settings->Optimize();
  90. SoftBodyCreationSettings tree(tree_settings, RVec3(10, 0, 0), Quat::sIdentity(), Layers::MOVING);
  91. mSoftBodies.push_back(mBodyInterface->CreateAndAddSoftBody(tree, EActivation::Activate));
  92. }
  93. // Create a weed like structure
  94. {
  95. // Root particle
  96. Ref<SoftBodySharedSettings> weed_settings = new SoftBodySharedSettings;
  97. constexpr int cNumVertices = 64;
  98. constexpr int cNumStrands = 50;
  99. default_random_engine random;
  100. uniform_real_distribution<float> radius_distribution(0, 1.0f);
  101. uniform_real_distribution<float> phase_distribution(0, 2.0f * JPH_PI);
  102. for (int strand = 0; strand < cNumStrands; ++strand)
  103. {
  104. // Place at a random location
  105. float radius = radius_distribution(random);
  106. float theta = phase_distribution(random);
  107. Vec3 root_pos = Vec3(radius * Sin(theta), 0, radius * Cos(theta));
  108. // Randomize the phase of the wave
  109. float phase1 = phase_distribution(random);
  110. float phase2 = phase_distribution(random);
  111. uint32 first_vertex = uint32(weed_settings->mVertices.size());
  112. for (int i = 0; i < cNumVertices; ++i)
  113. {
  114. // Generate a wavy pattern
  115. float amplitude = 0.1f * Sin(phase1 + i * 2.0f * JPH_PI / 8);
  116. Vec3 pos = root_pos + Vec3(Sin(phase2) * amplitude, 0.1f * i, Cos(phase2) * amplitude);
  117. SoftBodySharedSettings::Vertex v;
  118. pos.StoreFloat3(&v.mPosition);
  119. v.mInvMass = i == 0? 0.0f : 0.1f;
  120. weed_settings->mVertices.push_back(v);
  121. }
  122. uint32 first_rod = uint32(weed_settings->mRodStretchShearConstraints.size());
  123. for (int i = 0; i < cNumVertices - 1; ++i)
  124. weed_settings->mRodStretchShearConstraints.push_back(SoftBodySharedSettings::RodStretchShear(first_vertex + i, first_vertex + i + 1));
  125. for (int i = 0; i < cNumVertices - 2; ++i)
  126. weed_settings->mRodBendTwistConstraints.push_back(SoftBodySharedSettings::RodBendTwist(first_rod + i, first_rod + i + 1));
  127. }
  128. weed_settings->CalculateRodProperties();
  129. weed_settings->Optimize();
  130. SoftBodyCreationSettings weed(weed_settings, RVec3(20, 0, 0), Quat::sIdentity(), Layers::MOVING);
  131. weed.mGravityFactor = 0.8f;
  132. mSoftBodies.push_back(mBodyInterface->CreateAndAddSoftBody(weed, EActivation::Activate));
  133. }
  134. }
  135. void SoftBodyCosseratRodConstraintTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  136. {
  137. // Draw the soft body rods
  138. for (BodyID id : mSoftBodies)
  139. {
  140. BodyLockRead lock(mPhysicsSystem->GetBodyLockInterface(), id);
  141. if (lock.Succeeded())
  142. {
  143. const Body &body = lock.GetBody();
  144. const SoftBodyMotionProperties *mp = static_cast<const SoftBodyMotionProperties *>(body.GetMotionProperties());
  145. RMat44 com = body.GetCenterOfMassTransform();
  146. for (const SoftBodySharedSettings::RodStretchShear &r : mp->GetSettings()->mRodStretchShearConstraints)
  147. {
  148. RVec3 x0 = com * mp->GetVertex(r.mVertex[0]).mPosition;
  149. RVec3 x1 = com * mp->GetVertex(r.mVertex[1]).mPosition;
  150. mDebugRenderer->DrawLine(x0, x1, Color::sWhite);
  151. }
  152. }
  153. }
  154. }