MutableCompoundShape.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Physics/Collision/Shape/CompoundShape.h>
  5. JPH_NAMESPACE_BEGIN
  6. class CollideShapeSettings;
  7. /// Class that constructs a MutableCompoundShape.
  8. class MutableCompoundShapeSettings final : public CompoundShapeSettings
  9. {
  10. public:
  11. JPH_DECLARE_SERIALIZABLE_VIRTUAL(MutableCompoundShapeSettings)
  12. // See: ShapeSettings
  13. virtual ShapeResult Create() const override;
  14. };
  15. /// A compound shape, sub shapes can be rotated and translated.
  16. /// This shape is optimized for adding / removing and changing the rotation / translation of sub shapes but is less efficient in querying.
  17. /// Shifts all child objects so that they're centered around the center of mass (which needs to be kept up to date by calling AdjustCenterOfMass).
  18. ///
  19. /// Note: If you're using MutableCompoundShapes and are querying data while modifying the shape you'll have a race condition.
  20. /// In this case it is best to create a new MutableCompoundShape and set the new shape on the body using BodyInterface::SetShape. If a
  21. /// query is still working on the old shape, it will have taken a reference and keep the old shape alive until the query finishes.
  22. class MutableCompoundShape final : public CompoundShape
  23. {
  24. public:
  25. JPH_OVERRIDE_NEW_DELETE
  26. /// Constructor
  27. MutableCompoundShape() : CompoundShape(EShapeSubType::MutableCompound) { }
  28. MutableCompoundShape(const MutableCompoundShapeSettings &inSettings, ShapeResult &outResult);
  29. // See Shape::CastRay
  30. virtual bool CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const override;
  31. virtual void CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter = { }) const override;
  32. // See: Shape::CollidePoint
  33. virtual void CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter = { }) const override;
  34. // See Shape::CollectTransformedShapes
  35. virtual void CollectTransformedShapes(const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, const SubShapeIDCreator &inSubShapeIDCreator, TransformedShapeCollector &ioCollector, const ShapeFilter &inShapeFilter) const override;
  36. // See: CompoundShape::GetIntersectingSubShapes
  37. virtual int GetIntersectingSubShapes(const AABox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const override;
  38. // See: CompoundShape::GetIntersectingSubShapes
  39. virtual int GetIntersectingSubShapes(const OrientedBox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const override;
  40. // See Shape
  41. virtual void SaveBinaryState(StreamOut &inStream) const override;
  42. // See Shape::GetStats
  43. virtual Stats GetStats() const override { return Stats(sizeof(*this) + mSubShapes.size() * sizeof(SubShape) + mSubShapeBounds.size() * sizeof(Bounds), 0); }
  44. ///@{
  45. /// @name Mutating shapes. Note that this is not thread safe, so you need to ensure that any bodies that use this shape are locked at the time of modification using BodyLockWrite. After modification you need to call BodyInterface::NotifyShapeChanged to update the broadphase and collision caches.
  46. /// Adding a new shape
  47. /// @return The index of the newly added shape
  48. uint AddShape(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape, uint32 inUserData = 0);
  49. /// Remove a shape by index
  50. void RemoveShape(uint inIndex);
  51. /// Modify the position / orientation of a shape
  52. void ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation);
  53. /// Modify the position / orientation and shape at the same time
  54. void ModifyShape(uint inIndex, Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape);
  55. /// @brief Batch set positions / orientations, this avoids duplicate work due to bounding box calculation.
  56. /// @param inStartIndex Index of first shape to update
  57. /// @param inNumber Number of shapes to update
  58. /// @param inPositions A list of positions with arbitrary stride
  59. /// @param inRotations A list of orientations with arbitrary stride
  60. /// @param inPositionStride The position stride (the number of bytes between the first and second element)
  61. /// @param inRotationStride The orientation stride (the number of bytes between the first and second element)
  62. void ModifyShapes(uint inStartIndex, uint inNumber, const Vec3 *inPositions, const Quat *inRotations, uint inPositionStride = sizeof(Vec3), uint inRotationStride = sizeof(Quat));
  63. /// Recalculate the center of mass and shift all objects so they're centered around it
  64. /// (this needs to be done of dynamic bodies and if the center of mass changes significantly due to adding / removing / repositioning sub shapes or else the simulation will look unnatural)
  65. void AdjustCenterOfMass();
  66. ///@}
  67. // Register shape functions with the registry
  68. static void sRegister();
  69. protected:
  70. // See: Shape::RestoreBinaryState
  71. virtual void RestoreBinaryState(StreamIn &inStream) override;
  72. private:
  73. // Visitor for GetIntersectingSubShapes
  74. template <class BoxType>
  75. struct GetIntersectingSubShapesVisitorMC : public GetIntersectingSubShapesVisitor<BoxType>
  76. {
  77. using GetIntersectingSubShapesVisitor<BoxType>::GetIntersectingSubShapesVisitor;
  78. using Result = UVec4;
  79. JPH_INLINE Result TestBlock(Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ) const
  80. {
  81. return GetIntersectingSubShapesVisitor<BoxType>::TestBounds(inBoundsMinX, inBoundsMinY, inBoundsMinZ, inBoundsMaxX, inBoundsMaxY, inBoundsMaxZ);
  82. }
  83. JPH_INLINE bool ShouldVisitBlock(UVec4Arg inResult) const
  84. {
  85. return inResult.TestAnyTrue();
  86. }
  87. JPH_INLINE bool ShouldVisitSubShape(UVec4Arg inResult, uint inIndexInBlock) const
  88. {
  89. return inResult[inIndexInBlock] != 0;
  90. }
  91. };
  92. /// Get the number of blocks of 4 bounding boxes
  93. inline uint GetNumBlocks() const { return ((uint)mSubShapes.size() + 3) >> 2; }
  94. /// Ensure that the mSubShapeBounds has enough space to store bounding boxes equivalent to the number of shapes in mSubShapes
  95. void EnsureSubShapeBoundsCapacity();
  96. /// Update mSubShapeBounds
  97. /// @param inStartIdx First sub shape to update
  98. /// @param inNumber Number of shapes to update
  99. void CalculateSubShapeBounds(uint inStartIdx, uint inNumber);
  100. /// Calculate mLocalBounds from mSubShapeBounds
  101. void CalculateLocalBounds();
  102. template <class Visitor>
  103. JPH_INLINE void WalkSubShapes(Visitor &ioVisitor) const; ///< Walk the sub shapes and call Visitor::VisitShape for each sub shape encountered
  104. // Helper functions called by CollisionDispatch
  105. static void sCollideCompoundVsShape(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);
  106. static void sCollideShapeVsCompound(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);
  107. static void sCastShapeVsCompound(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector);
  108. struct Bounds
  109. {
  110. Vec4 mMinX;
  111. Vec4 mMinY;
  112. Vec4 mMinZ;
  113. Vec4 mMaxX;
  114. Vec4 mMaxY;
  115. Vec4 mMaxZ;
  116. };
  117. Array<Bounds> mSubShapeBounds; ///< Bounding boxes of all sub shapes in SOA format (in blocks of 4 boxes), MinX 0..3, MinY 0..3, MinZ 0..3, MaxX 0..3, MaxY 0..3, MaxZ 0..3, MinX 4..7, MinY 4..7, ...
  118. };
  119. JPH_NAMESPACE_END