QuadTree.cpp 50 KB

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