CollideShapeVsShapePerLeaf.h 4.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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/Physics/Collision/TransformedShape.h>
  8. #include <Jolt/Core/STLLocalAllocator.h>
  9. JPH_NAMESPACE_BEGIN
  10. /// 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.
  11. /// 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.
  12. /// The default CollisionDispatch::sCollideShapeVsShape function would return all intersecting triangles in A against C, all in B against C etc.
  13. /// @param inShape1 The first shape
  14. /// @param inShape2 The second shape
  15. /// @param inScale1 Local space scale of shape 1 (scales relative to its center of mass)
  16. /// @param inScale2 Local space scale of shape 2 (scales relative to its center of mass)
  17. /// @param inCenterOfMassTransform1 Transform to transform center of mass of shape 1 into world space
  18. /// @param inCenterOfMassTransform2 Transform to transform center of mass of shape 2 into world space
  19. /// @param inSubShapeIDCreator1 Class that tracks the current sub shape ID for shape 1
  20. /// @param inSubShapeIDCreator2 Class that tracks the current sub shape ID for shape 2
  21. /// @param inCollideShapeSettings Options for the CollideShape test
  22. /// @param ioCollector The collector that receives the results.
  23. /// @param inShapeFilter allows selectively disabling collisions between pairs of (sub) shapes.
  24. /// @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).
  25. template <class LeafCollector>
  26. 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 = { })
  27. {
  28. // Tracks information we need about a leaf shape
  29. struct LeafShape
  30. {
  31. LeafShape() = default;
  32. LeafShape(const AABox &inBounds, Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const Shape *inShape, const SubShapeIDCreator &inSubShapeIDCreator) :
  33. mBounds(inBounds),
  34. mCenterOfMassTransform(inCenterOfMassTransform),
  35. mScale(inScale),
  36. mShape(inShape),
  37. mSubShapeIDCreator(inSubShapeIDCreator)
  38. {
  39. }
  40. AABox mBounds;
  41. Mat44 mCenterOfMassTransform;
  42. Vec3 mScale;
  43. const Shape * mShape;
  44. SubShapeIDCreator mSubShapeIDCreator;
  45. };
  46. constexpr uint cMaxLocalLeafShapes = 32;
  47. // 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
  48. class MyCollector : public TransformedShapeCollector
  49. {
  50. public:
  51. MyCollector()
  52. {
  53. mHits.reserve(cMaxLocalLeafShapes);
  54. }
  55. void AddHit(const TransformedShape &inShape) override
  56. {
  57. mHits.emplace_back(inShape.GetWorldSpaceBounds(), inShape.GetCenterOfMassTransform().ToMat44(), inShape.GetShapeScale(), inShape.mShape, inShape.mSubShapeIDCreator);
  58. }
  59. Array<LeafShape, STLLocalAllocator<LeafShape, cMaxLocalLeafShapes>> mHits;
  60. };
  61. // Get bounds of both shapes
  62. AABox bounds1 = inShape1->GetWorldSpaceBounds(inCenterOfMassTransform1, inScale1);
  63. AABox bounds2 = inShape2->GetWorldSpaceBounds(inCenterOfMassTransform2, inScale2);
  64. // Get leaf shapes that overlap with the bounds of the other shape
  65. MyCollector leaf_shapes1, leaf_shapes2;
  66. inShape1->CollectTransformedShapes(bounds2, inCenterOfMassTransform1.GetTranslation(), inCenterOfMassTransform1.GetQuaternion(), inScale1, inSubShapeIDCreator1, leaf_shapes1, inShapeFilter);
  67. inShape2->CollectTransformedShapes(bounds1, inCenterOfMassTransform2.GetTranslation(), inCenterOfMassTransform2.GetQuaternion(), inScale2, inSubShapeIDCreator2, leaf_shapes2, inShapeFilter);
  68. // Now test each leaf shape against each other leaf
  69. for (const LeafShape &leaf1 : leaf_shapes1.mHits)
  70. for (const LeafShape &leaf2 : leaf_shapes2.mHits)
  71. if (leaf1.mBounds.Overlaps(leaf2.mBounds))
  72. {
  73. // Use the leaf collector to collect max 1 hit for this pair and pass it on to ioCollector
  74. LeafCollector collector;
  75. CollisionDispatch::sCollideShapeVsShape(leaf1.mShape, leaf2.mShape, leaf1.mScale, leaf2.mScale, leaf1.mCenterOfMassTransform, leaf2.mCenterOfMassTransform, leaf1.mSubShapeIDCreator, leaf2.mSubShapeIDCreator, inCollideShapeSettings, collector, inShapeFilter);
  76. if (collector.HadHit())
  77. ioCollector.AddHit(collector.mHit);
  78. }
  79. }
  80. JPH_NAMESPACE_END