NarrowPhaseQuery.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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/NarrowPhaseQuery.h>
  6. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  7. #include <Jolt/Physics/Collision/RayCast.h>
  8. #include <Jolt/Physics/Collision/AABoxCast.h>
  9. #include <Jolt/Physics/Collision/ShapeCast.h>
  10. #include <Jolt/Physics/Collision/CollideShape.h>
  11. #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
  12. #include <Jolt/Physics/Collision/CastResult.h>
  13. #include <Jolt/Physics/Collision/InternalEdgeRemovingCollector.h>
  14. JPH_NAMESPACE_BEGIN
  15. bool NarrowPhaseQuery::CastRay(const RRayCast &inRay, RayCastResult &ioHit, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  16. {
  17. JPH_PROFILE_FUNCTION();
  18. class MyCollector : public RayCastBodyCollector
  19. {
  20. public:
  21. MyCollector(const RRayCast &inRay, RayCastResult &ioHit, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  22. mRay(inRay),
  23. mHit(ioHit),
  24. mBodyLockInterface(inBodyLockInterface),
  25. mBodyFilter(inBodyFilter)
  26. {
  27. ResetEarlyOutFraction(ioHit.mFraction);
  28. }
  29. virtual void AddHit(const ResultType &inResult) override
  30. {
  31. JPH_ASSERT(inResult.mFraction < mHit.mFraction, "This hit should not have been passed on to the collector");
  32. // Only test shape if it passes the body filter
  33. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  34. {
  35. // Lock the body
  36. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  37. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  38. {
  39. const Body &body = lock.GetBody();
  40. // Check body filter again now that we've locked the body
  41. if (mBodyFilter.ShouldCollideLocked(body))
  42. {
  43. // Collect the transformed shape
  44. TransformedShape ts = body.GetTransformedShape();
  45. // Release the lock now, we have all the info we need in the transformed shape
  46. lock.ReleaseLock();
  47. // Do narrow phase collision check
  48. if (ts.CastRay(mRay, mHit))
  49. {
  50. // Test that we didn't find a further hit by accident
  51. JPH_ASSERT(mHit.mFraction >= 0.0f && mHit.mFraction < GetEarlyOutFraction());
  52. // Update early out fraction based on narrow phase collector
  53. UpdateEarlyOutFraction(mHit.mFraction);
  54. }
  55. }
  56. }
  57. }
  58. }
  59. RRayCast mRay;
  60. RayCastResult & mHit;
  61. const BodyLockInterface & mBodyLockInterface;
  62. const BodyFilter & mBodyFilter;
  63. };
  64. // Do broadphase test, note that the broadphase uses floats so we drop precision here
  65. MyCollector collector(inRay, ioHit, *mBodyLockInterface, inBodyFilter);
  66. mBroadPhaseQuery->CastRay(RayCast(inRay), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  67. return ioHit.mFraction <= 1.0f;
  68. }
  69. void NarrowPhaseQuery::CastRay(const RRayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  70. {
  71. JPH_PROFILE_FUNCTION();
  72. class MyCollector : public RayCastBodyCollector
  73. {
  74. public:
  75. MyCollector(const RRayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  76. RayCastBodyCollector(ioCollector),
  77. mRay(inRay),
  78. mRayCastSettings(inRayCastSettings),
  79. mCollector(ioCollector),
  80. mBodyLockInterface(inBodyLockInterface),
  81. mBodyFilter(inBodyFilter),
  82. mShapeFilter(inShapeFilter)
  83. {
  84. }
  85. virtual void AddHit(const ResultType &inResult) override
  86. {
  87. JPH_ASSERT(inResult.mFraction < mCollector.GetEarlyOutFraction(), "This hit should not have been passed on to the collector");
  88. // Only test shape if it passes the body filter
  89. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  90. {
  91. // Lock the body
  92. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  93. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  94. {
  95. const Body &body = lock.GetBody();
  96. // Check body filter again now that we've locked the body
  97. if (mBodyFilter.ShouldCollideLocked(body))
  98. {
  99. // Collect the transformed shape
  100. TransformedShape ts = body.GetTransformedShape();
  101. // Notify collector of new body
  102. mCollector.OnBody(body);
  103. // Release the lock now, we have all the info we need in the transformed shape
  104. lock.ReleaseLock();
  105. // Do narrow phase collision check
  106. ts.CastRay(mRay, mRayCastSettings, mCollector, mShapeFilter);
  107. // Notify collector of the end of this body
  108. // We do this before updating the early out fraction so that the collector can still modify it
  109. mCollector.OnBodyEnd();
  110. // Update early out fraction based on narrow phase collector
  111. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  112. }
  113. }
  114. }
  115. }
  116. RRayCast mRay;
  117. RayCastSettings mRayCastSettings;
  118. CastRayCollector & mCollector;
  119. const BodyLockInterface & mBodyLockInterface;
  120. const BodyFilter & mBodyFilter;
  121. const ShapeFilter & mShapeFilter;
  122. };
  123. // Do broadphase test, note that the broadphase uses floats so we drop precision here
  124. MyCollector collector(inRay, inRayCastSettings, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  125. mBroadPhaseQuery->CastRay(RayCast(inRay), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  126. }
  127. void NarrowPhaseQuery::CollidePoint(RVec3Arg inPoint, CollidePointCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  128. {
  129. JPH_PROFILE_FUNCTION();
  130. class MyCollector : public CollideShapeBodyCollector
  131. {
  132. public:
  133. MyCollector(RVec3Arg inPoint, CollidePointCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  134. CollideShapeBodyCollector(ioCollector),
  135. mPoint(inPoint),
  136. mCollector(ioCollector),
  137. mBodyLockInterface(inBodyLockInterface),
  138. mBodyFilter(inBodyFilter),
  139. mShapeFilter(inShapeFilter)
  140. {
  141. }
  142. virtual void AddHit(const ResultType &inResult) override
  143. {
  144. // Only test shape if it passes the body filter
  145. if (mBodyFilter.ShouldCollide(inResult))
  146. {
  147. // Lock the body
  148. BodyLockRead lock(mBodyLockInterface, inResult);
  149. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  150. {
  151. const Body &body = lock.GetBody();
  152. // Check body filter again now that we've locked the body
  153. if (mBodyFilter.ShouldCollideLocked(body))
  154. {
  155. // Collect the transformed shape
  156. TransformedShape ts = body.GetTransformedShape();
  157. // Notify collector of new body
  158. mCollector.OnBody(body);
  159. // Release the lock now, we have all the info we need in the transformed shape
  160. lock.ReleaseLock();
  161. // Do narrow phase collision check
  162. ts.CollidePoint(mPoint, mCollector, mShapeFilter);
  163. // Notify collector of the end of this body
  164. // We do this before updating the early out fraction so that the collector can still modify it
  165. mCollector.OnBodyEnd();
  166. // Update early out fraction based on narrow phase collector
  167. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  168. }
  169. }
  170. }
  171. }
  172. RVec3 mPoint;
  173. CollidePointCollector & mCollector;
  174. const BodyLockInterface & mBodyLockInterface;
  175. const BodyFilter & mBodyFilter;
  176. const ShapeFilter & mShapeFilter;
  177. };
  178. // Do broadphase test (note: truncates double to single precision since the broadphase uses single precision)
  179. MyCollector collector(inPoint, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  180. mBroadPhaseQuery->CollidePoint(Vec3(inPoint), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  181. }
  182. void NarrowPhaseQuery::CollideShape(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  183. {
  184. JPH_PROFILE_FUNCTION();
  185. class MyCollector : public CollideShapeBodyCollector
  186. {
  187. public:
  188. MyCollector(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  189. CollideShapeBodyCollector(ioCollector),
  190. mShape(inShape),
  191. mShapeScale(inShapeScale),
  192. mCenterOfMassTransform(inCenterOfMassTransform),
  193. mCollideShapeSettings(inCollideShapeSettings),
  194. mBaseOffset(inBaseOffset),
  195. mCollector(ioCollector),
  196. mBodyLockInterface(inBodyLockInterface),
  197. mBodyFilter(inBodyFilter),
  198. mShapeFilter(inShapeFilter)
  199. {
  200. }
  201. virtual void AddHit(const ResultType &inResult) override
  202. {
  203. // Only test shape if it passes the body filter
  204. if (mBodyFilter.ShouldCollide(inResult))
  205. {
  206. // Lock the body
  207. BodyLockRead lock(mBodyLockInterface, inResult);
  208. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  209. {
  210. const Body &body = lock.GetBody();
  211. // Check body filter again now that we've locked the body
  212. if (mBodyFilter.ShouldCollideLocked(body))
  213. {
  214. // Collect the transformed shape
  215. TransformedShape ts = body.GetTransformedShape();
  216. // Notify collector of new body
  217. mCollector.OnBody(body);
  218. // Release the lock now, we have all the info we need in the transformed shape
  219. lock.ReleaseLock();
  220. // Do narrow phase collision check
  221. ts.CollideShape(mShape, mShapeScale, mCenterOfMassTransform, mCollideShapeSettings, mBaseOffset, mCollector, mShapeFilter);
  222. // Notify collector of the end of this body
  223. // We do this before updating the early out fraction so that the collector can still modify it
  224. mCollector.OnBodyEnd();
  225. // Update early out fraction based on narrow phase collector
  226. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  227. }
  228. }
  229. }
  230. }
  231. const Shape * mShape;
  232. Vec3 mShapeScale;
  233. RMat44 mCenterOfMassTransform;
  234. const CollideShapeSettings & mCollideShapeSettings;
  235. RVec3 mBaseOffset;
  236. CollideShapeCollector & mCollector;
  237. const BodyLockInterface & mBodyLockInterface;
  238. const BodyFilter & mBodyFilter;
  239. const ShapeFilter & mShapeFilter;
  240. };
  241. // Calculate bounds for shape and expand by max separation distance
  242. AABox bounds = inShape->GetWorldSpaceBounds(inCenterOfMassTransform, inShapeScale);
  243. bounds.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));
  244. // Do broadphase test
  245. MyCollector collector(inShape, inShapeScale, inCenterOfMassTransform, inCollideShapeSettings, inBaseOffset, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  246. mBroadPhaseQuery->CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  247. }
  248. void NarrowPhaseQuery::CollideShapeWithInternalEdgeRemoval(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  249. {
  250. // We require these settings for internal edge removal to work
  251. CollideShapeSettings settings = inCollideShapeSettings;
  252. settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
  253. settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
  254. InternalEdgeRemovingCollector wrapper(ioCollector
  255. #ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
  256. , inBaseOffset
  257. #endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
  258. );
  259. CollideShape(inShape, inShapeScale, inCenterOfMassTransform, settings, inBaseOffset, wrapper, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter);
  260. }
  261. void NarrowPhaseQuery::CastShape(const RShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  262. {
  263. JPH_PROFILE_FUNCTION();
  264. class MyCollector : public CastShapeBodyCollector
  265. {
  266. public:
  267. MyCollector(const RShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  268. CastShapeBodyCollector(ioCollector),
  269. mShapeCast(inShapeCast),
  270. mShapeCastSettings(inShapeCastSettings),
  271. mBaseOffset(inBaseOffset),
  272. mCollector(ioCollector),
  273. mBodyLockInterface(inBodyLockInterface),
  274. mBodyFilter(inBodyFilter),
  275. mShapeFilter(inShapeFilter)
  276. {
  277. }
  278. virtual void AddHit(const ResultType &inResult) override
  279. {
  280. JPH_ASSERT(inResult.mFraction <= max(0.0f, mCollector.GetEarlyOutFraction()), "This hit should not have been passed on to the collector");
  281. // Only test shape if it passes the body filter
  282. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  283. {
  284. // Lock the body
  285. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  286. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  287. {
  288. const Body &body = lock.GetBody();
  289. // Check body filter again now that we've locked the body
  290. if (mBodyFilter.ShouldCollideLocked(body))
  291. {
  292. // Collect the transformed shape
  293. TransformedShape ts = body.GetTransformedShape();
  294. // Notify collector of new body
  295. mCollector.OnBody(body);
  296. // Release the lock now, we have all the info we need in the transformed shape
  297. lock.ReleaseLock();
  298. // Do narrow phase collision check
  299. ts.CastShape(mShapeCast, mShapeCastSettings, mBaseOffset, mCollector, mShapeFilter);
  300. // Notify collector of the end of this body
  301. // We do this before updating the early out fraction so that the collector can still modify it
  302. mCollector.OnBodyEnd();
  303. // Update early out fraction based on narrow phase collector
  304. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  305. }
  306. }
  307. }
  308. }
  309. RShapeCast mShapeCast;
  310. const ShapeCastSettings & mShapeCastSettings;
  311. RVec3 mBaseOffset;
  312. CastShapeCollector & mCollector;
  313. const BodyLockInterface & mBodyLockInterface;
  314. const BodyFilter & mBodyFilter;
  315. const ShapeFilter & mShapeFilter;
  316. };
  317. // Do broadphase test
  318. MyCollector collector(inShapeCast, inShapeCastSettings, inBaseOffset, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  319. mBroadPhaseQuery->CastAABox({ inShapeCast.mShapeWorldBounds, inShapeCast.mDirection }, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  320. }
  321. void NarrowPhaseQuery::CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  322. {
  323. class MyCollector : public CollideShapeBodyCollector
  324. {
  325. public:
  326. MyCollector(const AABox &inBox, TransformedShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  327. CollideShapeBodyCollector(ioCollector),
  328. mBox(inBox),
  329. mCollector(ioCollector),
  330. mBodyLockInterface(inBodyLockInterface),
  331. mBodyFilter(inBodyFilter),
  332. mShapeFilter(inShapeFilter)
  333. {
  334. }
  335. virtual void AddHit(const ResultType &inResult) override
  336. {
  337. // Only test shape if it passes the body filter
  338. if (mBodyFilter.ShouldCollide(inResult))
  339. {
  340. // Lock the body
  341. BodyLockRead lock(mBodyLockInterface, inResult);
  342. if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
  343. {
  344. const Body &body = lock.GetBody();
  345. // Check body filter again now that we've locked the body
  346. if (mBodyFilter.ShouldCollideLocked(body))
  347. {
  348. // Collect the transformed shape
  349. TransformedShape ts = body.GetTransformedShape();
  350. // Notify collector of new body
  351. mCollector.OnBody(body);
  352. // Release the lock now, we have all the info we need in the transformed shape
  353. lock.ReleaseLock();
  354. // Do narrow phase collision check
  355. ts.CollectTransformedShapes(mBox, mCollector, mShapeFilter);
  356. // Notify collector of the end of this body
  357. // We do this before updating the early out fraction so that the collector can still modify it
  358. mCollector.OnBodyEnd();
  359. // Update early out fraction based on narrow phase collector
  360. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  361. }
  362. }
  363. }
  364. }
  365. const AABox & mBox;
  366. TransformedShapeCollector & mCollector;
  367. const BodyLockInterface & mBodyLockInterface;
  368. const BodyFilter & mBodyFilter;
  369. const ShapeFilter & mShapeFilter;
  370. };
  371. // Do broadphase test
  372. MyCollector collector(inBox, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  373. mBroadPhaseQuery->CollideAABox(inBox, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  374. }
  375. JPH_NAMESPACE_END