2
0

BroadPhaseInsertionTest.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/BroadPhase/BroadPhaseInsertionTest.h>
  6. #include <Jolt/Physics/Collision/RayCast.h>
  7. #include <Jolt/Physics/Collision/CastResult.h>
  8. #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
  9. #include <Jolt/Geometry/RayAABox.h>
  10. #include <Utils/Log.h>
  11. #include <Utils/DebugRendererSP.h>
  12. JPH_IMPLEMENT_RTTI_VIRTUAL(BroadPhaseInsertionTest)
  13. {
  14. JPH_ADD_BASE_CLASS(BroadPhaseInsertionTest, BroadPhaseTest)
  15. }
  16. void BroadPhaseInsertionTest::Initialize()
  17. {
  18. BroadPhaseTest::Initialize();
  19. CreateBalancedDistribution(mBodyManager, mBodyManager->GetMaxBodies());
  20. }
  21. void BroadPhaseInsertionTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  22. {
  23. // Check if we need to change direction
  24. if (mDirection == 1 && mCurrentBody >= mBodyManager->GetMaxBodies())
  25. mDirection = -1;
  26. if (mDirection == -1 && mCurrentBody == 0)
  27. mDirection = 1;
  28. int num_this_step = int(mBodyManager->GetMaxBodies() / 10);
  29. if (mDirection < 0)
  30. mCurrentBody -= num_this_step;
  31. Body **body_vector = mBodyManager->GetBodies().data();
  32. // Randomly move bodies around
  33. if (mCurrentBody > 0)
  34. {
  35. const int cNumBodiesToMove = 100;
  36. BodyID *bodies_to_move = new BodyID [cNumBodiesToMove];
  37. uniform_int_distribution<int> body_selector(0, (int)mCurrentBody - 1);
  38. uniform_real_distribution<float> translation_selector(1.0f, 5.0f);
  39. for (int i = 0; i < cNumBodiesToMove; ++i)
  40. {
  41. Body &body = *body_vector[body_selector(mRandomGenerator)];
  42. JPH_ASSERT(body.IsInBroadPhase());
  43. body.SetPositionAndRotationInternal(body.GetPosition() + translation_selector(mRandomGenerator) * Vec3::sRandom(mRandomGenerator), Quat::sIdentity());
  44. bodies_to_move[i] = body.GetID();
  45. }
  46. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_move, cNumBodiesToMove);
  47. delete [] bodies_to_move;
  48. }
  49. // Create batch of bodies
  50. BodyID *bodies_to_add_or_remove = new BodyID [num_this_step];
  51. for (int b = 0; b < num_this_step; ++b)
  52. bodies_to_add_or_remove[b] = body_vector[mCurrentBody + b]->GetID();
  53. // Add/remove them
  54. if (mDirection == 1)
  55. {
  56. // Prepare and abort
  57. BroadPhase::AddState add_state = mBroadPhase->AddBodiesPrepare(bodies_to_add_or_remove, num_this_step);
  58. mBroadPhase->AddBodiesAbort(bodies_to_add_or_remove, num_this_step, add_state);
  59. // Prepare and add
  60. add_state = mBroadPhase->AddBodiesPrepare(bodies_to_add_or_remove, num_this_step);
  61. mBroadPhase->AddBodiesFinalize(bodies_to_add_or_remove, num_this_step, add_state);
  62. }
  63. else
  64. mBroadPhase->RemoveBodies(bodies_to_add_or_remove, num_this_step);
  65. // Delete temp array
  66. delete [] bodies_to_add_or_remove;
  67. // Create ray
  68. default_random_engine random;
  69. Vec3 from = 1000.0f * Vec3::sRandom(random);
  70. RayCast ray { from, -2.0f * from };
  71. // Raycast before update
  72. AllHitCollisionCollector<RayCastBodyCollector> hits_before;
  73. mBroadPhase->CastRay(ray, hits_before);
  74. int num_before = (int)hits_before.mHits.size();
  75. BroadPhaseCastResult *results_before = hits_before.mHits.data();
  76. Trace("Before update: %d results found", num_before);
  77. // Draw results
  78. DrawLineSP(mDebugRenderer, ray.mOrigin, ray.mOrigin + ray.mDirection, Color::sRed);
  79. for (int i = 0; i < num_before; ++i)
  80. DrawMarkerSP(mDebugRenderer, ray.GetPointOnRay(results_before[i].mFraction), Color::sGreen, 10.0f);
  81. // Update the broadphase
  82. mBroadPhase->Optimize();
  83. // Raycast after update
  84. AllHitCollisionCollector<RayCastBodyCollector> hits_after;
  85. mBroadPhase->CastRay(ray, hits_after);
  86. int num_after = (int)hits_after.mHits.size();
  87. BroadPhaseCastResult *results_after = hits_after.mHits.data();
  88. Trace("After update: %d results found", num_after);
  89. // Before update we may have some false hits, check that there are less hits after update than before
  90. if (num_after > num_before)
  91. FatalError("BroadPhaseInsertionTest: After has more hits than before");
  92. for (BroadPhaseCastResult *ra = results_after, *ra_end = results_after + num_after; ra < ra_end; ++ra)
  93. {
  94. bool found = false;
  95. for (BroadPhaseCastResult *rb = results_before, *rb_end = results_before + num_before; rb < rb_end; ++rb)
  96. if (ra->mBodyID == rb->mBodyID)
  97. {
  98. found = true;
  99. break;
  100. }
  101. if (!found)
  102. FatalError("BroadPhaseInsertionTest: Result after not found in result before");
  103. }
  104. // Validate with brute force approach
  105. for (const Body *b : mBodyManager->GetBodies())
  106. {
  107. bool found = false;
  108. for (BroadPhaseCastResult *r = results_after, *r_end = results_after + num_after; r < r_end; ++r)
  109. if (r->mBodyID == b->GetID())
  110. {
  111. found = true;
  112. break;
  113. }
  114. if (b->IsInBroadPhase()
  115. && RayAABoxHits(ray.mOrigin, ray.mDirection, b->GetWorldSpaceBounds().mMin, b->GetWorldSpaceBounds().mMax))
  116. {
  117. if (!found)
  118. FatalError("BroadPhaseInsertionTest: Is intersecting but was not found");
  119. }
  120. else
  121. {
  122. if (found)
  123. FatalError("BroadPhaseInsertionTest: Is not intersecting but was found");
  124. }
  125. }
  126. if (mDirection > 0)
  127. mCurrentBody += num_this_step;
  128. }