2
0

BroadPhaseBruteForce.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h>
  6. #include <Jolt/Physics/Collision/RayCast.h>
  7. #include <Jolt/Physics/Collision/AABoxCast.h>
  8. #include <Jolt/Physics/Collision/CastResult.h>
  9. #include <Jolt/Physics/Body/BodyManager.h>
  10. #include <Jolt/Physics/Body/BodyPair.h>
  11. #include <Jolt/Geometry/RayAABox.h>
  12. #include <Jolt/Geometry/OrientedBox.h>
  13. #include <Jolt/Core/QuickSort.h>
  14. JPH_NAMESPACE_BEGIN
  15. void BroadPhaseBruteForce::AddBodiesFinalize(BodyID *ioBodies, int inNumber, AddState inAddState)
  16. {
  17. lock_guard lock(mMutex);
  18. BodyVector &bodies = mBodyManager->GetBodies();
  19. // Allocate space
  20. uint32 idx = (uint32)mBodyIDs.size();
  21. mBodyIDs.resize(idx + inNumber);
  22. // Add bodies
  23. for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)
  24. {
  25. Body &body = *bodies[b->GetIndex()];
  26. // Validate that body ID is consistent with array index
  27. JPH_ASSERT(body.GetID() == *b);
  28. JPH_ASSERT(!body.IsInBroadPhase());
  29. // Add it to the list
  30. mBodyIDs[idx] = body.GetID();
  31. ++idx;
  32. // Indicate body is in the broadphase
  33. body.SetInBroadPhaseInternal(true);
  34. }
  35. // Resort
  36. QuickSort(mBodyIDs.begin(), mBodyIDs.end());
  37. }
  38. void BroadPhaseBruteForce::RemoveBodies(BodyID *ioBodies, int inNumber)
  39. {
  40. lock_guard lock(mMutex);
  41. BodyVector &bodies = mBodyManager->GetBodies();
  42. JPH_ASSERT((int)mBodyIDs.size() >= inNumber);
  43. // Remove bodies
  44. for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)
  45. {
  46. Body &body = *bodies[b->GetIndex()];
  47. // Validate that body ID is consistent with array index
  48. JPH_ASSERT(body.GetID() == *b);
  49. JPH_ASSERT(body.IsInBroadPhase());
  50. // Find body id
  51. Array<BodyID>::iterator it = lower_bound(mBodyIDs.begin(), mBodyIDs.end(), body.GetID());
  52. JPH_ASSERT(it != mBodyIDs.end());
  53. // Remove element
  54. mBodyIDs.erase(it);
  55. // Indicate body is no longer in the broadphase
  56. body.SetInBroadPhaseInternal(false);
  57. }
  58. }
  59. void BroadPhaseBruteForce::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock)
  60. {
  61. // Do nothing, we directly reference the body
  62. }
  63. void BroadPhaseBruteForce::NotifyBodiesLayerChanged(BodyID * ioBodies, int inNumber)
  64. {
  65. // Do nothing, we directly reference the body
  66. }
  67. void BroadPhaseBruteForce::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  68. {
  69. shared_lock lock(mMutex);
  70. // Load ray
  71. Vec3 origin(inRay.mOrigin);
  72. RayInvDirection inv_direction(inRay.mDirection);
  73. // For all bodies
  74. float early_out_fraction = ioCollector.GetEarlyOutFraction();
  75. for (BodyID b : mBodyIDs)
  76. {
  77. const Body &body = mBodyManager->GetBody(b);
  78. // Test layer
  79. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  80. {
  81. // Test intersection with ray
  82. const AABox &bounds = body.GetWorldSpaceBounds();
  83. float fraction = RayAABox(origin, inv_direction, bounds.mMin, bounds.mMax);
  84. if (fraction < early_out_fraction)
  85. {
  86. // Store hit
  87. BroadPhaseCastResult result { b, fraction };
  88. ioCollector.AddHit(result);
  89. if (ioCollector.ShouldEarlyOut())
  90. break;
  91. early_out_fraction = ioCollector.GetEarlyOutFraction();
  92. }
  93. }
  94. }
  95. }
  96. void BroadPhaseBruteForce::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  97. {
  98. shared_lock lock(mMutex);
  99. // For all bodies
  100. for (BodyID b : mBodyIDs)
  101. {
  102. const Body &body = mBodyManager->GetBody(b);
  103. // Test layer
  104. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  105. {
  106. // Test intersection with box
  107. const AABox &bounds = body.GetWorldSpaceBounds();
  108. if (bounds.Overlaps(inBox))
  109. {
  110. // Store hit
  111. ioCollector.AddHit(b);
  112. if (ioCollector.ShouldEarlyOut())
  113. break;
  114. }
  115. }
  116. }
  117. }
  118. void BroadPhaseBruteForce::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  119. {
  120. shared_lock lock(mMutex);
  121. float radius_sq = Square(inRadius);
  122. // For all bodies
  123. for (BodyID b : mBodyIDs)
  124. {
  125. const Body &body = mBodyManager->GetBody(b);
  126. // Test layer
  127. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  128. {
  129. // Test intersection with box
  130. const AABox &bounds = body.GetWorldSpaceBounds();
  131. if (bounds.GetSqDistanceTo(inCenter) <= radius_sq)
  132. {
  133. // Store hit
  134. ioCollector.AddHit(b);
  135. if (ioCollector.ShouldEarlyOut())
  136. break;
  137. }
  138. }
  139. }
  140. }
  141. void BroadPhaseBruteForce::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  142. {
  143. shared_lock lock(mMutex);
  144. // For all bodies
  145. for (BodyID b : mBodyIDs)
  146. {
  147. const Body &body = mBodyManager->GetBody(b);
  148. // Test layer
  149. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  150. {
  151. // Test intersection with box
  152. const AABox &bounds = body.GetWorldSpaceBounds();
  153. if (bounds.Contains(inPoint))
  154. {
  155. // Store hit
  156. ioCollector.AddHit(b);
  157. if (ioCollector.ShouldEarlyOut())
  158. break;
  159. }
  160. }
  161. }
  162. }
  163. void BroadPhaseBruteForce::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  164. {
  165. shared_lock lock(mMutex);
  166. // For all bodies
  167. for (BodyID b : mBodyIDs)
  168. {
  169. const Body &body = mBodyManager->GetBody(b);
  170. // Test layer
  171. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  172. {
  173. // Test intersection with box
  174. const AABox &bounds = body.GetWorldSpaceBounds();
  175. if (inBox.Overlaps(bounds))
  176. {
  177. // Store hit
  178. ioCollector.AddHit(b);
  179. if (ioCollector.ShouldEarlyOut())
  180. break;
  181. }
  182. }
  183. }
  184. }
  185. void BroadPhaseBruteForce::CastAABoxNoLock(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  186. {
  187. shared_lock lock(mMutex);
  188. // Load box
  189. Vec3 origin(inBox.mBox.GetCenter());
  190. Vec3 extent(inBox.mBox.GetExtent());
  191. RayInvDirection inv_direction(inBox.mDirection);
  192. // For all bodies
  193. float early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();
  194. for (BodyID b : mBodyIDs)
  195. {
  196. const Body &body = mBodyManager->GetBody(b);
  197. // Test layer
  198. if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
  199. {
  200. // Test intersection with ray
  201. const AABox &bounds = body.GetWorldSpaceBounds();
  202. float fraction = RayAABox(origin, inv_direction, bounds.mMin - extent, bounds.mMax + extent);
  203. if (fraction < early_out_fraction)
  204. {
  205. // Store hit
  206. BroadPhaseCastResult result { b, fraction };
  207. ioCollector.AddHit(result);
  208. if (ioCollector.ShouldEarlyOut())
  209. break;
  210. early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();
  211. }
  212. }
  213. }
  214. }
  215. void BroadPhaseBruteForce::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
  216. {
  217. CastAABoxNoLock(inBox, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  218. }
  219. void BroadPhaseBruteForce::FindCollidingPairs(BodyID *ioActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, const ObjectVsBroadPhaseLayerFilter &inObjectVsBroadPhaseLayerFilter, const ObjectLayerPairFilter &inObjectLayerPairFilter, BodyPairCollector &ioPairCollector) const
  220. {
  221. shared_lock lock(mMutex);
  222. // Loop through all active bodies
  223. size_t num_bodies = mBodyIDs.size();
  224. for (int b1 = 0; b1 < inNumActiveBodies; ++b1)
  225. {
  226. BodyID b1_id = ioActiveBodies[b1];
  227. const Body &body1 = mBodyManager->GetBody(b1_id);
  228. const ObjectLayer layer1 = body1.GetObjectLayer();
  229. // Expand the bounding box by the speculative contact distance
  230. AABox bounds1 = body1.GetWorldSpaceBounds();
  231. bounds1.ExpandBy(Vec3::sReplicate(inSpeculativeContactDistance));
  232. // For all other bodies
  233. for (size_t b2 = 0; b2 < num_bodies; ++b2)
  234. {
  235. // Check if bodies can collide
  236. BodyID b2_id = mBodyIDs[b2];
  237. const Body &body2 = mBodyManager->GetBody(b2_id);
  238. if (!Body::sFindCollidingPairsCanCollide(body1, body2))
  239. continue;
  240. // Check if layers can collide
  241. const ObjectLayer layer2 = body2.GetObjectLayer();
  242. if (!inObjectLayerPairFilter.ShouldCollide(layer1, layer2))
  243. continue;
  244. // Check if bounds overlap
  245. const AABox &bounds2 = body2.GetWorldSpaceBounds();
  246. if (!bounds1.Overlaps(bounds2))
  247. continue;
  248. // Store overlapping pair
  249. ioPairCollector.AddHit({ b1_id, b2_id });
  250. }
  251. }
  252. }
  253. JPH_NAMESPACE_END