SoftBodyContactListenerTest.cpp 4.8 KB

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