TransformedShape.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Physics/Collision/ObjectLayer.h>
  5. #include <Physics/Collision/ShapeFilter.h>
  6. #include <Physics/Collision/Shape/Shape.h>
  7. #include <Physics/Collision/Shape/SubShapeID.h>
  8. #include <Physics/Collision/BackFaceMode.h>
  9. #include <Physics/Body/BodyID.h>
  10. namespace JPH {
  11. struct RayCast;
  12. class CollideShapeSettings;
  13. class RayCastResult;
  14. /// Temporary data structure that contains a shape and a transform.
  15. /// This structure can be obtained from a body (e.g. after a broad phase query) under lock protection.
  16. /// The lock can then be released and collision detection operations can be safely performed since
  17. /// the class takes a reference on the shape and does not use anything from the body anymore.
  18. class TransformedShape
  19. {
  20. public:
  21. /// Constructor
  22. TransformedShape() = default;
  23. TransformedShape(Vec3Arg inPositionCOM, QuatArg inRotation, const Shape *inShape, const BodyID &inBodyID, const SubShapeIDCreator &inSubShapeIDCreator = SubShapeIDCreator()) : mShapePositionCOM(inPositionCOM), mShapeRotation(inRotation), mShape(inShape), mBodyID(inBodyID), mSubShapeIDCreator(inSubShapeIDCreator) { }
  24. /// Cast a ray, returns true if it finds a hit closer than ioHit.mFraction and updates ioHit in that case.
  25. bool CastRay(const RayCast &inRay, RayCastResult &ioHit) const;
  26. /// Cast a ray, allows collecting multiple hits
  27. void CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector) const;
  28. /// Check if inPoint is inside any shapes. For this tests all shapes are treated as if they were solid.
  29. /// For a mesh shape, this test will only provide sensible information if the mesh is a closed manifold.
  30. /// For each shape that collides, ioCollector will receive a hit
  31. void CollidePoint(Vec3Arg inPoint, CollidePointCollector &ioCollector) const;
  32. /// Collide a shape and report any hits to ioCollector
  33. void CollideShape(const Shape *inShape, Vec3Arg inShapeScale, Mat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector) const;
  34. /// Cast a shape and report any hits to ioCollector
  35. void CastShape(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, CastShapeCollector &ioCollector, const ShapeFilter &inShapeFilter = { }) const;
  36. /// Collect the leaf transformed shapes of all leaf shapes of this shape
  37. /// inBox is the world space axis aligned box which leaf shapes should collide with
  38. void CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector) const;
  39. /// Use the context from Shape
  40. using GetTrianglesContext = Shape::GetTrianglesContext;
  41. /// To start iterating over triangles, call this function first.
  42. /// ioContext is a temporary buffer and should remain untouched until the last call to GetTrianglesNext.
  43. /// inBox is the world space bounding in which you want to get the triangles.
  44. /// To get the actual triangles call GetTrianglesNext.
  45. void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox) const;
  46. /// Call this repeatedly to get all triangles in the box.
  47. /// outTriangleVertices should be large enough to hold 3 * inMaxTriangleRequested entries
  48. /// outMaterials (if it is not null) should contain inMaxTrianglesRequested entries
  49. /// The function returns the amount of triangles that it found (which will be <= inMaxTrianglesRequested), or 0 if there are no more triangles.
  50. /// Note that the function can return a value < inMaxTrianglesRequested and still have more triangles to process (triangles can be returned in blocks)
  51. /// Note that the function may return triangles outside of the requested box, only coarse culling is performed on the returned triangles
  52. int GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials = nullptr) const;
  53. /// Get/set the scale of the shape as a Vec3
  54. inline Vec3 GetShapeScale() const { return Vec3::sLoadFloat3Unsafe(mShapeScale); }
  55. inline void SetShapeScale(Vec3Arg inScale) { inScale.StoreFloat3(&mShapeScale); }
  56. /// Calculates the transform for this shapes's center of mass (excluding scale)
  57. inline const Mat44 GetCenterOfMassTransform() const { return Mat44::sRotationTranslation(mShapeRotation, mShapePositionCOM); }
  58. /// Calculates the inverse of the transform for this shape's center of mass (excluding scale)
  59. inline const Mat44 GetInverseCenterOfMassTransform() const { return Mat44::sInverseRotationTranslation(mShapeRotation, mShapePositionCOM); }
  60. /// Sets the world transform (including scale) of this transformed shape (not from the center of mass but in the space the shape was created)
  61. inline void SetWorldTransform(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inScale)
  62. {
  63. mShapePositionCOM = inPosition + inRotation * (inScale * mShape->GetCenterOfMass());
  64. mShapeRotation = inRotation;
  65. SetShapeScale(inScale);
  66. }
  67. /// Sets the world transform (including scale) of this transformed shape (not from the center of mass but in the space the shape was created)
  68. inline void SetWorldTransform(Mat44Arg inTransform)
  69. {
  70. Vec3 scale;
  71. Mat44 rot_trans = inTransform.Decompose(scale);
  72. SetWorldTransform(rot_trans.GetTranslation(), rot_trans.GetRotation().GetQuaternion(), scale);
  73. }
  74. /// Calculates the world transform including scale of this shape (not from the center of mass but in the space the shape was created)
  75. inline const Mat44 GetWorldTransform() const
  76. {
  77. Mat44 transform = Mat44::sRotation(mShapeRotation) * Mat44::sScale(GetShapeScale());
  78. transform.SetTranslation(mShapePositionCOM - transform.Multiply3x3(mShape->GetCenterOfMass()));
  79. return transform;
  80. }
  81. /// Get the world space bounding box for this transformed shape
  82. AABox GetWorldSpaceBounds() const { return mShape != nullptr? mShape->GetWorldSpaceBounds(GetCenterOfMassTransform(), GetShapeScale()) : AABox(); }
  83. /// Make inSubShapeID relative to mShape. When mSubShapeIDCreator is not empty, this is needed in order to get the correct path to the sub shape.
  84. inline SubShapeID MakeSubShapeIDRelativeToShape(const SubShapeID &inSubShapeID) const
  85. {
  86. // Take off the sub shape ID part that comes from mSubShapeIDCreator and validate that it is the same
  87. SubShapeID sub_shape_id;
  88. uint num_bits_written = mSubShapeIDCreator.GetNumBitsWritten();
  89. JPH_IF_ENABLE_ASSERTS(uint32 root_id =) inSubShapeID.PopID(num_bits_written, sub_shape_id);
  90. JPH_ASSERT(root_id == (mSubShapeIDCreator.GetID().GetValue() & ((1 << num_bits_written) - 1)));
  91. return sub_shape_id;
  92. }
  93. /// Get surface normal of a particular sub shape and its world space surface position on this body
  94. inline Vec3 GetWorldSpaceSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inPosition) const
  95. {
  96. Mat44 inv_com = GetInverseCenterOfMassTransform();
  97. Vec3 scale = GetShapeScale(); // See comment at ScaledShape::GetSurfaceNormal for the math behind the scaling of the normal
  98. return inv_com.Multiply3x3Transposed(mShape->GetSurfaceNormal(MakeSubShapeIDRelativeToShape(inSubShapeID), (inv_com * inPosition) / scale) / scale).Normalized();
  99. }
  100. /// Get material of a particular sub shape
  101. inline const PhysicsMaterial *GetMaterial(const SubShapeID &inSubShapeID) const
  102. {
  103. return mShape->GetMaterial(MakeSubShapeIDRelativeToShape(inSubShapeID));
  104. }
  105. /// Get the user data of a particular sub shape
  106. inline uint32 GetSubShapeUserData(const SubShapeID &inSubShapeID) const
  107. {
  108. return mShape->GetSubShapeUserData(MakeSubShapeIDRelativeToShape(inSubShapeID));
  109. }
  110. /// Get the direct child sub shape and its transform for a sub shape ID.
  111. /// @param inSubShapeID Sub shape ID that indicates the path to the leaf shape
  112. /// @param outRemainder The remainder of the sub shape ID after removing the sub shape
  113. /// @return Direct child sub shape and its transform, note that the body ID and sub shape ID will be invalid
  114. TransformedShape GetSubShapeTransformedShape(const SubShapeID &inSubShapeID, SubShapeID &outRemainder) const
  115. {
  116. return mShape->GetSubShapeTransformedShape(inSubShapeID, mShapePositionCOM, mShapeRotation, GetShapeScale(), outRemainder);
  117. }
  118. /// Helper function to return the body id from a transformed shape. If the transformed shape is null an invalid body ID will be returned.
  119. inline static BodyID sGetBodyID(const TransformedShape *inTS) { return inTS != nullptr? inTS->mBodyID : BodyID(); }
  120. Vec3 mShapePositionCOM; ///< Center of mass world position of the shape
  121. Quat mShapeRotation; ///< Rotation of the shape
  122. RefConst<Shape> mShape; ///< The shape itself
  123. Float3 mShapeScale { 1, 1, 1 }; ///< Not stored as Vec3 to get a nicely packed structure
  124. BodyID mBodyID; ///< Optional body ID from which this shape comes
  125. SubShapeIDCreator mSubShapeIDCreator; ///< Optional sub shape ID creator for the shape (can be used when expanding compound shapes into multiple transformed shapes)
  126. };
  127. static_assert(sizeof(TransformedShape) == 64, "Not properly packed");
  128. static_assert(alignof(TransformedShape) == 16, "Not properly aligned");
  129. } // JPH