QuadTree.cpp 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548
  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/Collision/SortReverseAndStore.h>
  9. #include <Physics/Body/BodyPair.h>
  10. #include <Physics/PhysicsLock.h>
  11. #include <Geometry/AABox4.h>
  12. #include <Geometry/RayAABox.h>
  13. #include <Geometry/OrientedBox.h>
  14. namespace JPH {
  15. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. // QuadTree::Node
  17. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  18. QuadTree::Node::Node()
  19. {
  20. // First reset bounds
  21. Vec4 val = Vec4::sReplicate(cLargeFloat);
  22. val.StoreFloat4((Float4 *)&mBoundsMinX);
  23. val.StoreFloat4((Float4 *)&mBoundsMinY);
  24. val.StoreFloat4((Float4 *)&mBoundsMinZ);
  25. val = Vec4::sReplicate(-cLargeFloat);
  26. val.StoreFloat4((Float4 *)&mBoundsMaxX);
  27. val.StoreFloat4((Float4 *)&mBoundsMaxY);
  28. val.StoreFloat4((Float4 *)&mBoundsMaxZ);
  29. // Reset child node ids
  30. mChildNodeID[0] = NodeID::sInvalid();
  31. mChildNodeID[1] = NodeID::sInvalid();
  32. mChildNodeID[2] = NodeID::sInvalid();
  33. mChildNodeID[3] = NodeID::sInvalid();
  34. }
  35. void QuadTree::Node::GetChildBounds(int inChildIndex, AABox &outBounds) const
  36. {
  37. // Read bounding box in order min -> max
  38. outBounds.mMin = Vec3(mBoundsMinX[inChildIndex], mBoundsMinY[inChildIndex], mBoundsMinZ[inChildIndex]);
  39. outBounds.mMax = Vec3(mBoundsMaxX[inChildIndex], mBoundsMaxY[inChildIndex], mBoundsMaxZ[inChildIndex]);
  40. }
  41. void QuadTree::Node::SetChildBounds(int inChildIndex, const AABox &inBounds)
  42. {
  43. // Set max first (this keeps the bounding box invalid for reading threads)
  44. mBoundsMaxZ[inChildIndex] = inBounds.mMax.GetZ();
  45. mBoundsMaxY[inChildIndex] = inBounds.mMax.GetY();
  46. mBoundsMaxX[inChildIndex] = inBounds.mMax.GetX();
  47. // Then set min (and make box valid)
  48. mBoundsMinZ[inChildIndex] = inBounds.mMin.GetZ();
  49. mBoundsMinY[inChildIndex] = inBounds.mMin.GetY();
  50. mBoundsMinX[inChildIndex] = inBounds.mMin.GetX(); // Min X becomes valid last
  51. }
  52. void QuadTree::Node::InvalidateChildBounds(int inChildIndex)
  53. {
  54. // First we make the box invalid by setting the min to cLargeFloat
  55. mBoundsMinX[inChildIndex] = cLargeFloat; // Min X becomes invalid first
  56. mBoundsMinY[inChildIndex] = cLargeFloat;
  57. mBoundsMinZ[inChildIndex] = cLargeFloat;
  58. // Then we reset the max values too
  59. mBoundsMaxX[inChildIndex] = -cLargeFloat;
  60. mBoundsMaxY[inChildIndex] = -cLargeFloat;
  61. mBoundsMaxZ[inChildIndex] = -cLargeFloat;
  62. }
  63. void QuadTree::Node::GetNodeBounds(AABox &outBounds) const
  64. {
  65. // Get first child bounds
  66. GetChildBounds(0, outBounds);
  67. // Encapsulate other child bounds
  68. for (int child_idx = 1; child_idx < 4; ++child_idx)
  69. {
  70. AABox tmp;
  71. GetChildBounds(child_idx, tmp);
  72. outBounds.Encapsulate(tmp);
  73. }
  74. }
  75. bool QuadTree::Node::EncapsulateChildBounds(int inChildIndex, const AABox &inBounds)
  76. {
  77. bool changed = AtomicMin(mBoundsMinX[inChildIndex], inBounds.mMin.GetX());
  78. changed |= AtomicMin(mBoundsMinY[inChildIndex], inBounds.mMin.GetY());
  79. changed |= AtomicMin(mBoundsMinZ[inChildIndex], inBounds.mMin.GetZ());
  80. changed |= AtomicMax(mBoundsMaxX[inChildIndex], inBounds.mMax.GetX());
  81. changed |= AtomicMax(mBoundsMaxY[inChildIndex], inBounds.mMax.GetY());
  82. changed |= AtomicMax(mBoundsMaxZ[inChildIndex], inBounds.mMax.GetZ());
  83. return changed;
  84. }
  85. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. // QuadTree
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. const float QuadTree::cLargeFloat = 1.0e30f;
  89. const AABox QuadTree::cInvalidBounds(Vec3::sReplicate(cLargeFloat), Vec3::sReplicate(-cLargeFloat));
  90. void QuadTree::GetBodyLocation(const TrackingVector &inTracking, BodyID inBodyID, uint32 &outNodeIdx, uint32 &outChildIdx) const
  91. {
  92. uint32 body_location = inTracking[inBodyID.GetIndex()].mBodyLocation;
  93. JPH_ASSERT(body_location != Tracking::cInvalidBodyLocation);
  94. outNodeIdx = body_location & 0x3fffffff;
  95. outChildIdx = body_location >> 30;
  96. JPH_ASSERT(mAllocator->Get(outNodeIdx).mChildNodeID[outChildIdx] == inBodyID, "Make sure that the body is in the node where it should be");
  97. }
  98. void QuadTree::SetBodyLocation(TrackingVector &ioTracking, BodyID inBodyID, uint32 inNodeIdx, uint32 inChildIdx) const
  99. {
  100. JPH_ASSERT(inNodeIdx <= 0x3fffffff);
  101. JPH_ASSERT(inChildIdx < 4);
  102. JPH_ASSERT(mAllocator->Get(inNodeIdx).mChildNodeID[inChildIdx] == inBodyID, "Make sure that the body is in the node where it should be");
  103. ioTracking[inBodyID.GetIndex()].mBodyLocation = inNodeIdx + (inChildIdx << 30);
  104. #ifdef JPH_ENABLE_ASSERTS
  105. uint32 v1, v2;
  106. GetBodyLocation(ioTracking, inBodyID, v1, v2);
  107. JPH_ASSERT(v1 == inNodeIdx);
  108. JPH_ASSERT(v2 == inChildIdx);
  109. #endif
  110. }
  111. void QuadTree::InvalidateBodyLocation(TrackingVector &ioTracking, BodyID inBodyID)
  112. {
  113. ioTracking[inBodyID.GetIndex()].mBodyLocation = Tracking::cInvalidBodyLocation;
  114. }
  115. QuadTree::~QuadTree()
  116. {
  117. // Get rid of any nodes that are still to be freed
  118. DiscardOldTree();
  119. // Get the current root node
  120. RootNode &root_node = GetCurrentRoot();
  121. // Collect all bodies
  122. Allocator::Batch free_batch;
  123. NodeID node_stack[cStackSize];
  124. node_stack[0] = root_node.GetNodeID();
  125. JPH_ASSERT(node_stack[0].IsValid());
  126. if (node_stack[0].IsNode())
  127. {
  128. int top = 0;
  129. do
  130. {
  131. // Process node
  132. NodeID node_id = node_stack[top];
  133. JPH_ASSERT(!node_id.IsBody());
  134. uint32 node_idx = node_id.GetNodeIndex();
  135. const Node &node = mAllocator->Get(node_idx);
  136. // Recurse and get all child nodes
  137. for (int i = 0; i < 4; ++i)
  138. {
  139. NodeID child_node_id = node.mChildNodeID[i];
  140. if (child_node_id.IsValid() && child_node_id.IsNode())
  141. {
  142. JPH_ASSERT(top < cStackSize);
  143. node_stack[top] = child_node_id;
  144. top++;
  145. }
  146. }
  147. // Mark node to be freed
  148. mAllocator->AddObjectToBatch(free_batch, node_idx);
  149. --top;
  150. }
  151. while (top >= 0);
  152. }
  153. // Now free all nodes
  154. mAllocator->DestructObjectBatch(free_batch);
  155. }
  156. uint32 QuadTree::AllocateNode()
  157. {
  158. uint32 index = mAllocator->ConstructObject();
  159. if (index == Allocator::cInvalidObjectIndex)
  160. {
  161. Trace("QuadTree: Out of nodes!");
  162. JPH_CRASH;
  163. }
  164. return index;
  165. }
  166. void QuadTree::Init(Allocator &inAllocator)
  167. {
  168. // Store allocator
  169. mAllocator = &inAllocator;
  170. // Allocate root node
  171. mRootNode[mRootNodeIndex].mIndex = AllocateNode();
  172. }
  173. void QuadTree::DiscardOldTree()
  174. {
  175. // Check if there is an old tree
  176. RootNode &old_root_node = mRootNode[mRootNodeIndex ^ 1];
  177. if (old_root_node.mIndex != cInvalidNodeIndex)
  178. {
  179. // Clear the root
  180. old_root_node.mIndex = cInvalidNodeIndex;
  181. // Now free all old nodes
  182. mAllocator->DestructObjectBatch(mFreeNodeBatch);
  183. // Clear the batch
  184. mFreeNodeBatch = Allocator::Batch();
  185. }
  186. }
  187. void QuadTree::UpdatePrepare(const BodyVector &inBodies, TrackingVector &ioTracking, UpdateState &outUpdateState)
  188. {
  189. #ifdef JPH_ENABLE_ASSERTS
  190. // We only read positions
  191. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::Read);
  192. #endif
  193. // Assert we have no nodes pending deletion, this means DiscardOldTree wasn't called yet
  194. JPH_ASSERT(mFreeNodeBatch.mNumObjects == 0);
  195. // Mark tree non-dirty
  196. mIsDirty = false;
  197. // Get the current root node
  198. RootNode &root_node = GetCurrentRoot();
  199. // Assert sane data
  200. #ifdef _DEBUG
  201. ValidateTree(inBodies, ioTracking, root_node.mIndex, mNumBodies);
  202. #endif
  203. // Create space for all body ID's
  204. NodeID *node_ids = new NodeID [mNumBodies];
  205. NodeID *cur_node_id = node_ids;
  206. // Collect all bodies
  207. NodeID node_stack[cStackSize];
  208. node_stack[0] = root_node.GetNodeID();
  209. JPH_ASSERT(node_stack[0].IsValid());
  210. int top = 0;
  211. do
  212. {
  213. // Check if node is a body
  214. NodeID node_id = node_stack[top];
  215. if (node_id.IsBody())
  216. {
  217. // Validate that we're still in the right layer
  218. #ifdef JPH_ENABLE_ASSERTS
  219. uint32 body_index = node_id.GetBodyID().GetIndex();
  220. JPH_ASSERT(ioTracking[body_index].mObjectLayer == inBodies[body_index]->GetObjectLayer());
  221. #endif
  222. // Store body
  223. *cur_node_id = node_id;
  224. ++cur_node_id;
  225. }
  226. else
  227. {
  228. // Process normal node
  229. uint32 node_idx = node_id.GetNodeIndex();
  230. const Node &node = mAllocator->Get(node_idx);
  231. if (!node.mIsChanged)
  232. {
  233. // Node is unchanged, treat it as a whole
  234. *cur_node_id = node_id;
  235. ++cur_node_id;
  236. }
  237. else
  238. {
  239. // Node is changed, recurse and get all children
  240. for (int i = 0; i < 4; ++i)
  241. {
  242. NodeID child_node_id = node.mChildNodeID[i];
  243. if (child_node_id.IsValid())
  244. {
  245. JPH_ASSERT(top < cStackSize);
  246. node_stack[top] = child_node_id;
  247. top++;
  248. }
  249. }
  250. // Mark node to be freed
  251. mAllocator->AddObjectToBatch(mFreeNodeBatch, node_idx);
  252. }
  253. }
  254. --top;
  255. }
  256. while (top >= 0);
  257. // Check that our book keeping matches
  258. uint32 num_node_ids = uint32(cur_node_id - node_ids);
  259. JPH_ASSERT(num_node_ids <= mNumBodies);
  260. // This will be the new root node id
  261. NodeID root_node_id;
  262. if (num_node_ids > 0)
  263. {
  264. // Build new tree
  265. AABox root_bounds;
  266. root_node_id = BuildTree(inBodies, ioTracking, node_ids, num_node_ids, root_bounds);
  267. if (root_node_id.IsBody())
  268. {
  269. // For a single body we need to allocate a new root node
  270. uint32 root_idx = AllocateNode();
  271. Node &root = mAllocator->Get(root_idx);
  272. root.SetChildBounds(0, root_bounds);
  273. root.mChildNodeID[0] = root_node_id;
  274. SetBodyLocation(ioTracking, root_node_id.GetBodyID(), root_idx, 0);
  275. root_node_id = NodeID::sFromNodeIndex(root_idx);
  276. }
  277. }
  278. else
  279. {
  280. // Empty tree, create root node
  281. uint32 root_idx = AllocateNode();
  282. root_node_id = NodeID::sFromNodeIndex(root_idx);
  283. }
  284. // Delete temporary data
  285. delete [] node_ids;
  286. outUpdateState.mRootNodeID = root_node_id;
  287. }
  288. void QuadTree::UpdateFinalize([[maybe_unused]] const BodyVector &inBodies, [[maybe_unused]] const TrackingVector &inTracking, const UpdateState &inUpdateState)
  289. {
  290. // Tree building is complete, now we switch the old with the new tree
  291. uint32 new_root_idx = mRootNodeIndex ^ 1;
  292. RootNode &new_root_node = mRootNode[new_root_idx];
  293. {
  294. // Note: We don't need to lock here as the old tree stays available so any queries
  295. // that use it can continue using it until DiscardOldTree is called. This slot
  296. // should be empty and unused at this moment.
  297. JPH_ASSERT(new_root_node.mIndex == cInvalidNodeIndex);
  298. new_root_node.mIndex = inUpdateState.mRootNodeID.GetNodeIndex();
  299. }
  300. // All queries that start from now on will use this new tree
  301. mRootNodeIndex = new_root_idx;
  302. #ifdef _DEBUG
  303. ValidateTree(inBodies, inTracking, new_root_node.mIndex, mNumBodies);
  304. #endif
  305. }
  306. void QuadTree::sPartition(NodeID *ioNodeIDs, Vec3 *ioNodeCenters, int inNumber, int &outMidPoint)
  307. {
  308. // Handle trivial case
  309. if (inNumber <= 4)
  310. {
  311. outMidPoint = inNumber / 2;
  312. return;
  313. }
  314. // Calculate bounding box of box centers
  315. Vec3 center_min = Vec3::sReplicate(cLargeFloat);
  316. Vec3 center_max = Vec3::sReplicate(-cLargeFloat);
  317. for (Vec3 *c = ioNodeCenters, *c_end = ioNodeCenters + inNumber; c < c_end; ++c)
  318. {
  319. Vec3 center = *c;
  320. center_min = Vec3::sMin(center_min, center);
  321. center_max = Vec3::sMax(center_max, center);
  322. }
  323. // Calculate split plane
  324. int dimension = (center_max - center_min).GetHighestComponentIndex();
  325. float split = 0.5f * (center_min + center_max)[dimension];
  326. // Divide bodies
  327. int start = 0, end = inNumber;
  328. while (start < end)
  329. {
  330. // Search for first element that is on the right hand side of the split plane
  331. while (start < end && ioNodeCenters[start][dimension] < split)
  332. ++start;
  333. // Search for the first element that is on the left hand side of the split plane
  334. while (start < end && ioNodeCenters[end - 1][dimension] >= split)
  335. --end;
  336. if (start < end)
  337. {
  338. // Swap the two elements
  339. swap(ioNodeIDs[start], ioNodeIDs[end - 1]);
  340. swap(ioNodeCenters[start], ioNodeCenters[end - 1]);
  341. ++start;
  342. --end;
  343. }
  344. }
  345. JPH_ASSERT(start == end);
  346. if (start > 0 && start < inNumber)
  347. {
  348. // Success!
  349. outMidPoint = start;
  350. }
  351. else
  352. {
  353. // Failed to divide bodies
  354. outMidPoint = inNumber / 2;
  355. }
  356. }
  357. void QuadTree::sPartition4(NodeID *ioNodeIDs, Vec3 *ioNodeCenters, int inBegin, int inEnd, int *outSplit)
  358. {
  359. NodeID *node_ids = ioNodeIDs + inBegin;
  360. Vec3 *node_centers = ioNodeCenters + inBegin;
  361. int number = inEnd - inBegin;
  362. // Partition entire range
  363. sPartition(node_ids, node_centers, number, outSplit[2]);
  364. // Partition lower half
  365. sPartition(node_ids, node_centers, outSplit[2], outSplit[1]);
  366. // Partition upper half
  367. sPartition(node_ids + outSplit[2], node_centers + outSplit[2], number - outSplit[2], outSplit[3]);
  368. // Convert to proper range
  369. outSplit[0] = inBegin;
  370. outSplit[1] += inBegin;
  371. outSplit[2] += inBegin;
  372. outSplit[3] += outSplit[2];
  373. outSplit[4] = inEnd;
  374. }
  375. AABox QuadTree::GetNodeOrBodyBounds(const BodyVector &inBodies, NodeID inNodeID) const
  376. {
  377. if (inNodeID.IsNode())
  378. {
  379. // It is a node
  380. uint32 node_idx = inNodeID.GetNodeIndex();
  381. const Node &node = mAllocator->Get(node_idx);
  382. AABox bounds;
  383. node.GetNodeBounds(bounds);
  384. return bounds;
  385. }
  386. else
  387. {
  388. // It is a body
  389. return inBodies[inNodeID.GetBodyID().GetIndex()]->GetWorldSpaceBounds();
  390. }
  391. }
  392. QuadTree::NodeID QuadTree::BuildTree(const BodyVector &inBodies, TrackingVector &ioTracking, NodeID *ioNodeIDs, int inNumber, AABox &outBounds)
  393. {
  394. // Trivial case: No bodies in tree
  395. if (inNumber == 0)
  396. {
  397. outBounds = cInvalidBounds;
  398. return NodeID::sInvalid();
  399. }
  400. // Trivial case: When we have 1 body or node, return it
  401. if (inNumber == 1)
  402. {
  403. if (ioNodeIDs->IsNode())
  404. {
  405. // When returning an existing node as root, ensure that no parent has been set
  406. Node &node = mAllocator->Get(ioNodeIDs->GetNodeIndex());
  407. node.mParentNodeIndex = cInvalidNodeIndex;
  408. }
  409. outBounds = GetNodeOrBodyBounds(inBodies, *ioNodeIDs);
  410. return *ioNodeIDs;
  411. }
  412. // Calculate centers of all bodies that are to be inserted
  413. Vec3 *centers = new Vec3 [inNumber];
  414. JPH_ASSERT(IsAligned(centers, 16));
  415. Vec3 *c = centers;
  416. for (NodeID *n = ioNodeIDs, *n_end = ioNodeIDs + inNumber; n < n_end; ++n, ++c)
  417. *c = GetNodeOrBodyBounds(inBodies, *n).GetCenter();
  418. // The algorithm is a recursive tree build, but to avoid the call overhead we keep track of a stack here
  419. struct StackEntry
  420. {
  421. uint32 mNodeIdx; // Node index of node that is generated
  422. int mChildIdx; // Index of child that we're currently processing
  423. int mSplit[5]; // Indices where the node ID's have been split to form 4 partitions
  424. Vec3 mNodeBoundsMin; // Bounding box of this node, accumulated while iterating over children
  425. Vec3 mNodeBoundsMax;
  426. };
  427. static_assert(sizeof(StackEntry) == 64);
  428. StackEntry stack[cStackSize / 4]; // We don't process 4 at a time in this loop but 1, so the stack can be 4x as small
  429. int top = 0;
  430. // Create root node
  431. stack[0].mNodeIdx = AllocateNode();
  432. stack[0].mChildIdx = -1;
  433. stack[0].mNodeBoundsMin = Vec3::sReplicate(cLargeFloat);
  434. stack[0].mNodeBoundsMax = Vec3::sReplicate(-cLargeFloat);
  435. sPartition4(ioNodeIDs, centers, 0, inNumber, stack[0].mSplit);
  436. for (;;)
  437. {
  438. StackEntry &cur_stack = stack[top];
  439. // Next child
  440. cur_stack.mChildIdx++;
  441. // Check if all children processed
  442. if (cur_stack.mChildIdx >= 4)
  443. {
  444. // Terminate if there's nothing left to pop
  445. if (top <= 0)
  446. break;
  447. // Add our bounds to our parents bounds
  448. StackEntry &prev_stack = stack[top - 1];
  449. prev_stack.mNodeBoundsMin = Vec3::sMin(prev_stack.mNodeBoundsMin, cur_stack.mNodeBoundsMin);
  450. prev_stack.mNodeBoundsMax = Vec3::sMax(prev_stack.mNodeBoundsMax, cur_stack.mNodeBoundsMax);
  451. // Store parent node
  452. Node &node = mAllocator->Get(cur_stack.mNodeIdx);
  453. node.mParentNodeIndex = prev_stack.mNodeIdx;
  454. // Store this node's properties in the parent node
  455. Node &parent_node = mAllocator->Get(prev_stack.mNodeIdx);
  456. parent_node.mChildNodeID[prev_stack.mChildIdx] = NodeID::sFromNodeIndex(cur_stack.mNodeIdx);
  457. parent_node.SetChildBounds(prev_stack.mChildIdx, AABox(cur_stack.mNodeBoundsMin, cur_stack.mNodeBoundsMax));
  458. // Pop entry from stack
  459. --top;
  460. }
  461. else
  462. {
  463. // Get low and high index to bodies to process
  464. int low = cur_stack.mSplit[cur_stack.mChildIdx];
  465. int high = cur_stack.mSplit[cur_stack.mChildIdx + 1];
  466. int num_bodies = high - low;
  467. if (num_bodies == 1)
  468. {
  469. // Get body info
  470. NodeID child_node_id = ioNodeIDs[low];
  471. AABox bounds = GetNodeOrBodyBounds(inBodies, child_node_id);
  472. // Update node
  473. Node &node = mAllocator->Get(cur_stack.mNodeIdx);
  474. node.mChildNodeID[cur_stack.mChildIdx] = child_node_id;
  475. node.SetChildBounds(cur_stack.mChildIdx, bounds);
  476. if (child_node_id.IsNode())
  477. {
  478. // Update parent for this node
  479. Node &child_node = mAllocator->Get(child_node_id.GetNodeIndex());
  480. child_node.mParentNodeIndex = cur_stack.mNodeIdx;
  481. }
  482. else
  483. {
  484. // Set location in tracking
  485. SetBodyLocation(ioTracking, child_node_id.GetBodyID(), cur_stack.mNodeIdx, cur_stack.mChildIdx);
  486. }
  487. // Encapsulate bounding box in parent
  488. cur_stack.mNodeBoundsMin = Vec3::sMin(cur_stack.mNodeBoundsMin, bounds.mMin);
  489. cur_stack.mNodeBoundsMax = Vec3::sMax(cur_stack.mNodeBoundsMax, bounds.mMax);
  490. }
  491. else if (num_bodies > 1)
  492. {
  493. // Allocate new node
  494. StackEntry &new_stack = stack[++top];
  495. JPH_ASSERT(top < cStackSize / 4);
  496. new_stack.mNodeIdx = AllocateNode();
  497. new_stack.mChildIdx = -1;
  498. new_stack.mNodeBoundsMin = Vec3::sReplicate(cLargeFloat);
  499. new_stack.mNodeBoundsMax = Vec3::sReplicate(-cLargeFloat);
  500. sPartition4(ioNodeIDs, centers, low, high, new_stack.mSplit);
  501. }
  502. }
  503. }
  504. // Delete temporary data
  505. delete [] centers;
  506. // Store bounding box of root
  507. outBounds.mMin = stack[0].mNodeBoundsMin;
  508. outBounds.mMax = stack[0].mNodeBoundsMax;
  509. // Return root
  510. return NodeID::sFromNodeIndex(stack[0].mNodeIdx);
  511. }
  512. void QuadTree::MarkNodeAndParentsChanged(uint32 inNodeIndex)
  513. {
  514. uint32 node_idx = inNodeIndex;
  515. do
  516. {
  517. // If node has changed, parent will be too
  518. Node &node = mAllocator->Get(node_idx);
  519. if (node.mIsChanged)
  520. break;
  521. // Mark node as changed
  522. node.mIsChanged = true;
  523. // Get our parent
  524. node_idx = node.mParentNodeIndex;
  525. }
  526. while (node_idx != cInvalidNodeIndex);
  527. }
  528. void QuadTree::WidenAndMarkNodeAndParentsChanged(uint32 inNodeIndex, const AABox &inNewBounds)
  529. {
  530. uint32 node_idx = inNodeIndex;
  531. for (;;)
  532. {
  533. // Mark node as changed
  534. Node &node = mAllocator->Get(node_idx);
  535. node.mIsChanged = true;
  536. // Get our parent
  537. uint32 parent_idx = node.mParentNodeIndex;
  538. if (parent_idx == cInvalidNodeIndex)
  539. break;
  540. // Find which child of the parent we're in
  541. Node &parent_node = mAllocator->Get(parent_idx);
  542. NodeID node_id = NodeID::sFromNodeIndex(node_idx);
  543. int child_idx = -1;
  544. for (int i = 0; i < 4; ++i)
  545. if (parent_node.mChildNodeID[i] == node_id)
  546. {
  547. // Found one, set the node index and child index and update the bounding box too
  548. child_idx = i;
  549. break;
  550. }
  551. JPH_ASSERT(child_idx != -1, "Nodes don't get removed from the tree, we must have found it");
  552. // To avoid any race conditions with other threads we only enlarge bounding boxes
  553. if (!parent_node.EncapsulateChildBounds(child_idx, inNewBounds))
  554. {
  555. // No changes to bounding box, only marking as changed remains to be done
  556. if (!parent_node.mIsChanged)
  557. MarkNodeAndParentsChanged(parent_idx);
  558. break;
  559. }
  560. // Update node index
  561. node_idx = parent_idx;
  562. }
  563. }
  564. bool QuadTree::TryInsertLeaf(TrackingVector &ioTracking, int inNodeIndex, NodeID inLeafID, const AABox &inLeafBounds, int inLeafNumBodies)
  565. {
  566. // Tentively assign the node as parent
  567. bool leaf_is_node = inLeafID.IsNode();
  568. if (leaf_is_node)
  569. {
  570. uint32 leaf_idx = inLeafID.GetNodeIndex();
  571. mAllocator->Get(leaf_idx).mParentNodeIndex = inNodeIndex;
  572. }
  573. // Fetch node that we're adding to
  574. Node &node = mAllocator->Get(inNodeIndex);
  575. // Find an empty child
  576. for (uint32 child_idx = 0; child_idx < 4; ++child_idx)
  577. if (!node.mChildNodeID[child_idx].IsValid())
  578. {
  579. // Check if we can claim it
  580. if (node.mChildNodeID[child_idx].CompareExchange(NodeID::sInvalid(), inLeafID))
  581. {
  582. // We managed to add it to the node
  583. // If leaf was a body, we need to update its bookkeeping
  584. if (!leaf_is_node)
  585. SetBodyLocation(ioTracking, inLeafID.GetBodyID(), inNodeIndex, child_idx);
  586. // Now set the bounding box making the child valid for queries
  587. node.SetChildBounds(child_idx, inLeafBounds);
  588. // Widen the bounds for our parents too
  589. WidenAndMarkNodeAndParentsChanged(inNodeIndex, inLeafBounds);
  590. // Update body counter
  591. mNumBodies += inLeafNumBodies;
  592. // And we're done
  593. return true;
  594. }
  595. }
  596. return false;
  597. }
  598. bool QuadTree::TryCreateNewRoot(TrackingVector &ioTracking, atomic<uint32> &ioRootNodeIndex, NodeID inLeafID, const AABox &inLeafBounds, int inLeafNumBodies)
  599. {
  600. // Fetch old root
  601. uint32 root_idx = ioRootNodeIndex;
  602. Node &root = mAllocator->Get(root_idx);
  603. // Create new root
  604. uint32 new_root_idx = AllocateNode();
  605. Node &new_root = mAllocator->Get(new_root_idx);
  606. // Mark this new root as changed as we're not creating a very efficient tree at this point
  607. new_root.mIsChanged = true;
  608. // First child is current root, note that since the tree may be modified concurrently we cannot assume that the bounds of our child will be correct so we set a very large bounding box
  609. new_root.mChildNodeID[0] = NodeID::sFromNodeIndex(root_idx);
  610. new_root.SetChildBounds(0, AABox(Vec3::sReplicate(-cLargeFloat), Vec3::sReplicate(cLargeFloat)));
  611. // Second child is new leaf
  612. new_root.mChildNodeID[1] = inLeafID;
  613. new_root.SetChildBounds(1, inLeafBounds);
  614. // Tentatively assign new root as parent
  615. bool leaf_is_node = inLeafID.IsNode();
  616. if (leaf_is_node)
  617. {
  618. uint32 leaf_idx = inLeafID.GetNodeIndex();
  619. mAllocator->Get(leaf_idx).mParentNodeIndex = new_root_idx;
  620. }
  621. // Try to swap it
  622. if (ioRootNodeIndex.compare_exchange_strong(root_idx, new_root_idx))
  623. {
  624. // We managed to set the new root
  625. // If leaf was a body, we need to update its bookkeeping
  626. if (!leaf_is_node)
  627. SetBodyLocation(ioTracking, inLeafID.GetBodyID(), new_root_idx, 1);
  628. // Store parent node for old root
  629. root.mParentNodeIndex = new_root_idx;
  630. // Update body counter
  631. mNumBodies += inLeafNumBodies;
  632. // And we're done
  633. return true;
  634. }
  635. // Failed to swap, someone else must have created a new root, try again
  636. mAllocator->DestructObject(new_root_idx);
  637. return false;
  638. }
  639. void QuadTree::AddBodiesPrepare(const BodyVector &inBodies, TrackingVector &ioTracking, BodyID *ioBodyIDs, int inNumber, AddState &outState)
  640. {
  641. // Assert sane input
  642. JPH_ASSERT(ioBodyIDs != nullptr);
  643. JPH_ASSERT(inNumber > 0);
  644. #ifdef JPH_ENABLE_ASSERTS
  645. // Below we just cast the body ID's to node ID's, check here that that is valid
  646. for (const BodyID *b = ioBodyIDs, *b_end = ioBodyIDs + inNumber; b < b_end; ++b)
  647. NodeID::sFromBodyID(*b);
  648. #endif
  649. // Build subtree for the new bodies
  650. outState.mLeafID = BuildTree(inBodies, ioTracking, (NodeID *)ioBodyIDs, inNumber, outState.mLeafBounds);
  651. #ifdef _DEBUG
  652. if (outState.mLeafID.IsNode())
  653. ValidateTree(inBodies, ioTracking, outState.mLeafID.GetNodeIndex(), inNumber);
  654. #endif
  655. }
  656. void QuadTree::AddBodiesFinalize(TrackingVector &ioTracking, int inNumberBodies, const AddState &inState)
  657. {
  658. // Assert sane input
  659. JPH_ASSERT(inNumberBodies > 0);
  660. // Mark tree dirty
  661. mIsDirty = true;
  662. // Get the current root node
  663. RootNode &root_node = GetCurrentRoot();
  664. for (;;)
  665. {
  666. // Check if we can insert the body in the root
  667. if (TryInsertLeaf(ioTracking, root_node.mIndex, inState.mLeafID, inState.mLeafBounds, inNumberBodies))
  668. return;
  669. // Check if we can create a new root
  670. if (TryCreateNewRoot(ioTracking, root_node.mIndex, inState.mLeafID, inState.mLeafBounds, inNumberBodies))
  671. return;
  672. }
  673. }
  674. void QuadTree::AddBodiesAbort(TrackingVector &ioTracking, const AddState &inState)
  675. {
  676. // Collect all bodies
  677. Allocator::Batch free_batch;
  678. NodeID node_stack[cStackSize];
  679. node_stack[0] = inState.mLeafID;
  680. JPH_ASSERT(node_stack[0].IsValid());
  681. int top = 0;
  682. do
  683. {
  684. // Check if node is a body
  685. NodeID child_node_id = node_stack[top];
  686. if (child_node_id.IsBody())
  687. {
  688. // Reset location of body
  689. InvalidateBodyLocation(ioTracking, child_node_id.GetBodyID());
  690. }
  691. else
  692. {
  693. // Process normal node
  694. uint32 node_idx = child_node_id.GetNodeIndex();
  695. const Node &node = mAllocator->Get(node_idx);
  696. for (int i = 0; i < 4; ++i)
  697. {
  698. NodeID sub_child_node_id = node.mChildNodeID[i];
  699. if (sub_child_node_id.IsValid())
  700. {
  701. JPH_ASSERT(top < cStackSize);
  702. node_stack[top] = sub_child_node_id;
  703. top++;
  704. }
  705. }
  706. // Mark it to be freed
  707. mAllocator->AddObjectToBatch(free_batch, node_idx);
  708. }
  709. --top;
  710. }
  711. while (top >= 0);
  712. // Now free all nodes as a single batch
  713. mAllocator->DestructObjectBatch(free_batch);
  714. }
  715. void QuadTree::RemoveBodies([[maybe_unused]] const BodyVector &inBodies, TrackingVector &ioTracking, BodyID *ioBodyIDs, int inNumber)
  716. {
  717. // Assert sane input
  718. JPH_ASSERT(ioBodyIDs != nullptr);
  719. JPH_ASSERT(inNumber > 0);
  720. // Mark tree dirty
  721. mIsDirty = true;
  722. for (BodyID *cur = ioBodyIDs, *end = ioBodyIDs + inNumber; cur < end; ++cur)
  723. {
  724. // Check if BodyID is correct
  725. JPH_ASSERT(inBodies[cur->GetIndex()]->GetID() == *cur, "Provided BodyID doesn't match BodyID in body manager");
  726. // Get location of body
  727. uint32 node_idx, child_idx;
  728. GetBodyLocation(ioTracking, *cur, node_idx, child_idx);
  729. // First we reset our internal bookkeeping
  730. InvalidateBodyLocation(ioTracking, *cur);
  731. // Then we make the bounding box invalid, no queries can find this node anymore
  732. Node &node = mAllocator->Get(node_idx);
  733. node.InvalidateChildBounds(child_idx);
  734. // Finally we reset the child id, this makes the node available for adds again
  735. node.mChildNodeID[child_idx] = NodeID::sInvalid();
  736. // We don't need to bubble up our bounding box changes to our parents since we never make volumes smaller, only bigger
  737. // But we do need to mark the nodes as changed so that the tree can be rebuilt
  738. MarkNodeAndParentsChanged(node_idx);
  739. }
  740. mNumBodies -= inNumber;
  741. }
  742. void QuadTree::NotifyBodiesAABBChanged(const BodyVector &inBodies, const TrackingVector &inTracking, BodyID *ioBodyIDs, int inNumber)
  743. {
  744. // Assert sane input
  745. JPH_ASSERT(ioBodyIDs != nullptr);
  746. JPH_ASSERT(inNumber > 0);
  747. for (BodyID *cur = ioBodyIDs, *end = ioBodyIDs + inNumber; cur < end; ++cur)
  748. {
  749. // Check if BodyID is correct
  750. const Body *body = inBodies[cur->GetIndex()];
  751. JPH_ASSERT(body->GetID() == *cur, "Provided BodyID doesn't match BodyID in body manager");
  752. // Get the new bounding box
  753. const AABox &new_bounds = body->GetWorldSpaceBounds();
  754. // Get location of body
  755. uint32 node_idx, child_idx;
  756. GetBodyLocation(inTracking, *cur, node_idx, child_idx);
  757. // Widen bounds for node
  758. Node &node = mAllocator->Get(node_idx);
  759. if (node.EncapsulateChildBounds(child_idx, new_bounds))
  760. {
  761. // Mark tree dirty
  762. mIsDirty = true;
  763. // If bounds changed, widen the bounds for our parents too
  764. WidenAndMarkNodeAndParentsChanged(node_idx, new_bounds);
  765. }
  766. }
  767. }
  768. template <class Visitor>
  769. JPH_INLINE void QuadTree::WalkTree(const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking, Visitor &ioVisitor JPH_IF_TRACK_BROADPHASE_STATS(, LayerToStats &ioStats)) const
  770. {
  771. // Get the root
  772. const RootNode &root_node = GetCurrentRoot();
  773. #ifdef JPH_TRACK_BROADPHASE_STATS
  774. // Start tracking stats
  775. int bodies_visited = 0;
  776. int hits_collected = 0;
  777. int nodes_visited = 0;
  778. uint64 collector_ticks = 0;
  779. uint64 start = GetProcessorTickCount();
  780. #endif // JPH_TRACK_BROADPHASE_STATS
  781. NodeID node_stack[cStackSize];
  782. node_stack[0] = root_node.GetNodeID();
  783. int top = 0;
  784. do
  785. {
  786. // Check if node is a body
  787. NodeID child_node_id = node_stack[top];
  788. if (child_node_id.IsBody())
  789. {
  790. // Track amount of bodies visited
  791. JPH_IF_TRACK_BROADPHASE_STATS(++bodies_visited;)
  792. BodyID body_id = child_node_id.GetBodyID();
  793. ObjectLayer object_layer = inTracking[body_id.GetIndex()].mObjectLayer; // We're not taking a lock on the body, so it may be in the process of being removed so check if the object layer is invalid
  794. if (object_layer != cObjectLayerInvalid && inObjectLayerFilter.ShouldCollide(object_layer))
  795. {
  796. JPH_PROFILE("VisitBody");
  797. // Track amount of hits
  798. JPH_IF_TRACK_BROADPHASE_STATS(++hits_collected;)
  799. // Start track time the collector takes
  800. JPH_IF_TRACK_BROADPHASE_STATS(uint64 collector_start = GetProcessorTickCount();)
  801. // We found a body we collide with, call our visitor
  802. ioVisitor.VisitBody(body_id, top);
  803. // End track time the collector takes
  804. JPH_IF_TRACK_BROADPHASE_STATS(collector_ticks += GetProcessorTickCount() - collector_start;)
  805. // Check if we're done
  806. if (ioVisitor.ShouldAbort())
  807. break;
  808. }
  809. }
  810. else if (child_node_id.IsValid())
  811. {
  812. JPH_IF_TRACK_BROADPHASE_STATS(++nodes_visited;)
  813. // Check if stack can hold more nodes
  814. if (top + 4 < cStackSize)
  815. {
  816. // Process normal node
  817. const Node &node = mAllocator->Get(child_node_id.GetNodeIndex());
  818. JPH_ASSERT(IsAligned(&node, JPH_CACHE_LINE_SIZE));
  819. // Load bounds of 4 children
  820. Vec4 bounds_minx = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinX);
  821. Vec4 bounds_miny = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinY);
  822. Vec4 bounds_minz = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinZ);
  823. Vec4 bounds_maxx = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxX);
  824. Vec4 bounds_maxy = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxY);
  825. Vec4 bounds_maxz = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxZ);
  826. // Load ids for 4 children
  827. UVec4 child_ids = UVec4::sLoadInt4Aligned((const uint32 *)&node.mChildNodeID[0]);
  828. // Check which sub nodes to visit
  829. int num_results = ioVisitor.VisitNodes(bounds_minx, bounds_miny, bounds_minz, bounds_maxx, bounds_maxy, bounds_maxz, child_ids, top);
  830. child_ids.StoreInt4((uint32 *)&node_stack[top]);
  831. top += num_results;
  832. }
  833. else
  834. JPH_ASSERT(false, "Stack full!");
  835. }
  836. // Fetch next node until we find one that the visitor wants to see
  837. do
  838. --top;
  839. while (top >= 0 && !ioVisitor.ShouldVisitNode(top));
  840. }
  841. while (top >= 0);
  842. #ifdef JPH_TRACK_BROADPHASE_STATS
  843. // Calculate total time the broadphase walk took
  844. uint64 total_ticks = GetProcessorTickCount() - start;
  845. // Update stats under lock protection (slow!)
  846. {
  847. unique_lock lock(mStatsMutex);
  848. Stat &s = ioStats[inObjectLayerFilter.GetDescription()];
  849. s.mNumQueries++;
  850. s.mNodesVisited += nodes_visited;
  851. s.mBodiesVisited += bodies_visited;
  852. s.mHitsReported += hits_collected;
  853. s.mTotalTicks += total_ticks;
  854. s.mCollectorTicks += collector_ticks;
  855. }
  856. #endif // JPH_TRACK_BROADPHASE_STATS
  857. }
  858. void QuadTree::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  859. {
  860. class Visitor
  861. {
  862. public:
  863. /// Constructor
  864. JPH_INLINE Visitor(const RayCast &inRay, RayCastBodyCollector &ioCollector) :
  865. mOrigin(inRay.mOrigin),
  866. mInvDirection(inRay.mDirection),
  867. mCollector(ioCollector)
  868. {
  869. mFractionStack[0] = -1;
  870. }
  871. /// Returns true if further processing of the tree should be aborted
  872. JPH_INLINE bool ShouldAbort() const
  873. {
  874. return mCollector.ShouldEarlyOut();
  875. }
  876. /// Returns true if this node / body should be visited, false if no hit can be generated
  877. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  878. {
  879. return mFractionStack[inStackTop] < mCollector.GetEarlyOutFraction();
  880. }
  881. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  882. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop)
  883. {
  884. // Test the ray against 4 bounding boxes
  885. Vec4 fraction = RayAABox4(mOrigin, mInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  886. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  887. return SortReverseAndStore(fraction, mCollector.GetEarlyOutFraction(), ioChildNodeIDs, &mFractionStack[inStackTop]);
  888. }
  889. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  890. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  891. {
  892. // Store potential hit with body
  893. BroadPhaseCastResult result { inBodyID, mFractionStack[inStackTop] };
  894. mCollector.AddHit(result);
  895. }
  896. private:
  897. Vec3 mOrigin;
  898. RayInvDirection mInvDirection;
  899. RayCastBodyCollector & mCollector;
  900. float mFractionStack[cStackSize];
  901. };
  902. Visitor visitor(inRay, ioCollector);
  903. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCastRayStats));
  904. }
  905. void QuadTree::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  906. {
  907. class Visitor
  908. {
  909. public:
  910. /// Constructor
  911. JPH_INLINE Visitor(const AABox &inBox, CollideShapeBodyCollector &ioCollector) :
  912. mBox(inBox),
  913. mCollector(ioCollector)
  914. {
  915. }
  916. /// Returns true if further processing of the tree should be aborted
  917. JPH_INLINE bool ShouldAbort() const
  918. {
  919. return mCollector.ShouldEarlyOut();
  920. }
  921. /// Returns true if this node / body should be visited, false if no hit can be generated
  922. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  923. {
  924. return true;
  925. }
  926. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  927. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop) const
  928. {
  929. // Test the box vs 4 boxes
  930. UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  931. return CountAndSortTrues(hitting, ioChildNodeIDs);
  932. }
  933. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  934. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  935. {
  936. // Store potential hit with body
  937. mCollector.AddHit(inBodyID);
  938. }
  939. private:
  940. const AABox & mBox;
  941. CollideShapeBodyCollector & mCollector;
  942. };
  943. Visitor visitor(inBox, ioCollector);
  944. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCollideAABoxStats));
  945. }
  946. void QuadTree::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  947. {
  948. class Visitor
  949. {
  950. public:
  951. /// Constructor
  952. JPH_INLINE Visitor(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector) :
  953. mCenterX(inCenter.SplatX()),
  954. mCenterY(inCenter.SplatY()),
  955. mCenterZ(inCenter.SplatZ()),
  956. mRadiusSq(Vec4::sReplicate(Square(inRadius))),
  957. mCollector(ioCollector)
  958. {
  959. }
  960. /// Returns true if further processing of the tree should be aborted
  961. JPH_INLINE bool ShouldAbort() const
  962. {
  963. return mCollector.ShouldEarlyOut();
  964. }
  965. /// Returns true if this node / body should be visited, false if no hit can be generated
  966. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  967. {
  968. return true;
  969. }
  970. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  971. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop) const
  972. {
  973. // Test 4 boxes vs sphere
  974. UVec4 hitting = AABox4VsSphere(mCenterX, mCenterY, mCenterZ, mRadiusSq, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  975. return CountAndSortTrues(hitting, ioChildNodeIDs);
  976. }
  977. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  978. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  979. {
  980. // Store potential hit with body
  981. mCollector.AddHit(inBodyID);
  982. }
  983. private:
  984. Vec4 mCenterX;
  985. Vec4 mCenterY;
  986. Vec4 mCenterZ;
  987. Vec4 mRadiusSq;
  988. CollideShapeBodyCollector & mCollector;
  989. };
  990. Visitor visitor(inCenter, inRadius, ioCollector);
  991. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCollideSphereStats));
  992. }
  993. void QuadTree::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  994. {
  995. class Visitor
  996. {
  997. public:
  998. /// Constructor
  999. JPH_INLINE Visitor(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector) :
  1000. mPoint(inPoint),
  1001. mCollector(ioCollector)
  1002. {
  1003. }
  1004. /// Returns true if further processing of the tree should be aborted
  1005. JPH_INLINE bool ShouldAbort() const
  1006. {
  1007. return mCollector.ShouldEarlyOut();
  1008. }
  1009. /// Returns true if this node / body should be visited, false if no hit can be generated
  1010. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  1011. {
  1012. return true;
  1013. }
  1014. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  1015. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop) const
  1016. {
  1017. // Test if point overlaps with box
  1018. UVec4 hitting = AABox4VsPoint(mPoint, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1019. return CountAndSortTrues(hitting, ioChildNodeIDs);
  1020. }
  1021. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  1022. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  1023. {
  1024. // Store potential hit with body
  1025. mCollector.AddHit(inBodyID);
  1026. }
  1027. private:
  1028. Vec3 mPoint;
  1029. CollideShapeBodyCollector & mCollector;
  1030. };
  1031. Visitor visitor(inPoint, ioCollector);
  1032. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCollidePointStats));
  1033. }
  1034. void QuadTree::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  1035. {
  1036. class Visitor
  1037. {
  1038. public:
  1039. /// Constructor
  1040. JPH_INLINE Visitor(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector) :
  1041. mBox(inBox),
  1042. mCollector(ioCollector)
  1043. {
  1044. }
  1045. /// Returns true if further processing of the tree should be aborted
  1046. JPH_INLINE bool ShouldAbort() const
  1047. {
  1048. return mCollector.ShouldEarlyOut();
  1049. }
  1050. /// Returns true if this node / body should be visited, false if no hit can be generated
  1051. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  1052. {
  1053. return true;
  1054. }
  1055. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  1056. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop) const
  1057. {
  1058. // Test if point overlaps with box
  1059. UVec4 hitting = AABox4VsBox(mBox, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1060. return CountAndSortTrues(hitting, ioChildNodeIDs);
  1061. }
  1062. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  1063. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  1064. {
  1065. // Store potential hit with body
  1066. mCollector.AddHit(inBodyID);
  1067. }
  1068. private:
  1069. OrientedBox mBox;
  1070. CollideShapeBodyCollector & mCollector;
  1071. };
  1072. Visitor visitor(inBox, ioCollector);
  1073. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCollideOrientedBoxStats));
  1074. }
  1075. void QuadTree::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const ObjectLayerFilter &inObjectLayerFilter, const TrackingVector &inTracking) const
  1076. {
  1077. class Visitor
  1078. {
  1079. public:
  1080. /// Constructor
  1081. JPH_INLINE Visitor(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector) :
  1082. mOrigin(inBox.mBox.GetCenter()),
  1083. mExtent(inBox.mBox.GetExtent()),
  1084. mInvDirection(inBox.mDirection),
  1085. mCollector(ioCollector)
  1086. {
  1087. mFractionStack[0] = -1;
  1088. }
  1089. /// Returns true if further processing of the tree should be aborted
  1090. JPH_INLINE bool ShouldAbort() const
  1091. {
  1092. return mCollector.ShouldEarlyOut();
  1093. }
  1094. /// Returns true if this node / body should be visited, false if no hit can be generated
  1095. JPH_INLINE bool ShouldVisitNode(int inStackTop) const
  1096. {
  1097. return mFractionStack[inStackTop] < mCollector.GetEarlyOutFraction();
  1098. }
  1099. /// Visit nodes, returns number of hits found and sorts ioChildNodeIDs so that they are at the beginning of the vector.
  1100. JPH_INLINE int VisitNodes(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ, UVec4 &ioChildNodeIDs, int inStackTop)
  1101. {
  1102. // Enlarge them by the casted aabox extents
  1103. AABox4EnlargeWithExtent(mExtent, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1104. // Test 4 children
  1105. Vec4 fraction = RayAABox4(mOrigin, mInvDirection, inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  1106. // Sort so that highest values are first (we want to first process closer hits and we process stack top to bottom)
  1107. return SortReverseAndStore(fraction, mCollector.GetEarlyOutFraction(), ioChildNodeIDs, &mFractionStack[inStackTop]);
  1108. }
  1109. /// Visit a body, returns false if the algorithm should terminate because no hits can be generated anymore
  1110. JPH_INLINE void VisitBody(const BodyID &inBodyID, int inStackTop)
  1111. {
  1112. // Store potential hit with body
  1113. BroadPhaseCastResult result { inBodyID, mFractionStack[inStackTop] };
  1114. mCollector.AddHit(result);
  1115. }
  1116. private:
  1117. Vec3 mOrigin;
  1118. Vec3 mExtent;
  1119. RayInvDirection mInvDirection;
  1120. CastShapeBodyCollector & mCollector;
  1121. float mFractionStack[cStackSize];
  1122. };
  1123. Visitor visitor(inBox, ioCollector);
  1124. WalkTree(inObjectLayerFilter, inTracking, visitor JPH_IF_TRACK_BROADPHASE_STATS(, mCastAABoxStats));
  1125. }
  1126. void QuadTree::FindCollidingPairs(const BodyVector &inBodies, const BodyID *inActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, BodyPairCollector &ioPairCollector, ObjectLayerPairFilter inObjectLayerPairFilter) const
  1127. {
  1128. // Note that we don't lock the tree 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.
  1129. // We double check this at the end of the function.
  1130. const RootNode &root_node = GetCurrentRoot();
  1131. JPH_ASSERT(root_node.mIndex != cInvalidNodeIndex);
  1132. // Assert sane input
  1133. JPH_ASSERT(inActiveBodies != nullptr);
  1134. JPH_ASSERT(inNumActiveBodies > 0);
  1135. NodeID node_stack[cStackSize];
  1136. // Loop over all active bodies
  1137. for (int b1 = 0; b1 < inNumActiveBodies; ++b1)
  1138. {
  1139. BodyID b1_id = inActiveBodies[b1];
  1140. const Body &body1 = *inBodies[b1_id.GetIndex()];
  1141. JPH_ASSERT(!body1.IsStatic());
  1142. // Expand the bounding box by the speculative contact distance
  1143. AABox bounds1 = body1.GetWorldSpaceBounds();
  1144. bounds1.ExpandBy(Vec3::sReplicate(inSpeculativeContactDistance));
  1145. // Test each body with the tree
  1146. node_stack[0] = root_node.GetNodeID();
  1147. int top = 0;
  1148. do
  1149. {
  1150. // Check if node is a body
  1151. NodeID child_node_id = node_stack[top];
  1152. if (child_node_id.IsBody())
  1153. {
  1154. // Don't collide with self
  1155. BodyID b2_id = child_node_id.GetBodyID();
  1156. if (b1_id != b2_id)
  1157. {
  1158. // Collision between dynamic pairs need to be picked up only once
  1159. const Body &body2 = *inBodies[b2_id.GetIndex()];
  1160. if (inObjectLayerPairFilter(body1.GetObjectLayer(), body2.GetObjectLayer())
  1161. && Body::sFindCollidingPairsCanCollide(body1, body2))
  1162. {
  1163. // In the broadphase we widen the bounding box when a body moves, do a final
  1164. // check to see if the bounding boxes actually overlap
  1165. if (bounds1.Overlaps(body2.GetWorldSpaceBounds()))
  1166. {
  1167. // Store potential hit between bodies
  1168. ioPairCollector.AddHit({ b1_id, b2_id });
  1169. }
  1170. }
  1171. }
  1172. }
  1173. else if (child_node_id.IsValid())
  1174. {
  1175. // Process normal node
  1176. const Node &node = mAllocator->Get(child_node_id.GetNodeIndex());
  1177. JPH_ASSERT(IsAligned(&node, JPH_CACHE_LINE_SIZE));
  1178. // Get bounds of 4 children
  1179. Vec4 bounds_minx = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinX);
  1180. Vec4 bounds_miny = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinY);
  1181. Vec4 bounds_minz = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMinZ);
  1182. Vec4 bounds_maxx = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxX);
  1183. Vec4 bounds_maxy = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxY);
  1184. Vec4 bounds_maxz = Vec4::sLoadFloat4Aligned((const Float4 *)&node.mBoundsMaxZ);
  1185. // Test overlap
  1186. UVec4 overlap = AABox4VsBox(bounds1, bounds_minx, bounds_miny, bounds_minz, bounds_maxx, bounds_maxy, bounds_maxz);
  1187. int num_results = overlap.CountTrues();
  1188. if (num_results > 0)
  1189. {
  1190. // Load ids for 4 children
  1191. UVec4 child_ids = UVec4::sLoadInt4Aligned((const uint32 *)&node.mChildNodeID[0]);
  1192. // Sort so that overlaps are first
  1193. child_ids = UVec4::sSort4True(overlap, child_ids);
  1194. // Push them onto the stack
  1195. if (top + 4 < cStackSize)
  1196. {
  1197. child_ids.StoreInt4((uint32 *)&node_stack[top]);
  1198. top += num_results;
  1199. }
  1200. else
  1201. JPH_ASSERT(false, "Stack full!");
  1202. }
  1203. }
  1204. --top;
  1205. }
  1206. while (top >= 0);
  1207. }
  1208. // Test that the root node was not swapped while finding collision pairs.
  1209. // This would mean that UpdateFinalize/DiscardOldTree ran during collision detection which should not be possible due to the way the jobs are scheduled.
  1210. JPH_ASSERT(root_node.mIndex != cInvalidNodeIndex);
  1211. JPH_ASSERT(&root_node == &GetCurrentRoot());
  1212. }
  1213. #ifdef _DEBUG
  1214. void QuadTree::ValidateTree(const BodyVector &inBodies, const TrackingVector &inTracking, uint32 inNodeIndex, uint32 inNumExpectedBodies) const
  1215. {
  1216. JPH_PROFILE_FUNCTION();
  1217. // Root should be valid
  1218. JPH_ASSERT(inNodeIndex != cInvalidNodeIndex);
  1219. // To avoid call overhead, create a stack in place
  1220. struct StackEntry
  1221. {
  1222. uint32 mNodeIndex;
  1223. uint32 mParentNodeIndex;
  1224. };
  1225. StackEntry stack[cStackSize];
  1226. stack[0].mNodeIndex = inNodeIndex;
  1227. stack[0].mParentNodeIndex = cInvalidNodeIndex;
  1228. int top = 0;
  1229. uint32 num_bodies = 0;
  1230. do
  1231. {
  1232. // Copy entry from the stack
  1233. StackEntry cur_stack = stack[top];
  1234. // Validate parent
  1235. const Node &node = mAllocator->Get(cur_stack.mNodeIndex);
  1236. JPH_ASSERT(node.mParentNodeIndex == cur_stack.mParentNodeIndex);
  1237. // Validate that when a parent is not-changed that all of its children are also
  1238. JPH_ASSERT(cur_stack.mParentNodeIndex == cInvalidNodeIndex || mAllocator->Get(cur_stack.mParentNodeIndex).mIsChanged || !node.mIsChanged);
  1239. // Loop children
  1240. for (uint32 i = 0; i < 4; ++i)
  1241. {
  1242. NodeID child_node_id = node.mChildNodeID[i];
  1243. if (child_node_id.IsValid())
  1244. {
  1245. if (child_node_id.IsNode())
  1246. {
  1247. // Child is a node, recurse
  1248. uint32 child_idx = child_node_id.GetNodeIndex();
  1249. StackEntry &new_entry = stack[top++];
  1250. new_entry.mNodeIndex = child_idx;
  1251. new_entry.mParentNodeIndex = cur_stack.mNodeIndex;
  1252. // Validate that the bounding box is bigger or equal to the bounds in the tree
  1253. // Bounding box could also be invalid if all children of our child were removed
  1254. AABox child_bounds;
  1255. node.GetChildBounds(i, child_bounds);
  1256. AABox real_child_bounds;
  1257. mAllocator->Get(child_idx).GetNodeBounds(real_child_bounds);
  1258. JPH_ASSERT(child_bounds.Contains(real_child_bounds) || !real_child_bounds.IsValid());
  1259. }
  1260. else
  1261. {
  1262. // Increment number of bodies found
  1263. ++num_bodies;
  1264. // Check if tracker matches position of body
  1265. uint32 node_idx, child_idx;
  1266. GetBodyLocation(inTracking, child_node_id.GetBodyID(), node_idx, child_idx);
  1267. JPH_ASSERT(node_idx == cur_stack.mNodeIndex);
  1268. JPH_ASSERT(child_idx == i);
  1269. // Validate that the body bounds are bigger or equal to the bounds in the tree
  1270. AABox body_bounds;
  1271. node.GetChildBounds(i, body_bounds);
  1272. const Body *body = inBodies[child_node_id.GetBodyID().GetIndex()];
  1273. AABox cached_body_bounds = body->GetWorldSpaceBounds();
  1274. AABox real_body_bounds = body->GetShape()->GetWorldSpaceBounds(body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
  1275. JPH_ASSERT(cached_body_bounds == real_body_bounds); // Check that cached body bounds are up to date
  1276. JPH_ASSERT(body_bounds.Contains(real_body_bounds));
  1277. }
  1278. }
  1279. }
  1280. --top;
  1281. }
  1282. while (top >= 0);
  1283. // Check that the amount of bodies in the tree matches our counter
  1284. JPH_ASSERT(num_bodies == inNumExpectedBodies);
  1285. }
  1286. #endif
  1287. #ifdef JPH_TRACK_BROADPHASE_STATS
  1288. void QuadTree::ReportStats(const char *inName, const LayerToStats &inLayer) const
  1289. {
  1290. uint64 ticks_per_sec = GetProcessorTicksPerSecond();
  1291. for (const LayerToStats::value_type &kv : inLayer)
  1292. {
  1293. double total_time = 1000.0 * double(kv.second.mTotalTicks) / double(ticks_per_sec);
  1294. double total_time_excl_collector = 1000.0 * double(kv.second.mTotalTicks - kv.second.mCollectorTicks) / double(ticks_per_sec);
  1295. double hits_reported_vs_bodies_visited = kv.second.mBodiesVisited > 0? 100.0 * double(kv.second.mHitsReported) / double(kv.second.mBodiesVisited) : 100.0;
  1296. double hits_reported_vs_nodes_visited = kv.second.mNodesVisited > 0? double(kv.second.mHitsReported) / double(kv.second.mNodesVisited) : -1.0f;
  1297. stringstream str;
  1298. str << inName << ", " << kv.first << ", " << mName << ", " << kv.second.mNumQueries << ", " << total_time << ", " << total_time_excl_collector << ", " << kv.second.mNodesVisited << ", " << kv.second.mBodiesVisited << ", " << kv.second.mHitsReported << ", " << hits_reported_vs_bodies_visited << ", " << hits_reported_vs_nodes_visited;
  1299. Trace(str.str().c_str());
  1300. }
  1301. }
  1302. void QuadTree::ReportStats() const
  1303. {
  1304. unique_lock lock(mStatsMutex);
  1305. ReportStats("RayCast", mCastRayStats);
  1306. ReportStats("CollideAABox", mCollideAABoxStats);
  1307. ReportStats("CollideSphere", mCollideSphereStats);
  1308. ReportStats("CollidePoint", mCollidePointStats);
  1309. ReportStats("CollideOrientedBox", mCollideOrientedBoxStats);
  1310. ReportStats("CastAABox", mCastAABoxStats);
  1311. }
  1312. #endif // JPH_TRACK_BROADPHASE_STATS
  1313. } // JPH