CollideShapeVsShapePerLeaf.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Physics/Collision/CollideShape.h>
  6. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  7. #include <Jolt/Core/STLLocalAllocator.h>
  8. JPH_NAMESPACE_BEGIN
  9. /// Collide 2 shapes and returns at most 1 hit per leaf shape pairs that overlapping. This can be used when not all contacts between the shapes are needed.
  10. /// E.g. when testing a compound with 2 MeshShapes A and B against a compound with 2 SphereShapes C and D, then at most you'll get 4 collisions: AC, AD, BC, BD.
  11. /// The default CollisionDispatch::sCollideShapeVsShape function would return all intersecting triangles in A against C, all in B against C etc.
  12. /// @param inShape1 The first shape
  13. /// @param inShape2 The second shape
  14. /// @param inScale1 Local space scale of shape 1 (scales relative to its center of mass)
  15. /// @param inScale2 Local space scale of shape 2 (scales relative to its center of mass)
  16. /// @param inCenterOfMassTransform1 Transform to transform center of mass of shape 1 into world space
  17. /// @param inCenterOfMassTransform2 Transform to transform center of mass of shape 2 into world space
  18. /// @param inSubShapeIDCreator1 Class that tracks the current sub shape ID for shape 1
  19. /// @param inSubShapeIDCreator2 Class that tracks the current sub shape ID for shape 2
  20. /// @param inCollideShapeSettings Options for the CollideShape test
  21. /// @param ioCollector The collector that receives the results.
  22. /// @param inShapeFilter allows selectively disabling collisions between pairs of (sub) shapes.
  23. /// @tparam LeafCollector The type of the collector that will be used to collect hits between leaf pairs. Must be either AnyHitCollisionCollector<CollideShapeCollector> to get any hit (cheapest) or ClosestHitCollisionCollector<CollideShapeCollector> to get the deepest hit (more expensive).
  24. template <class LeafCollector>
  25. void CollideShapeVsShapePerLeaf(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, const ShapeFilter &inShapeFilter = { })
  26. {
  27. // Tracks information we need about a leaf shape
  28. struct LeafShape
  29. {
  30. LeafShape() = default;
  31. LeafShape(const AABox &inBounds, Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const Shape *inShape, const SubShapeIDCreator &inSubShapeIDCreator) :
  32. mBounds(inBounds),
  33. mCenterOfMassTransform(inCenterOfMassTransform),
  34. mScale(inScale),
  35. mShape(inShape),
  36. mSubShapeIDCreator(inSubShapeIDCreator)
  37. {
  38. }
  39. AABox mBounds;
  40. Mat44 mCenterOfMassTransform;
  41. Vec3 mScale;
  42. const Shape * mShape;
  43. SubShapeIDCreator mSubShapeIDCreator;
  44. };
  45. constexpr uint cMaxLocalLeafShapes = 32;
  46. // A collector that stores the information we need from a leaf shape in an array that is usually on the stack but can fall back to the heap if needed
  47. class MyCollector : public TransformedShapeCollector
  48. {
  49. public:
  50. MyCollector()
  51. {
  52. mHits.reserve(cMaxLocalLeafShapes);
  53. }
  54. void AddHit(const TransformedShape &inShape) override
  55. {
  56. mHits.emplace_back(inShape.GetWorldSpaceBounds(), inShape.GetCenterOfMassTransform().ToMat44(), inShape.GetShapeScale(), inShape.mShape, inShape.mSubShapeIDCreator);
  57. }
  58. Array<LeafShape, STLLocalAllocator<LeafShape, cMaxLocalLeafShapes>> mHits;
  59. };
  60. // Get bounds of both shapes
  61. AABox bounds1 = inShape1->GetWorldSpaceBounds(inCenterOfMassTransform1, inScale1);
  62. AABox bounds2 = inShape2->GetWorldSpaceBounds(inCenterOfMassTransform2, inScale2);
  63. // Get leaf shapes that overlap with the bounds of the other shape
  64. MyCollector leaf_shapes1, leaf_shapes2;
  65. inShape1->CollectTransformedShapes(bounds2, inCenterOfMassTransform1.GetTranslation(), inCenterOfMassTransform1.GetQuaternion(), inScale1, inSubShapeIDCreator1, leaf_shapes1, inShapeFilter);
  66. inShape2->CollectTransformedShapes(bounds1, inCenterOfMassTransform2.GetTranslation(), inCenterOfMassTransform2.GetQuaternion(), inScale2, inSubShapeIDCreator2, leaf_shapes2, inShapeFilter);
  67. // Now test each leaf shape against each other leaf
  68. for (const LeafShape &leaf1 : leaf_shapes1.mHits)
  69. for (const LeafShape &leaf2 : leaf_shapes2.mHits)
  70. if (leaf1.mBounds.Overlaps(leaf2.mBounds))
  71. {
  72. // Use the leaf collector to collect max 1 hit for this pair and pass it on to ioCollector
  73. LeafCollector collector;
  74. CollisionDispatch::sCollideShapeVsShape(leaf1.mShape, leaf2.mShape, leaf1.mScale, leaf2.mScale, leaf1.mCenterOfMassTransform, leaf2.mCenterOfMassTransform, leaf1.mSubShapeIDCreator, leaf2.mSubShapeIDCreator, inCollideShapeSettings, collector, inShapeFilter);
  75. if (collector.HadHit())
  76. ioCollector.AddHit(collector.mHit);
  77. }
  78. }
  79. JPH_NAMESPACE_END