BroadPhaseQuadTree.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/Collision/BroadPhase/BroadPhaseQuadTree.h>
  5. #include <Physics/Collision/RayCast.h>
  6. #include <Physics/Collision/AABoxCast.h>
  7. #include <Physics/Collision/CastResult.h>
  8. #include <Physics/PhysicsLock.h>
  9. namespace JPH {
  10. BroadPhaseQuadTree::~BroadPhaseQuadTree()
  11. {
  12. delete [] mLayers;
  13. }
  14. void BroadPhaseQuadTree::Init(BodyManager* inBodyManager, const ObjectToBroadPhaseLayer &inObjectToBroadPhaseLayer)
  15. {
  16. BroadPhase::Init(inBodyManager, inObjectToBroadPhaseLayer);
  17. // Store input parameters
  18. mObjectToBroadPhaseLayer = inObjectToBroadPhaseLayer;
  19. // Store max bodies
  20. mMaxBodies = inBodyManager->GetMaxBodies();
  21. // Initialize tracking data
  22. mTracking.resize(mMaxBodies);
  23. // Init allocator
  24. // Estimate the amount of nodes we're going to need
  25. uint32 num_leaves = (uint32)(mMaxBodies + 1) / 2; // Assume 50% fill
  26. uint32 num_leaves_plus_internal_nodes = num_leaves + (num_leaves + 2) / 3; // = Sum(num_leaves * 4^-i) with i = [0, Inf].
  27. mAllocator.Init(2 * num_leaves_plus_internal_nodes, 256); // We use double the amount of nodes while rebuilding the tree during Update()
  28. // Determine min and max layers
  29. BroadPhaseLayer::Type min_layer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid, max_layer = 0;
  30. for (BroadPhaseLayer layer : inObjectToBroadPhaseLayer)
  31. {
  32. min_layer = min(min_layer, (BroadPhaseLayer::Type)layer);
  33. max_layer = max(max_layer, (BroadPhaseLayer::Type)layer);
  34. }
  35. JPH_ASSERT(min_layer == 0); // Assume layers start at 0
  36. JPH_ASSERT(max_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid); // Assume the invalid layer is unused
  37. mNumLayers = max_layer + 1;
  38. // Init sub trees
  39. mLayers = new QuadTree [mNumLayers];
  40. for (uint l = 0; l < mNumLayers; ++l)
  41. mLayers[l].Init(mAllocator);
  42. }
  43. void BroadPhaseQuadTree::FrameSync()
  44. {
  45. JPH_PROFILE_FUNCTION();
  46. // Take a unique lock on the old query lock so that we know no one is using the old nodes anymore.
  47. // Note that nothing should be locked at this point to avoid risking a lock inversion deadlock.
  48. // Note that in other places where we lock this mutex we don't use SharedLock to detect lock inversions. As long as
  49. // nothing else is locked this is safe. This is why BroadPhaseQuery should be the highest priority lock.
  50. UniqueLock root_lock(mQueryLocks[mQueryLockIdx ^ 1], EPhysicsLockTypes::BroadPhaseQuery);
  51. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  52. mLayers[l].DiscardOldTree();
  53. }
  54. void BroadPhaseQuadTree::Optimize()
  55. {
  56. JPH_PROFILE_FUNCTION();
  57. FrameSync();
  58. LockModifications();
  59. for (uint l = 0; l < mNumLayers; ++l)
  60. {
  61. QuadTree &tree = mLayers[l];
  62. if (tree.HasBodies() && tree.IsDirty())
  63. {
  64. QuadTree::UpdateState update_state;
  65. tree.UpdatePrepare(mBodyManager->GetBodies(), mTracking, update_state);
  66. tree.UpdateFinalize(mBodyManager->GetBodies(), mTracking, update_state);
  67. }
  68. }
  69. UnlockModifications();
  70. mNextLayerToUpdate = 0;
  71. }
  72. void BroadPhaseQuadTree::LockModifications()
  73. {
  74. // From this point on we prevent modifications to the tree
  75. PhysicsLock::sLock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  76. }
  77. BroadPhase::UpdateState BroadPhaseQuadTree::UpdatePrepare()
  78. {
  79. // LockModifications should have been called
  80. JPH_ASSERT(mUpdateMutex.is_locked());
  81. // Create update state
  82. UpdateState update_state;
  83. UpdateStateImpl *update_state_impl = reinterpret_cast<UpdateStateImpl *>(&update_state);
  84. // Loop until we've seen all layers
  85. for (uint iteration = 0; iteration < mNumLayers; ++iteration)
  86. {
  87. // Get the layer
  88. QuadTree &tree = mLayers[mNextLayerToUpdate];
  89. mNextLayerToUpdate = (mNextLayerToUpdate + 1) % mNumLayers;
  90. // If it is dirty we update this one
  91. if (tree.HasBodies() && tree.IsDirty() && tree.CanBeUpdated())
  92. {
  93. update_state_impl->mTree = &tree;
  94. tree.UpdatePrepare(mBodyManager->GetBodies(), mTracking, update_state_impl->mUpdateState);
  95. return update_state;
  96. }
  97. }
  98. // Nothing to update
  99. update_state_impl->mTree = nullptr;
  100. return update_state;
  101. }
  102. void BroadPhaseQuadTree::UpdateFinalize(UpdateState &inUpdateState)
  103. {
  104. // LockModifications should have been called
  105. JPH_ASSERT(mUpdateMutex.is_locked());
  106. // Test if a tree was updated
  107. UpdateStateImpl *update_state_impl = reinterpret_cast<UpdateStateImpl *>(&inUpdateState);
  108. if (update_state_impl->mTree == nullptr)
  109. return;
  110. update_state_impl->mTree->UpdateFinalize(mBodyManager->GetBodies(), mTracking, update_state_impl->mUpdateState);
  111. // Make all queries from now on use the new lock
  112. mQueryLockIdx = mQueryLockIdx ^ 1;
  113. }
  114. void BroadPhaseQuadTree::UnlockModifications()
  115. {
  116. // From this point on we allow modifications to the tree again
  117. PhysicsLock::sUnlock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  118. }
  119. BroadPhase::AddState BroadPhaseQuadTree::AddBodiesPrepare(BodyID *ioBodies, int inNumber)
  120. {
  121. JPH_PROFILE_FUNCTION();
  122. JPH_ASSERT(inNumber > 0);
  123. const BodyVector &bodies = mBodyManager->GetBodies();
  124. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  125. LayerState *state = new LayerState [mNumLayers];
  126. // Sort bodies on layer
  127. const BroadPhaseLayer *object_to_broadphase = mObjectToBroadPhaseLayer.data();
  128. Body * const * const bodies_ptr = bodies.data(); // C pointer or else sort is incredibly slow in debug mode
  129. sort(ioBodies, ioBodies + inNumber, [bodies_ptr, object_to_broadphase](BodyID inLHS, BodyID inRHS) { return object_to_broadphase[bodies_ptr[inLHS.GetIndex()]->GetObjectLayer()] < object_to_broadphase[bodies_ptr[inRHS.GetIndex()]->GetObjectLayer()]; });
  130. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  131. while (b_start < b_end)
  132. {
  133. // Get broadphase layer
  134. ObjectLayer first_body_object_layer = bodies[b_start->GetIndex()]->GetObjectLayer();
  135. JPH_ASSERT(first_body_object_layer < mObjectToBroadPhaseLayer.size());
  136. BroadPhaseLayer::Type broadphase_layer = (BroadPhaseLayer::Type)object_to_broadphase[first_body_object_layer];
  137. JPH_ASSERT(broadphase_layer < mNumLayers);
  138. // Find first body with different layer
  139. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [bodies_ptr, object_to_broadphase](BroadPhaseLayer::Type inLayer, BodyID inBodyID) { return inLayer < (BroadPhaseLayer::Type)object_to_broadphase[bodies_ptr[inBodyID.GetIndex()]->GetObjectLayer()]; });
  140. // Keep track of state for this layer
  141. LayerState &layer_state = state[broadphase_layer];
  142. layer_state.mBodyStart = b_start;
  143. layer_state.mBodyEnd = b_mid;
  144. // Insert all bodies of the same layer
  145. mLayers[broadphase_layer].AddBodiesPrepare(bodies, mTracking, b_start, int(b_mid - b_start), layer_state.mAddState);
  146. // Keep track in which tree we placed the object
  147. for (const BodyID *b = b_start; b < b_mid; ++b)
  148. {
  149. uint32 index = b->GetIndex();
  150. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  151. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  152. Tracking &t = mTracking[index];
  153. JPH_ASSERT(t.mBroadPhaseLayer == (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  154. t.mBroadPhaseLayer = broadphase_layer;
  155. JPH_ASSERT(t.mObjectLayer == cObjectLayerInvalid);
  156. t.mObjectLayer = bodies[index]->GetObjectLayer();
  157. }
  158. // Repeat
  159. b_start = b_mid;
  160. }
  161. return state;
  162. }
  163. void BroadPhaseQuadTree::AddBodiesFinalize(BodyID *ioBodies, int inNumber, AddState inAddState)
  164. {
  165. JPH_PROFILE_FUNCTION();
  166. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  167. SharedLock lock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  168. BodyVector &bodies = mBodyManager->GetBodies();
  169. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  170. LayerState *state = (LayerState *)inAddState;
  171. for (BroadPhaseLayer::Type broadphase_layer = 0; broadphase_layer < mNumLayers; broadphase_layer++)
  172. {
  173. const LayerState &l = state[broadphase_layer];
  174. if (l.mBodyStart != nullptr)
  175. {
  176. // Insert all bodies of the same layer
  177. mLayers[broadphase_layer].AddBodiesFinalize(mTracking, int(l.mBodyEnd - l.mBodyStart), l.mAddState);
  178. // Mark added to broadphase
  179. for (const BodyID *b = l.mBodyStart; b < l.mBodyEnd; ++b)
  180. {
  181. uint32 index = b->GetIndex();
  182. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  183. JPH_ASSERT(mTracking[index].mBroadPhaseLayer == broadphase_layer);
  184. JPH_ASSERT(mTracking[index].mObjectLayer == bodies[index]->GetObjectLayer());
  185. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  186. bodies[index]->SetInBroadPhaseInternal(true);
  187. }
  188. }
  189. }
  190. delete [] state;
  191. }
  192. void BroadPhaseQuadTree::AddBodiesAbort(BodyID *ioBodies, int inNumber, AddState inAddState)
  193. {
  194. JPH_PROFILE_FUNCTION();
  195. JPH_IF_ENABLE_ASSERTS(const BodyVector &bodies = mBodyManager->GetBodies();)
  196. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  197. LayerState *state = (LayerState *)inAddState;
  198. for (BroadPhaseLayer::Type broadphase_layer = 0; broadphase_layer < mNumLayers; broadphase_layer++)
  199. {
  200. const LayerState &l = state[broadphase_layer];
  201. if (l.mBodyStart != nullptr)
  202. {
  203. // Insert all bodies of the same layer
  204. mLayers[broadphase_layer].AddBodiesAbort(mTracking, l.mAddState);
  205. // Reset bookkeeping
  206. for (const BodyID *b = l.mBodyStart; b < l.mBodyEnd; ++b)
  207. {
  208. uint32 index = b->GetIndex();
  209. JPH_ASSERT(bodies[index]->GetID() == *b, "Provided BodyID doesn't match BodyID in body manager");
  210. JPH_ASSERT(!bodies[index]->IsInBroadPhase());
  211. Tracking &t = mTracking[index];
  212. JPH_ASSERT(t.mBroadPhaseLayer == broadphase_layer);
  213. t.mBroadPhaseLayer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid;
  214. t.mObjectLayer = cObjectLayerInvalid;
  215. }
  216. }
  217. }
  218. delete [] state;
  219. }
  220. void BroadPhaseQuadTree::RemoveBodies(BodyID *ioBodies, int inNumber)
  221. {
  222. JPH_PROFILE_FUNCTION();
  223. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  224. SharedLock lock(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  225. JPH_ASSERT(inNumber > 0);
  226. BodyVector &bodies = mBodyManager->GetBodies();
  227. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  228. // Sort bodies on layer
  229. Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  230. sort(ioBodies, ioBodies + inNumber, [tracking](BodyID inLHS, BodyID inRHS) { return tracking[inLHS.GetIndex()].mBroadPhaseLayer < tracking[inRHS.GetIndex()].mBroadPhaseLayer; });
  231. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  232. while (b_start < b_end)
  233. {
  234. // Get broad phase layer
  235. BroadPhaseLayer::Type broadphase_layer = mTracking[b_start->GetIndex()].mBroadPhaseLayer;
  236. JPH_ASSERT(broadphase_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  237. // Find first body with different layer
  238. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [tracking](BroadPhaseLayer::Type inLayer, BodyID inBodyID) { return inLayer < tracking[inBodyID.GetIndex()].mBroadPhaseLayer; });
  239. // Remove all bodies of the same layer
  240. mLayers[broadphase_layer].RemoveBodies(bodies, mTracking, b_start, int(b_mid - b_start));
  241. for (const BodyID *b = b_start; b < b_mid; ++b)
  242. {
  243. // Reset bookkeeping
  244. uint32 index = b->GetIndex();
  245. Tracking &t = tracking[index];
  246. t.mBroadPhaseLayer = (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid;
  247. t.mObjectLayer = cObjectLayerInvalid;
  248. // Mark removed from broadphase
  249. JPH_ASSERT(bodies[index]->IsInBroadPhase());
  250. bodies[index]->SetInBroadPhaseInternal(false);
  251. }
  252. // Repeat
  253. b_start = b_mid;
  254. }
  255. }
  256. void BroadPhaseQuadTree::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock)
  257. {
  258. JPH_PROFILE_FUNCTION();
  259. JPH_ASSERT(inNumber > 0);
  260. // This cannot run concurrently with UpdatePrepare()/UpdateFinalize()
  261. if (inTakeLock)
  262. PhysicsLock::sLockShared(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  263. else
  264. JPH_ASSERT(mUpdateMutex.is_locked());
  265. const BodyVector &bodies = mBodyManager->GetBodies();
  266. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  267. // Sort bodies on layer
  268. const Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  269. sort(ioBodies, ioBodies + inNumber, [tracking](BodyID inLHS, BodyID inRHS) { return tracking[inLHS.GetIndex()].mBroadPhaseLayer < tracking[inRHS.GetIndex()].mBroadPhaseLayer; });
  270. BodyID *b_start = ioBodies, *b_end = ioBodies + inNumber;
  271. while (b_start < b_end)
  272. {
  273. // Get broadphase layer
  274. BroadPhaseLayer::Type broadphase_layer = tracking[b_start->GetIndex()].mBroadPhaseLayer;
  275. JPH_ASSERT(broadphase_layer != (BroadPhaseLayer::Type)cBroadPhaseLayerInvalid);
  276. // Find first body with different layer
  277. BodyID *b_mid = upper_bound(b_start, b_end, broadphase_layer, [tracking](BroadPhaseLayer::Type inLayer, BodyID inBodyID) { return inLayer < tracking[inBodyID.GetIndex()].mBroadPhaseLayer; });
  278. // Nodify all bodies of the same layer changed
  279. mLayers[broadphase_layer].NotifyBodiesAABBChanged(bodies, mTracking, b_start, int(b_mid - b_start));
  280. // Repeat
  281. b_start = b_mid;
  282. }
  283. if (inTakeLock)
  284. PhysicsLock::sUnlockShared(mUpdateMutex, EPhysicsLockTypes::BroadPhaseUpdate);
  285. }
  286. void BroadPhaseQuadTree::NotifyBodiesLayerChanged(BodyID *ioBodies, int inNumber)
  287. {
  288. JPH_PROFILE_FUNCTION();
  289. JPH_ASSERT(inNumber > 0);
  290. // First sort the bodies that actually changed layer to beginning of the array
  291. const BodyVector &bodies = mBodyManager->GetBodies();
  292. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  293. for (BodyID *body_id = ioBodies + inNumber - 1; body_id >= ioBodies; --body_id)
  294. {
  295. uint32 index = body_id->GetIndex();
  296. JPH_ASSERT(bodies[index]->GetID() == *body_id, "Provided BodyID doesn't match BodyID in body manager");
  297. ObjectLayer object_layer = bodies[index]->GetObjectLayer();
  298. JPH_ASSERT(object_layer < mObjectToBroadPhaseLayer.size());
  299. BroadPhaseLayer::Type broadphase_layer = (BroadPhaseLayer::Type)mObjectToBroadPhaseLayer[object_layer];
  300. JPH_ASSERT(broadphase_layer < mNumLayers);
  301. if (mTracking[index].mBroadPhaseLayer == broadphase_layer)
  302. {
  303. // Update tracking information
  304. mTracking[index].mObjectLayer = object_layer;
  305. // If move the body to the end, layer didn't change
  306. swap(*body_id, ioBodies[inNumber - 1]);
  307. --inNumber;
  308. }
  309. }
  310. if (inNumber > 0)
  311. {
  312. // Changing layer requires us to remove from one tree and add to another, so this is equivalent to removing all bodies first and then adding them again
  313. RemoveBodies(ioBodies, inNumber);
  314. AddState add_state = AddBodiesPrepare(ioBodies, inNumber);
  315. AddBodiesFinalize(ioBodies, inNumber, add_state);
  316. }
  317. }
  318. void BroadPhaseQuadTree::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  319. {
  320. JPH_PROFILE_FUNCTION();
  321. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  322. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  323. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  324. // Loop over all layers and test the ones that could hit
  325. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  326. {
  327. const QuadTree &tree = mLayers[l];
  328. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  329. {
  330. JPH_PROFILE(tree.GetName());
  331. tree.CastRay(inRay, ioCollector, inObjectLayerFilter, mTracking);
  332. if (ioCollector.ShouldEarlyOut())
  333. break;
  334. }
  335. }
  336. }
  337. void BroadPhaseQuadTree::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  338. {
  339. JPH_PROFILE_FUNCTION();
  340. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  341. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  342. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  343. // Loop over all layers and test the ones that could hit
  344. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  345. {
  346. const QuadTree &tree = mLayers[l];
  347. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  348. {
  349. JPH_PROFILE(tree.GetName());
  350. tree.CollideAABox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  351. if (ioCollector.ShouldEarlyOut())
  352. break;
  353. }
  354. }
  355. }
  356. void BroadPhaseQuadTree::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  357. {
  358. JPH_PROFILE_FUNCTION();
  359. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  360. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  361. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  362. // Loop over all layers and test the ones that could hit
  363. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  364. {
  365. const QuadTree &tree = mLayers[l];
  366. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  367. {
  368. JPH_PROFILE(tree.GetName());
  369. tree.CollideSphere(inCenter, inRadius, ioCollector, inObjectLayerFilter, mTracking);
  370. if (ioCollector.ShouldEarlyOut())
  371. break;
  372. }
  373. }
  374. }
  375. void BroadPhaseQuadTree::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  376. {
  377. JPH_PROFILE_FUNCTION();
  378. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  379. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  380. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  381. // Loop over all layers and test the ones that could hit
  382. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  383. {
  384. const QuadTree &tree = mLayers[l];
  385. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  386. {
  387. JPH_PROFILE(tree.GetName());
  388. tree.CollidePoint(inPoint, ioCollector, inObjectLayerFilter, mTracking);
  389. if (ioCollector.ShouldEarlyOut())
  390. break;
  391. }
  392. }
  393. }
  394. void BroadPhaseQuadTree::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  395. {
  396. JPH_PROFILE_FUNCTION();
  397. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  398. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  399. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  400. // Loop over all layers and test the ones that could hit
  401. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  402. {
  403. const QuadTree &tree = mLayers[l];
  404. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  405. {
  406. JPH_PROFILE(tree.GetName());
  407. tree.CollideOrientedBox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  408. if (ioCollector.ShouldEarlyOut())
  409. break;
  410. }
  411. }
  412. }
  413. void BroadPhaseQuadTree::CastAABoxNoLock(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  414. {
  415. JPH_PROFILE_FUNCTION();
  416. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  417. // Loop over all layers and test the ones that could hit
  418. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  419. {
  420. const QuadTree &tree = mLayers[l];
  421. if (tree.HasBodies() && inBroadPhaseLayerFilter.ShouldCollide(BroadPhaseLayer(l)))
  422. {
  423. JPH_PROFILE(tree.GetName());
  424. tree.CastAABox(inBox, ioCollector, inObjectLayerFilter, mTracking);
  425. if (ioCollector.ShouldEarlyOut())
  426. break;
  427. }
  428. }
  429. }
  430. void BroadPhaseQuadTree::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  431. {
  432. // Prevent this from running in parallel with node deletion in FrameSync(), see notes there
  433. shared_lock lock(mQueryLocks[mQueryLockIdx]);
  434. CastAABoxNoLock(inBox, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  435. }
  436. void BroadPhaseQuadTree::FindCollidingPairs(BodyID *ioActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, ObjectVsBroadPhaseLayerFilter inObjectVsBroadPhaseLayerFilter, ObjectLayerPairFilter inObjectLayerPairFilter, BodyPairCollector &ioPairCollector) const
  437. {
  438. JPH_PROFILE_FUNCTION();
  439. const BodyVector &bodies = mBodyManager->GetBodies();
  440. JPH_ASSERT(mMaxBodies == mBodyManager->GetMaxBodies());
  441. // Note that we don't take any locks at this point. We know that the tree is not going to be swapped or deleted while finding collision pairs due to the way the jobs are scheduled in the PhysicsSystem::Update.
  442. // Sort bodies on layer
  443. const Tracking *tracking = mTracking.data(); // C pointer or else sort is incredibly slow in debug mode
  444. sort(ioActiveBodies, ioActiveBodies + inNumActiveBodies, [tracking](BodyID inLHS, BodyID inRHS) { return tracking[inLHS.GetIndex()].mObjectLayer < tracking[inRHS.GetIndex()].mObjectLayer; });
  445. BodyID *b_start = ioActiveBodies, *b_end = ioActiveBodies + inNumActiveBodies;
  446. while (b_start < b_end)
  447. {
  448. // Get broadphase layer
  449. ObjectLayer object_layer = tracking[b_start->GetIndex()].mObjectLayer;
  450. JPH_ASSERT(object_layer != cObjectLayerInvalid);
  451. // Find first body with different layer
  452. BodyID *b_mid = upper_bound(b_start, b_end, object_layer, [tracking](ObjectLayer inLayer, BodyID inBodyID) { return inLayer < tracking[inBodyID.GetIndex()].mObjectLayer; });
  453. // Loop over all layers and test the ones that could hit
  454. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  455. {
  456. const QuadTree &tree = mLayers[l];
  457. if (tree.HasBodies() && inObjectVsBroadPhaseLayerFilter(object_layer, BroadPhaseLayer(l)))
  458. {
  459. JPH_PROFILE(tree.GetName());
  460. tree.FindCollidingPairs(bodies, b_start, int(b_mid - b_start), inSpeculativeContactDistance, ioPairCollector, inObjectLayerPairFilter);
  461. }
  462. }
  463. // Repeat
  464. b_start = b_mid;
  465. }
  466. }
  467. #if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
  468. void BroadPhaseQuadTree::SetBroadPhaseLayerToString(BroadPhaseLayerToString inBroadPhaseLayerToString)
  469. {
  470. // Set the name on the sub trees
  471. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  472. mLayers[l].SetName(inBroadPhaseLayerToString(BroadPhaseLayer(l)));
  473. }
  474. #endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED
  475. #ifdef JPH_TRACK_BROADPHASE_STATS
  476. void BroadPhaseQuadTree::ReportStats()
  477. {
  478. Trace("Query Type, Filter Description, Tree Name, Num Queries, Total Time (ms), Total Time Excl. Collector (ms), Nodes Visited, Bodies Visited, Hits Reported, Hits Reported vs Bodies Visited (%%), Hits Reported vs Nodes Visited");
  479. for (BroadPhaseLayer::Type l = 0; l < mNumLayers; ++l)
  480. mLayers[l].ReportStats();
  481. }
  482. #endif // JPH_TRACK_BROADPHASE_STATS
  483. } // JPH