NarrowPhaseQuery.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/Collision/NarrowPhaseQuery.h>
  5. #include <Physics/Collision/CollisionDispatch.h>
  6. #include <Physics/Collision/RayCast.h>
  7. #include <Physics/Collision/AABoxCast.h>
  8. #include <Physics/Collision/ShapeCast.h>
  9. #include <Physics/Collision/CollideShape.h>
  10. #include <Physics/Collision/CollisionCollectorImpl.h>
  11. #include <Physics/Collision/CastResult.h>
  12. namespace JPH {
  13. bool NarrowPhaseQuery::CastRay(const RayCast &inRay, RayCastResult &ioHit, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  14. {
  15. JPH_PROFILE_FUNCTION();
  16. class MyCollector : public RayCastBodyCollector
  17. {
  18. public:
  19. MyCollector(const RayCast &inRay, RayCastResult &ioHit, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  20. mRay(inRay),
  21. mHit(ioHit),
  22. mBodyLockInterface(inBodyLockInterface),
  23. mBodyFilter(inBodyFilter)
  24. {
  25. UpdateEarlyOutFraction(ioHit.mFraction);
  26. }
  27. virtual void AddHit(const ResultType &inResult) override
  28. {
  29. JPH_ASSERT(inResult.mFraction < mHit.mFraction, "This hit should not have been passed on to the collector");
  30. // Only test shape if it passes the body filter
  31. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  32. {
  33. // Lock the body
  34. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  35. if (lock.Succeeded())
  36. {
  37. // Collect the transformed shape
  38. TransformedShape ts = lock.GetBody().GetTransformedShape();
  39. // Do narrow phase collision check
  40. if (ts.CastRay(mRay, mHit))
  41. {
  42. // Test that we didn't find a further hit by accident
  43. JPH_ASSERT(mHit.mFraction >= 0.0f && mHit.mFraction < GetEarlyOutFraction());
  44. // Update early out fraction based on narrow phase collector
  45. UpdateEarlyOutFraction(mHit.mFraction);
  46. }
  47. }
  48. }
  49. }
  50. RayCast mRay;
  51. RayCastResult & mHit;
  52. const BodyLockInterface & mBodyLockInterface;
  53. const BodyFilter & mBodyFilter;
  54. };
  55. // Do broadphase test
  56. MyCollector collector(inRay, ioHit, *mBodyLockInterface, inBodyFilter);
  57. mBroadPhase->CastRay(inRay, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  58. return ioHit.mFraction <= 1.0f;
  59. }
  60. void NarrowPhaseQuery::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  61. {
  62. JPH_PROFILE_FUNCTION();
  63. class MyCollector : public RayCastBodyCollector
  64. {
  65. public:
  66. MyCollector(const RayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  67. mRay(inRay),
  68. mRayCastSettings(inRayCastSettings),
  69. mCollector(ioCollector),
  70. mBodyLockInterface(inBodyLockInterface),
  71. mBodyFilter(inBodyFilter)
  72. {
  73. UpdateEarlyOutFraction(ioCollector.GetEarlyOutFraction());
  74. }
  75. virtual void AddHit(const ResultType &inResult) override
  76. {
  77. JPH_ASSERT(inResult.mFraction < mCollector.GetEarlyOutFraction(), "This hit should not have been passed on to the collector");
  78. // Only test shape if it passes the body filter
  79. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  80. {
  81. // Lock the body
  82. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  83. if (lock.Succeeded())
  84. {
  85. const Body &body = lock.GetBody();
  86. // Collect the transformed shape
  87. TransformedShape ts = body.GetTransformedShape();
  88. // Notify collector of new body
  89. mCollector.OnBody(body);
  90. // Do narrow phase collision check
  91. ts.CastRay(mRay, mRayCastSettings, mCollector);
  92. // Update early out fraction based on narrow phase collector
  93. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  94. }
  95. }
  96. }
  97. RayCast mRay;
  98. RayCastSettings mRayCastSettings;
  99. CastRayCollector & mCollector;
  100. const BodyLockInterface & mBodyLockInterface;
  101. const BodyFilter & mBodyFilter;
  102. };
  103. // Do broadphase test
  104. MyCollector collector(inRay, inRayCastSettings, ioCollector, *mBodyLockInterface, inBodyFilter);
  105. mBroadPhase->CastRay(inRay, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  106. }
  107. void NarrowPhaseQuery::CollidePoint(Vec3Arg inPoint, CollidePointCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  108. {
  109. JPH_PROFILE_FUNCTION();
  110. class MyCollector : public CollideShapeBodyCollector
  111. {
  112. public:
  113. MyCollector(Vec3Arg inPoint, CollidePointCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  114. mPoint(inPoint),
  115. mCollector(ioCollector),
  116. mBodyLockInterface(inBodyLockInterface),
  117. mBodyFilter(inBodyFilter)
  118. {
  119. }
  120. virtual void AddHit(const ResultType &inResult) override
  121. {
  122. // Only test shape if it passes the body filter
  123. if (mBodyFilter.ShouldCollide(inResult))
  124. {
  125. // Lock the body
  126. BodyLockRead lock(mBodyLockInterface, inResult);
  127. if (lock.Succeeded())
  128. {
  129. const Body &body = lock.GetBody();
  130. // Collect the transformed shape
  131. TransformedShape ts = body.GetTransformedShape();
  132. // Notify collector of new body
  133. mCollector.OnBody(body);
  134. // Do narrow phase collision check
  135. ts.CollidePoint(mPoint, mCollector);
  136. // Update early out fraction based on narrow phase collector
  137. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  138. }
  139. }
  140. }
  141. Vec3 mPoint;
  142. CollidePointCollector & mCollector;
  143. const BodyLockInterface & mBodyLockInterface;
  144. const BodyFilter & mBodyFilter;
  145. };
  146. // Do broadphase test
  147. MyCollector collector(inPoint, ioCollector, *mBodyLockInterface, inBodyFilter);
  148. mBroadPhase->CollidePoint(inPoint, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  149. }
  150. void NarrowPhaseQuery::CollideShape(const Shape *inShape, Vec3Arg inShapeScale, Mat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  151. {
  152. JPH_PROFILE_FUNCTION();
  153. class MyCollector : public CollideShapeBodyCollector
  154. {
  155. public:
  156. MyCollector(const Shape *inShape, Vec3Arg inShapeScale, Mat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  157. mShape(inShape),
  158. mShapeScale(inShapeScale),
  159. mCenterOfMassTransform(inCenterOfMassTransform),
  160. mCollideShapeSettings(inCollideShapeSettings),
  161. mCollector(ioCollector),
  162. mBodyLockInterface(inBodyLockInterface),
  163. mBodyFilter(inBodyFilter)
  164. {
  165. }
  166. virtual void AddHit(const ResultType &inResult) override
  167. {
  168. // Only test shape if it passes the body filter
  169. if (mBodyFilter.ShouldCollide(inResult))
  170. {
  171. // Lock the body
  172. BodyLockRead lock(mBodyLockInterface, inResult);
  173. if (lock.Succeeded())
  174. {
  175. const Body &body = lock.GetBody();
  176. // Collect the transformed shape
  177. TransformedShape ts = body.GetTransformedShape();
  178. // Notify collector of new body
  179. mCollector.OnBody(body);
  180. // Do narrow phase collision check
  181. ts.CollideShape(mShape, mShapeScale, mCenterOfMassTransform, mCollideShapeSettings, mCollector);
  182. // Update early out fraction based on narrow phase collector
  183. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  184. }
  185. }
  186. }
  187. const Shape * mShape;
  188. Vec3 mShapeScale;
  189. Mat44 mCenterOfMassTransform;
  190. const CollideShapeSettings & mCollideShapeSettings;
  191. CollideShapeCollector & mCollector;
  192. const BodyLockInterface & mBodyLockInterface;
  193. const BodyFilter & mBodyFilter;
  194. };
  195. // Calculate bounds for shape and expand by max separation distance
  196. AABox bounds = inShape->GetWorldSpaceBounds(inCenterOfMassTransform, inShapeScale);
  197. bounds.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));
  198. // Do broadphase test
  199. MyCollector collector(inShape, inShapeScale, inCenterOfMassTransform, inCollideShapeSettings, ioCollector, *mBodyLockInterface, inBodyFilter);
  200. mBroadPhase->CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  201. }
  202. void NarrowPhaseQuery::CastShape(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, CastShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  203. {
  204. JPH_PROFILE_FUNCTION();
  205. class MyCollector : public CastShapeBodyCollector
  206. {
  207. private:
  208. /// Update early out fraction based on narrow phase collector
  209. inline void PropagateEarlyOutFraction()
  210. {
  211. // The CastShapeCollector uses negative values for penetration depth so we want to clamp to the smallest positive number to keep receiving deeper hits
  212. if (mCollector.ShouldEarlyOut())
  213. ForceEarlyOut();
  214. else
  215. UpdateEarlyOutFraction(max(FLT_MIN, mCollector.GetEarlyOutFraction()));
  216. }
  217. public:
  218. MyCollector(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, CastShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  219. mShapeCast(inShapeCast),
  220. mShapeCastSettings(inShapeCastSettings),
  221. mCollector(ioCollector),
  222. mBodyLockInterface(inBodyLockInterface),
  223. mBodyFilter(inBodyFilter),
  224. mShapeFilter(inShapeFilter)
  225. {
  226. PropagateEarlyOutFraction();
  227. }
  228. virtual void AddHit(const ResultType &inResult) override
  229. {
  230. JPH_ASSERT(inResult.mFraction <= max(0.0f, mCollector.GetEarlyOutFraction()), "This hit should not have been passed on to the collector");
  231. // Only test shape if it passes the body filter
  232. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  233. {
  234. // Lock the body
  235. BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
  236. if (lock.Succeeded())
  237. {
  238. const Body &body = lock.GetBody();
  239. // Collect the transformed shape
  240. TransformedShape ts = body.GetTransformedShape();
  241. // Notify collector of new body
  242. mCollector.OnBody(body);
  243. // Do narrow phase collision check
  244. ts.CastShape(mShapeCast, mShapeCastSettings, mCollector, mShapeFilter);
  245. // Update early out fraction based on narrow phase collector
  246. PropagateEarlyOutFraction();
  247. }
  248. }
  249. }
  250. ShapeCast mShapeCast;
  251. const ShapeCastSettings & mShapeCastSettings;
  252. CastShapeCollector & mCollector;
  253. const BodyLockInterface & mBodyLockInterface;
  254. const BodyFilter & mBodyFilter;
  255. const ShapeFilter & mShapeFilter;
  256. };
  257. // Do broadphase test
  258. MyCollector collector(inShapeCast, inShapeCastSettings, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
  259. mBroadPhase->CastAABox({ inShapeCast.mShapeWorldBounds, inShapeCast.mDirection }, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  260. }
  261. void NarrowPhaseQuery::CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  262. {
  263. class MyCollector : public CollideShapeBodyCollector
  264. {
  265. public:
  266. MyCollector(const AABox &inBox, TransformedShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
  267. mBox(inBox),
  268. mCollector(ioCollector),
  269. mBodyLockInterface(inBodyLockInterface),
  270. mBodyFilter(inBodyFilter)
  271. {
  272. }
  273. virtual void AddHit(const ResultType &inResult) override
  274. {
  275. // Only test shape if it passes the body filter
  276. if (mBodyFilter.ShouldCollide(inResult))
  277. {
  278. // Lock the body
  279. BodyLockRead lock(mBodyLockInterface, inResult);
  280. if (lock.Succeeded())
  281. {
  282. const Body &body = lock.GetBody();
  283. // Collect the transformed shape
  284. TransformedShape ts = body.GetTransformedShape();
  285. // Notify collector of new body
  286. mCollector.OnBody(body);
  287. // Do narrow phase collision check
  288. ts.CollectTransformedShapes(mBox, mCollector);
  289. // Update early out fraction based on narrow phase collector
  290. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  291. }
  292. }
  293. }
  294. const AABox & mBox;
  295. TransformedShapeCollector & mCollector;
  296. const BodyLockInterface & mBodyLockInterface;
  297. const BodyFilter & mBodyFilter;
  298. };
  299. // Do broadphase test
  300. MyCollector collector(inBox, ioCollector, *mBodyLockInterface, inBodyFilter);
  301. mBroadPhase->CollideAABox(inBox, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  302. }
  303. } // JPH