NarrowPhaseQuery.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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. CollideShape(inShape, inShapeScale, inCenterOfMassTransform, settings, inBaseOffset, wrapper, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter);
  256. }
  257. 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
  258. {
  259. JPH_PROFILE_FUNCTION();
  260. class MyCollector : public CastShapeBodyCollector
  261. {
  262. public:
  263. MyCollector(const RShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  264. CastShapeBodyCollector(ioCollector),
  265. mShapeCast(inShapeCast),
  266. mShapeCastSettings(inShapeCastSettings),
  267. mBaseOffset(inBaseOffset),
  268. mCollector(ioCollector),
  269. mBodyLockInterface(inBodyLockInterface),
  270. mBodyFilter(inBodyFilter),
  271. mShapeFilter(inShapeFilter)
  272. {
  273. }
  274. virtual void AddHit(const ResultType &inResult) override
  275. {
  276. JPH_ASSERT(inResult.mFraction <= max(0.0f, mCollector.GetEarlyOutFraction()), "This hit should not have been passed on to the collector");
  277. // Only test shape if it passes the body filter
  278. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  279. {
  280. // Lock the body
  281. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  282. 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
  283. {
  284. const Body &body = lock.GetBody();
  285. // Check body filter again now that we've locked the body
  286. if (mBodyFilter.ShouldCollideLocked(body))
  287. {
  288. // Collect the transformed shape
  289. TransformedShape ts = body.GetTransformedShape();
  290. // Notify collector of new body
  291. mCollector.OnBody(body);
  292. // Release the lock now, we have all the info we need in the transformed shape
  293. lock.ReleaseLock();
  294. // Do narrow phase collision check
  295. ts.CastShape(mShapeCast, mShapeCastSettings, mBaseOffset, mCollector, mShapeFilter);
  296. // Notify collector of the end of this body
  297. // We do this before updating the early out fraction so that the collector can still modify it
  298. mCollector.OnBodyEnd();
  299. // Update early out fraction based on narrow phase collector
  300. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  301. }
  302. }
  303. }
  304. }
  305. RShapeCast mShapeCast;
  306. const ShapeCastSettings & mShapeCastSettings;
  307. RVec3 mBaseOffset;
  308. CastShapeCollector & mCollector;
  309. const BodyLockInterface & mBodyLockInterface;
  310. const BodyFilter & mBodyFilter;
  311. const ShapeFilter & mShapeFilter;
  312. };
  313. // Do broadphase test
  314. MyCollector collector(inShapeCast, inShapeCastSettings, inBaseOffset, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  315. mBroadPhaseQuery->CastAABox({ inShapeCast.mShapeWorldBounds, inShapeCast.mDirection }, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  316. }
  317. void NarrowPhaseQuery::CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  318. {
  319. class MyCollector : public CollideShapeBodyCollector
  320. {
  321. public:
  322. MyCollector(const AABox &inBox, TransformedShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  323. CollideShapeBodyCollector(ioCollector),
  324. mBox(inBox),
  325. mCollector(ioCollector),
  326. mBodyLockInterface(inBodyLockInterface),
  327. mBodyFilter(inBodyFilter),
  328. mShapeFilter(inShapeFilter)
  329. {
  330. }
  331. virtual void AddHit(const ResultType &inResult) override
  332. {
  333. // Only test shape if it passes the body filter
  334. if (mBodyFilter.ShouldCollide(inResult))
  335. {
  336. // Lock the body
  337. BodyLockRead lock(mBodyLockInterface, inResult);
  338. 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
  339. {
  340. const Body &body = lock.GetBody();
  341. // Check body filter again now that we've locked the body
  342. if (mBodyFilter.ShouldCollideLocked(body))
  343. {
  344. // Collect the transformed shape
  345. TransformedShape ts = body.GetTransformedShape();
  346. // Notify collector of new body
  347. mCollector.OnBody(body);
  348. // Release the lock now, we have all the info we need in the transformed shape
  349. lock.ReleaseLock();
  350. // Do narrow phase collision check
  351. ts.CollectTransformedShapes(mBox, mCollector, mShapeFilter);
  352. // Notify collector of the end of this body
  353. // We do this before updating the early out fraction so that the collector can still modify it
  354. mCollector.OnBodyEnd();
  355. // Update early out fraction based on narrow phase collector
  356. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  357. }
  358. }
  359. }
  360. }
  361. const AABox & mBox;
  362. TransformedShapeCollector & mCollector;
  363. const BodyLockInterface & mBodyLockInterface;
  364. const BodyFilter & mBodyFilter;
  365. const ShapeFilter & mShapeFilter;
  366. };
  367. // Do broadphase test
  368. MyCollector collector(inBox, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  369. mBroadPhaseQuery->CollideAABox(inBox, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  370. }
  371. JPH_NAMESPACE_END