BroadPhaseBruteForce.cpp 8.2 KB

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