NarrowPhaseQuery.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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 BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter) :
  20. mRay(inRay),
  21. mHit(ioHit),
  22. mBodyInterface(inBodyInterface),
  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. // Collect the transformed shape
  34. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult.mBodyID);
  35. // Do narrow phase collision check
  36. if (ts.CastRay(mRay, mHit))
  37. {
  38. // Test that we didn't find a further hit by accident
  39. JPH_ASSERT(mHit.mFraction >= 0.0f && mHit.mFraction < GetEarlyOutFraction());
  40. // Update early out fraction based on narrow phase collector
  41. UpdateEarlyOutFraction(mHit.mFraction);
  42. }
  43. }
  44. }
  45. RayCast mRay;
  46. RayCastResult & mHit;
  47. const BodyInterface & mBodyInterface;
  48. const BodyFilter & mBodyFilter;
  49. };
  50. // Do broadphase test
  51. MyCollector collector(inRay, ioHit, *mBodyInterface, inBodyFilter);
  52. mBroadPhase->CastRay(inRay, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  53. return ioHit.mFraction <= 1.0f;
  54. }
  55. void NarrowPhaseQuery::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  56. {
  57. JPH_PROFILE_FUNCTION();
  58. class MyCollector : public RayCastBodyCollector
  59. {
  60. public:
  61. MyCollector(const RayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter) :
  62. mRay(inRay),
  63. mRayCastSettings(inRayCastSettings),
  64. mCollector(ioCollector),
  65. mBodyInterface(inBodyInterface),
  66. mBodyFilter(inBodyFilter)
  67. {
  68. UpdateEarlyOutFraction(ioCollector.GetEarlyOutFraction());
  69. }
  70. virtual void AddHit(const ResultType &inResult) override
  71. {
  72. JPH_ASSERT(inResult.mFraction < mCollector.GetEarlyOutFraction(), "This hit should not have been passed on to the collector");
  73. // Only test shape if it passes the body filter
  74. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  75. {
  76. // Collect the transformed shape
  77. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult.mBodyID);
  78. // Do narrow phase collision check
  79. ts.CastRay(mRay, mRayCastSettings, mCollector);
  80. // Update early out fraction based on narrow phase collector
  81. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  82. }
  83. }
  84. RayCast mRay;
  85. RayCastSettings mRayCastSettings;
  86. CastRayCollector & mCollector;
  87. const BodyInterface & mBodyInterface;
  88. const BodyFilter & mBodyFilter;
  89. };
  90. // Do broadphase test
  91. MyCollector collector(inRay, inRayCastSettings, ioCollector, *mBodyInterface, inBodyFilter);
  92. mBroadPhase->CastRay(inRay, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  93. }
  94. void NarrowPhaseQuery::CollidePoint(Vec3Arg inPoint, CollidePointCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  95. {
  96. JPH_PROFILE_FUNCTION();
  97. class MyCollector : public CollideShapeBodyCollector
  98. {
  99. public:
  100. MyCollector(Vec3Arg inPoint, CollidePointCollector &ioCollector, const BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter) :
  101. mPoint(inPoint),
  102. mCollector(ioCollector),
  103. mBodyInterface(inBodyInterface),
  104. mBodyFilter(inBodyFilter)
  105. {
  106. }
  107. virtual void AddHit(const ResultType &inResult) override
  108. {
  109. // Only test shape if it passes the body filter
  110. if (mBodyFilter.ShouldCollide(inResult))
  111. {
  112. // Collect the transformed shape
  113. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult);
  114. // Do narrow phase collision check
  115. ts.CollidePoint(mPoint, mCollector);
  116. // Update early out fraction based on narrow phase collector
  117. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  118. }
  119. }
  120. Vec3 mPoint;
  121. CollidePointCollector & mCollector;
  122. const BodyInterface & mBodyInterface;
  123. const BodyFilter & mBodyFilter;
  124. };
  125. // Do broadphase test
  126. MyCollector collector(inPoint, ioCollector, *mBodyInterface, inBodyFilter);
  127. mBroadPhase->CollidePoint(inPoint, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  128. }
  129. 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
  130. {
  131. JPH_PROFILE_FUNCTION();
  132. class MyCollector : public CollideShapeBodyCollector
  133. {
  134. public:
  135. MyCollector(const Shape *inShape, Vec3Arg inShapeScale, Mat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter) :
  136. mShape(inShape),
  137. mShapeScale(inShapeScale),
  138. mCenterOfMassTransform(inCenterOfMassTransform),
  139. mCollideShapeSettings(inCollideShapeSettings),
  140. mCollector(ioCollector),
  141. mBodyInterface(inBodyInterface),
  142. mBodyFilter(inBodyFilter)
  143. {
  144. }
  145. virtual void AddHit(const ResultType &inResult) override
  146. {
  147. // Only test shape if it passes the body filter
  148. if (mBodyFilter.ShouldCollide(inResult))
  149. {
  150. // Collect the transformed shape
  151. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult);
  152. // Do narrow phase collision check
  153. ts.CollideShape(mShape, mShapeScale, mCenterOfMassTransform, mCollideShapeSettings, mCollector);
  154. // Update early out fraction based on narrow phase collector
  155. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  156. }
  157. }
  158. const Shape * mShape;
  159. Vec3 mShapeScale;
  160. Mat44 mCenterOfMassTransform;
  161. const CollideShapeSettings & mCollideShapeSettings;
  162. CollideShapeCollector & mCollector;
  163. const BodyInterface & mBodyInterface;
  164. const BodyFilter & mBodyFilter;
  165. };
  166. // Calculate bounds for shape and expand by max separation distance
  167. AABox bounds = inShape->GetWorldSpaceBounds(inCenterOfMassTransform, inShapeScale);
  168. bounds.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));
  169. // Do broadphase test
  170. MyCollector collector(inShape, inShapeScale, inCenterOfMassTransform, inCollideShapeSettings, ioCollector, *mBodyInterface, inBodyFilter);
  171. mBroadPhase->CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  172. }
  173. void NarrowPhaseQuery::CastShape(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, CastShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
  174. {
  175. JPH_PROFILE_FUNCTION();
  176. class MyCollector : public CastShapeBodyCollector
  177. {
  178. private:
  179. /// Update early out fraction based on narrow phase collector
  180. inline void PropagateEarlyOutFraction()
  181. {
  182. // The CastShapeCollector uses negative values for penetration depth so we want to clamp to the smallest positive number to keep receiving deeper hits
  183. if (mCollector.ShouldEarlyOut())
  184. ForceEarlyOut();
  185. else
  186. UpdateEarlyOutFraction(max(FLT_MIN, mCollector.GetEarlyOutFraction()));
  187. }
  188. public:
  189. MyCollector(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, CastShapeCollector &ioCollector, const BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
  190. mShapeCast(inShapeCast),
  191. mShapeCastSettings(inShapeCastSettings),
  192. mCollector(ioCollector),
  193. mBodyInterface(inBodyInterface),
  194. mBodyFilter(inBodyFilter),
  195. mShapeFilter(inShapeFilter)
  196. {
  197. PropagateEarlyOutFraction();
  198. }
  199. virtual void AddHit(const ResultType &inResult) override
  200. {
  201. JPH_ASSERT(inResult.mFraction <= max(0.0f, mCollector.GetEarlyOutFraction()), "This hit should not have been passed on to the collector");
  202. // Only test shape if it passes the body filter
  203. if (mBodyFilter.ShouldCollide(inResult.mBodyID))
  204. {
  205. // Collect the transformed shape
  206. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult.mBodyID);
  207. // Do narrow phase collision check
  208. ts.CastShape(mShapeCast, mShapeCastSettings, mCollector, mShapeFilter);
  209. // Update early out fraction based on narrow phase collector
  210. PropagateEarlyOutFraction();
  211. }
  212. }
  213. ShapeCast mShapeCast;
  214. const ShapeCastSettings & mShapeCastSettings;
  215. CastShapeCollector & mCollector;
  216. const BodyInterface & mBodyInterface;
  217. const BodyFilter & mBodyFilter;
  218. const ShapeFilter & mShapeFilter;
  219. };
  220. // Do broadphase test
  221. MyCollector collector(inShapeCast, inShapeCastSettings, ioCollector, *mBodyInterface, inBodyFilter, inShapeFilter);
  222. mBroadPhase->CastAABox({ inShapeCast.mShapeWorldBounds, inShapeCast.mDirection }, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  223. }
  224. void NarrowPhaseQuery::CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
  225. {
  226. class MyCollector : public CollideShapeBodyCollector
  227. {
  228. public:
  229. MyCollector(const AABox &inBox, TransformedShapeCollector &ioCollector, const BodyInterface &inBodyInterface, const BodyFilter &inBodyFilter) :
  230. mBox(inBox),
  231. mCollector(ioCollector),
  232. mBodyInterface(inBodyInterface),
  233. mBodyFilter(inBodyFilter)
  234. {
  235. }
  236. virtual void AddHit(const ResultType &inResult) override
  237. {
  238. // Only test shape if it passes the body filter
  239. if (mBodyFilter.ShouldCollide(inResult))
  240. {
  241. // Collect the transformed shape
  242. TransformedShape ts = mBodyInterface.GetTransformedShape(inResult);
  243. // Do narrow phase collision check
  244. ts.CollectTransformedShapes(mBox, mCollector);
  245. // Update early out fraction based on narrow phase collector
  246. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  247. }
  248. }
  249. const AABox & mBox;
  250. TransformedShapeCollector & mCollector;
  251. const BodyInterface & mBodyInterface;
  252. const BodyFilter & mBodyFilter;
  253. };
  254. // Do broadphase test
  255. MyCollector collector(inBox, ioCollector, *mBodyInterface, inBodyFilter);
  256. mBroadPhase->CollideAABox(inBox, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
  257. }
  258. } // JPH