NarrowPhaseQuery.cpp 16 KB

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