BigWorldTest.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2022 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/Rig/BigWorldTest.h>
  6. #include <Jolt/Physics/PhysicsScene.h>
  7. #include <Jolt/Skeleton/Skeleton.h>
  8. #include <Jolt/Skeleton/SkeletalAnimation.h>
  9. #include <Jolt/Skeleton/SkeletonPose.h>
  10. #include <Jolt/Core/StringTools.h>
  11. #include <Jolt/ObjectStream/ObjectStreamIn.h>
  12. #include <Utils/RagdollLoader.h>
  13. #include <Application/DebugUI.h>
  14. #include <Renderer/DebugRendererImp.h>
  15. #include <Layers.h>
  16. #include <Utils/Log.h>
  17. #include <Utils/AssetStream.h>
  18. #include <random>
  19. JPH_IMPLEMENT_RTTI_VIRTUAL(BigWorldTest)
  20. {
  21. JPH_ADD_BASE_CLASS(BigWorldTest, Test)
  22. }
  23. BigWorldTest::~BigWorldTest()
  24. {
  25. for (Pile &pile : mPiles)
  26. for (Ragdoll *r : pile.mRagdolls)
  27. r->RemoveFromPhysicsSystem();
  28. }
  29. void BigWorldTest::Initialize()
  30. {
  31. constexpr int cPileSize = 5;
  32. // Default terrain
  33. Body &floor = CreateMeshTerrain();
  34. RefConst<Shape> shape = floor.GetShape();
  35. // Load ragdoll
  36. Ref<RagdollSettings> settings = RagdollLoader::sLoad("Human.tof", EMotionType::Dynamic);
  37. // Load animation
  38. Ref<SkeletalAnimation> animation;
  39. AssetStream stream("Human/dead_pose1.tof", std::ios::in);
  40. if (!ObjectStreamIn::sReadObject(stream.Get(), animation))
  41. FatalError("Could not open animation");
  42. SkeletonPose pose;
  43. pose.SetSkeleton(settings->GetSkeleton());
  44. animation->Sample(0.0f, pose);
  45. // Determine rotation for each ragdoll in the pile
  46. default_random_engine random;
  47. uniform_real_distribution<float> angle(0.0f, JPH_PI);
  48. Array<Quat> rotation;
  49. for (int i = 0; i < cPileSize; ++i)
  50. rotation.push_back(Quat::sRotation(Vec3::sAxisY(), angle(random)) * pose.GetJoint(0).mRotation);
  51. // Create piles at various distances
  52. Real distances[] = { 0.0_r, 1.0e3_r, 5.0e3_r, 1.0e4_r, 5.0e4_r, 1.0e5_r, 1.0e6_r, 1.0e7_r, 1.0e8_r };
  53. for (Real distance : distances)
  54. {
  55. // Calculate origin for this simulation assuming we want to be 'distance' away and the same distance along each coordinate axis
  56. RVec3 origin = RVec3::sReplicate(distance) / sqrt(3.0_r);
  57. // Create floor (floor at 0 was already created)
  58. if (distance != 0.0f)
  59. mBodyInterface->CreateAndAddBody(BodyCreationSettings(shape, origin, Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING), EActivation::DontActivate);
  60. // Create pile of ragdolls
  61. Pile pile;
  62. pile.mOrigin = origin;
  63. for (int i = 0; i < cPileSize; ++i)
  64. {
  65. // Create ragdoll
  66. Ref<Ragdoll> ragdoll = settings->CreateRagdoll(0, 0, mPhysicsSystem);
  67. // Override root
  68. SkeletonPose::JointState &root = pose.GetJoint(0);
  69. root.mTranslation = Vec3::sZero();
  70. root.mRotation = rotation[i];
  71. pose.SetRootOffset(origin + Vec3(0, 2.0f + 0.6f * i, 0));
  72. pose.CalculateJointMatrices();
  73. // Drive to pose
  74. ragdoll->SetPose(pose);
  75. ragdoll->DriveToPoseUsingMotors(pose);
  76. ragdoll->AddToPhysicsSystem(EActivation::Activate);
  77. pile.mRagdolls.push_back(ragdoll);
  78. }
  79. mPiles.push_back(pile);
  80. }
  81. }
  82. void BigWorldTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  83. {
  84. int pile_idx = 0;
  85. for (Pile &pile : mPiles)
  86. if (!pile.mOrigin.IsNearZero()) // Pile at 0 is drawn normally
  87. {
  88. // Check if we need to draw this pile
  89. if ((sDrawPileMask & (1 << pile_idx)) != 0)
  90. {
  91. Color color = Color::sGetDistinctColor(pile_idx);
  92. bool first = true;
  93. for (Ragdoll *r : pile.mRagdolls)
  94. {
  95. for (const BodyID &id : r->GetBodyIDs())
  96. {
  97. BodyLockRead lock(mPhysicsSystem->GetBodyLockInterface(), id);
  98. if (lock.Succeeded())
  99. {
  100. const Body &body = lock.GetBody();
  101. // Shift the transform back to the origin
  102. RMat44 transform = body.GetCenterOfMassTransform();
  103. transform.SetTranslation(transform.GetTranslation() - pile.mOrigin);
  104. // Draw distance label for the first body
  105. if (first)
  106. {
  107. mDebugRenderer->DrawText3D(transform.GetTranslation(), pile.GetLabel().c_str(), color, 0.2f);
  108. first = false;
  109. }
  110. #ifdef JPH_DEBUG_RENDERER
  111. // Draw the shape
  112. body.GetShape()->Draw(mDebugRenderer, transform, Vec3::sReplicate(1.0f), color, false, sDrawWireframe);
  113. #endif // JPH_DEBUG_RENDERER
  114. }
  115. }
  116. }
  117. }
  118. pile_idx++;
  119. }
  120. }
  121. void BigWorldTest::CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu)
  122. {
  123. // Draw in wireframe?
  124. inUI->CreateCheckBox(inSubMenu, "Draw distant scenes in wireframe", sDrawWireframe, [](UICheckBox::EState inState) { sDrawWireframe = inState == UICheckBox::STATE_CHECKED; });
  125. // Enable / disable drawing of a particular distance
  126. int pile_idx = 0;
  127. for (Pile &pile : mPiles)
  128. if (!pile.mOrigin.IsNearZero())
  129. {
  130. uint32 mask = 1 << pile_idx;
  131. inUI->CreateCheckBox(inSubMenu, "Draw pile at " + pile.GetLabel(), (sDrawPileMask & mask) != 0, [mask](UICheckBox::EState inState) { if (inState == UICheckBox::STATE_CHECKED) sDrawPileMask |= mask; else sDrawPileMask &= ~mask; });
  132. pile_idx++;
  133. }
  134. // Goto pile at a particular distance
  135. for (Pile &pile : mPiles)
  136. inUI->CreateTextButton(inSubMenu, "Goto pile at " + pile.GetLabel(), [this, &pile]() { sPivot = pile.mOrigin; RestartTest(); });
  137. }
  138. RMat44 BigWorldTest::GetCameraPivot(float inCameraHeading, float inCameraPitch) const
  139. {
  140. return RMat44::sTranslation(sPivot);
  141. }
  142. RVec3 BigWorldTest::GetDrawOffset() const
  143. {
  144. return sPivot;
  145. }