SoftBodyContactListenerTest.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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/SoftBodyContactListenerTest.h>
  6. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  7. #include <Jolt/Physics/SoftBody/SoftBodyCreationSettings.h>
  8. #include <Jolt/Physics/SoftBody/SoftBodyManifold.h>
  9. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  10. #include <Utils/SoftBodyCreator.h>
  11. #include <Renderer/DebugRendererImp.h>
  12. #include <Layers.h>
  13. JPH_IMPLEMENT_RTTI_VIRTUAL(SoftBodyContactListenerTest)
  14. {
  15. JPH_ADD_BASE_CLASS(SoftBodyContactListenerTest, Test)
  16. }
  17. void SoftBodyContactListenerTest::Initialize()
  18. {
  19. // Install contact listener for soft bodies
  20. mPhysicsSystem->SetSoftBodyContactListener(this);
  21. // Floor
  22. CreateFloor();
  23. // Start the 1st cycle
  24. StartCycle();
  25. }
  26. void SoftBodyContactListenerTest::UpdateLabel()
  27. {
  28. // Draw current state
  29. const char *cycle_names[] = { "Accept contact", "Sphere 10x mass", "Cloth 10x mass", "Sphere infinite mass", "Cloth infinite mass", "Sensor contact", "Reject contact", "Kinematic Sphere", "Kinematic Sphere, cloth infinite mass", "Kinematic sphere, sensor contact", "Kinematic Sphere, reject contact" };
  30. SetBodyLabel(mOtherBodyID, cycle_names[mCycle]);
  31. }
  32. void SoftBodyContactListenerTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  33. {
  34. mTime += inParams.mDeltaTime;
  35. if (mTime > 2.5f)
  36. {
  37. // Next cycle
  38. mCycle = (mCycle + 1) % 10;
  39. mTime = 0.0f;
  40. // Remove the old scene
  41. mBodyInterface->RemoveBody(mOtherBodyID);
  42. mBodyInterface->DestroyBody(mOtherBodyID);
  43. mBodyInterface->RemoveBody(mSoftBodyID);
  44. mBodyInterface->DestroyBody(mSoftBodyID);
  45. // Start the new
  46. StartCycle();
  47. }
  48. UpdateLabel();
  49. }
  50. void SoftBodyContactListenerTest::StartCycle()
  51. {
  52. // Create the cloth
  53. Ref<SoftBodySharedSettings> cloth_settings = SoftBodyCreator::CreateClothWithFixatedCorners(15, 15, 0.75f);
  54. // Create cloth that's fixated at the corners
  55. SoftBodyCreationSettings cloth(cloth_settings, RVec3(0, 5, 0), Quat::sRotation(Vec3::sAxisY(), 0.25f * JPH_PI), Layers::MOVING);
  56. cloth.mUpdatePosition = false; // Don't update the position of the cloth as it is fixed to the world
  57. cloth.mMakeRotationIdentity = false; // Test explicitly checks if soft bodies with a rotation collide with shapes properly
  58. mSoftBodyID = mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
  59. // If we want a kinematic sphere
  60. bool kinematic = mCycle > 6;
  61. // Create sphere
  62. BodyCreationSettings bcs(new SphereShape(1.0f), RVec3(0, 7, 0), Quat::sIdentity(), kinematic? EMotionType::Kinematic : EMotionType::Dynamic, Layers::MOVING);
  63. bcs.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
  64. bcs.mMassPropertiesOverride.mMass = 100.0f;
  65. if (kinematic)
  66. bcs.mLinearVelocity = Vec3(0, -2.5f, 0);
  67. mOtherBodyID = mBodyInterface->CreateAndAddBody(bcs, EActivation::Activate);
  68. UpdateLabel();
  69. }
  70. SoftBodyValidateResult SoftBodyContactListenerTest::OnSoftBodyContactValidate(const Body &inSoftBody, const Body &inOtherBody, SoftBodyContactSettings &ioSettings)
  71. {
  72. switch (mCycle)
  73. {
  74. case 0:
  75. // Normal
  76. return SoftBodyValidateResult::AcceptContact;
  77. case 1:
  78. // Makes the sphere 10x as heavy
  79. ioSettings.mInvMassScale2 = 0.1f;
  80. ioSettings.mInvInertiaScale2 = 0.1f;
  81. return SoftBodyValidateResult::AcceptContact;
  82. case 2:
  83. // Makes the cloth 10x as heavy
  84. ioSettings.mInvMassScale1 = 0.1f;
  85. return SoftBodyValidateResult::AcceptContact;
  86. case 3:
  87. // Makes the sphere have infinite mass
  88. ioSettings.mInvMassScale2 = 0.0f;
  89. ioSettings.mInvInertiaScale2 = 0.0f;
  90. return SoftBodyValidateResult::AcceptContact;
  91. case 4:
  92. // Makes the cloth have infinite mass
  93. ioSettings.mInvMassScale1 = 0.0f;
  94. return SoftBodyValidateResult::AcceptContact;
  95. case 5:
  96. // Sensor contact
  97. ioSettings.mIsSensor = true;
  98. return SoftBodyValidateResult::AcceptContact;
  99. case 6:
  100. // No contacts
  101. return SoftBodyValidateResult::RejectContact;
  102. case 7:
  103. // Kinematic sphere
  104. return SoftBodyValidateResult::AcceptContact;
  105. case 8:
  106. // Kinematic sphere, cloth infinite mass
  107. ioSettings.mInvMassScale1 = 0.0f;
  108. return SoftBodyValidateResult::AcceptContact;
  109. case 9:
  110. // Kinematic sphere, sensor contact
  111. ioSettings.mIsSensor = true;
  112. return SoftBodyValidateResult::AcceptContact;
  113. default:
  114. // No contacts
  115. return SoftBodyValidateResult::RejectContact;
  116. }
  117. }
  118. void SoftBodyContactListenerTest::OnSoftBodyContactAdded(const Body &inSoftBody, const SoftBodyManifold &inManifold)
  119. {
  120. // Draw contacts
  121. RMat44 com = inSoftBody.GetCenterOfMassTransform();
  122. for (const SoftBodyVertex &vertex : inManifold.GetVertices())
  123. if (inManifold.HasContact(vertex))
  124. {
  125. RVec3 position = com * inManifold.GetLocalContactPoint(vertex);
  126. Vec3 normal = inManifold.GetContactNormal(vertex);
  127. mDebugRenderer->DrawMarker(position, Color::sRed, 0.1f);
  128. mDebugRenderer->DrawArrow(position, position + normal, Color::sGreen, 0.1f);
  129. }
  130. }