CompoundShape.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Physics/Collision/Shape/Shape.h>
  5. #include <Jolt/Physics/Collision/Shape/ScaleHelpers.h>
  6. #include <Jolt/Physics/Collision/Shape/SubShapeID.h>
  7. JPH_NAMESPACE_BEGIN
  8. class CollideShapeSettings;
  9. class OrientedBox;
  10. /// Base class settings to construct a compound shape
  11. class CompoundShapeSettings : public ShapeSettings
  12. {
  13. public:
  14. JPH_DECLARE_SERIALIZABLE_ABSTRACT(CompoundShapeSettings)
  15. /// Constructor. Use AddShape to add the parts.
  16. CompoundShapeSettings() = default;
  17. /// Add a shape to the compound.
  18. void AddShape(Vec3Arg inPosition, QuatArg inRotation, const ShapeSettings *inShape, uint32 inUserData = 0);
  19. /// Add a shape to the compound. Variant that uses a concrete shape, which means this object cannot be serialized.
  20. void AddShape(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape, uint32 inUserData = 0);
  21. struct SubShapeSettings
  22. {
  23. JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(SubShapeSettings)
  24. RefConst<ShapeSettings> mShape; ///< Sub shape (either this or mShapePtr needs to be filled up)
  25. RefConst<Shape> mShapePtr; ///< Sub shape (either this or mShape needs to be filled up)
  26. Vec3 mPosition; ///< Position of the sub shape
  27. Quat mRotation; ///< Rotation of the sub shape
  28. uint32 mUserData = 0; ///< User data value (can be used by the application for any purpose)
  29. };
  30. using SubShapes = Array<SubShapeSettings>;
  31. SubShapes mSubShapes;
  32. };
  33. /// Base class for a compound shape
  34. class CompoundShape : public Shape
  35. {
  36. public:
  37. JPH_OVERRIDE_NEW_DELETE
  38. /// Constructor
  39. explicit CompoundShape(EShapeSubType inSubType) : Shape(EShapeType::Compound, inSubType) { }
  40. CompoundShape(EShapeSubType inSubType, const ShapeSettings &inSettings, ShapeResult &outResult) : Shape(EShapeType::Compound, inSubType, inSettings, outResult) { }
  41. // See Shape::GetCenterOfMass
  42. virtual Vec3 GetCenterOfMass() const override { return mCenterOfMass; }
  43. // See Shape::MustBeStatic
  44. virtual bool MustBeStatic() const override;
  45. // See Shape::GetLocalBounds
  46. virtual AABox GetLocalBounds() const override { return mLocalBounds; }
  47. // See Shape::GetSubShapeIDBitsRecursive
  48. virtual uint GetSubShapeIDBitsRecursive() const override;
  49. // See Shape::GetWorldSpaceBounds
  50. virtual AABox GetWorldSpaceBounds(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const override;
  51. // See Shape::GetInnerRadius
  52. virtual float GetInnerRadius() const override { return mInnerRadius; }
  53. // See Shape::GetMassProperties
  54. virtual MassProperties GetMassProperties() const override;
  55. // See Shape::GetMaterial
  56. virtual const PhysicsMaterial * GetMaterial(const SubShapeID &inSubShapeID) const override;
  57. // See Shape::GetSubShapeUserData
  58. virtual uint64 GetSubShapeUserData(const SubShapeID &inSubShapeID) const override;
  59. // See Shape::GetSubShapeTransformedShape
  60. virtual TransformedShape GetSubShapeTransformedShape(const SubShapeID &inSubShapeID, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, SubShapeID &outRemainder) const override;
  61. // See Shape::GetSurfaceNormal
  62. virtual Vec3 GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocalSurfacePosition) const override;
  63. // See Shape::GetSupportingFace
  64. virtual void GetSupportingFace(const SubShapeID &inSubShapeID, Vec3Arg inDirection, Vec3Arg inScale, Mat44Arg inCenterOfMassTransform, SupportingFace &outVertices) const override;
  65. // See Shape::GetSubmergedVolume
  66. virtual void GetSubmergedVolume(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const Plane &inSurface, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outCenterOfBuoyancy) const override;
  67. #ifdef JPH_DEBUG_RENDERER
  68. // See Shape::Draw
  69. virtual void Draw(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const override;
  70. // See Shape::DrawGetSupportFunction
  71. virtual void DrawGetSupportFunction(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inDrawSupportDirection) const override;
  72. // See Shape::DrawGetSupportingFace
  73. virtual void DrawGetSupportingFace(DebugRenderer *inRenderer, Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const override;
  74. #endif // JPH_DEBUG_RENDERER
  75. // See Shape::TransformShape
  76. virtual void TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const override;
  77. // See Shape::GetTrianglesStart
  78. virtual void GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const override { JPH_ASSERT(false, "Cannot call on non-leaf shapes, use CollectTransformedShapes to collect the leaves first!"); }
  79. // See Shape::GetTrianglesNext
  80. virtual int GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials = nullptr) const override { JPH_ASSERT(false, "Cannot call on non-leaf shapes, use CollectTransformedShapes to collect the leaves first!"); return 0; }
  81. /// Get which sub shape's bounding boxes overlap with an axis aligned box
  82. /// @param inBox The axis aligned box to test against (relative to the center of mass of this shape)
  83. /// @param outSubShapeIndices Buffer where to place the indices of the sub shapes that intersect
  84. /// @param inMaxSubShapeIndices How many indices will fit in the buffer (normally you'd provide a buffer of GetNumSubShapes() indices)
  85. /// @return How many indices were placed in outSubShapeIndices
  86. virtual int GetIntersectingSubShapes(const AABox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const = 0;
  87. /// Get which sub shape's bounding boxes overlap with an axis aligned box
  88. /// @param inBox The axis aligned box to test against (relative to the center of mass of this shape)
  89. /// @param outSubShapeIndices Buffer where to place the indices of the sub shapes that intersect
  90. /// @param inMaxSubShapeIndices How many indices will fit in the buffer (normally you'd provide a buffer of GetNumSubShapes() indices)
  91. /// @return How many indices were placed in outSubShapeIndices
  92. virtual int GetIntersectingSubShapes(const OrientedBox &inBox, uint *outSubShapeIndices, int inMaxSubShapeIndices) const = 0;
  93. struct SubShape
  94. {
  95. /// Initialize sub shape from sub shape settings
  96. /// @param inSettings Settings object
  97. /// @param outResult Result object, only used in case of error
  98. /// @return True on success, false on failure
  99. bool FromSettings(const CompoundShapeSettings::SubShapeSettings &inSettings, ShapeResult &outResult)
  100. {
  101. if (inSettings.mShapePtr != nullptr)
  102. {
  103. // Use provided shape
  104. mShape = inSettings.mShapePtr;
  105. }
  106. else
  107. {
  108. // Create child shape
  109. ShapeResult child_result = inSettings.mShape->Create();
  110. if (!child_result.IsValid())
  111. {
  112. outResult = child_result;
  113. return false;
  114. }
  115. mShape = child_result.Get();
  116. }
  117. // Copy user data
  118. mUserData = inSettings.mUserData;
  119. SetTransform(inSettings.mPosition, inSettings.mRotation, Vec3::sZero() /* Center of mass not yet calculated */);
  120. return true;
  121. }
  122. /// Update the transform of this sub shape
  123. /// @param inPosition New position
  124. /// @param inRotation New orientation
  125. /// @param inCenterOfMass The center of mass of the compound shape
  126. JPH_INLINE void SetTransform(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inCenterOfMass)
  127. {
  128. SetPositionCOM(inPosition - inCenterOfMass + inRotation * mShape->GetCenterOfMass());
  129. mIsRotationIdentity = inRotation.IsClose(Quat::sIdentity()) || inRotation.IsClose(-Quat::sIdentity());
  130. SetRotation(mIsRotationIdentity? Quat::sIdentity() : inRotation);
  131. }
  132. /// Get the local transform for this shape given the scale of the child shape
  133. /// The total transform of the child shape will be GetLocalTransformNoScale(inScale) * Mat44::sScaling(TransformScale(inScale))
  134. /// @param inScale The scale of the child shape (in local space of this shape)
  135. JPH_INLINE Mat44 GetLocalTransformNoScale(Vec3Arg inScale) const
  136. {
  137. JPH_ASSERT(IsValidScale(inScale));
  138. return Mat44::sRotationTranslation(GetRotation(), inScale * GetPositionCOM());
  139. }
  140. /// Test if inScale is valid for this sub shape
  141. inline bool IsValidScale(Vec3Arg inScale) const
  142. {
  143. // We can always handle uniform scale or identity rotations
  144. if (mIsRotationIdentity || ScaleHelpers::IsUniformScale(inScale))
  145. return true;
  146. return ScaleHelpers::CanScaleBeRotated(GetRotation(), inScale);
  147. }
  148. /// Transform the scale to the local space of the child shape
  149. inline Vec3 TransformScale(Vec3Arg inScale) const
  150. {
  151. // We don't need to transform uniform scale or if the rotation is identity
  152. if (mIsRotationIdentity || ScaleHelpers::IsUniformScale(inScale))
  153. return inScale;
  154. return ScaleHelpers::RotateScale(GetRotation(), inScale);
  155. }
  156. /// Compress the center of mass position
  157. JPH_INLINE void SetPositionCOM(Vec3Arg inPositionCOM)
  158. {
  159. inPositionCOM.StoreFloat3(&mPositionCOM);
  160. }
  161. /// Uncompress the center of mass position
  162. JPH_INLINE Vec3 GetPositionCOM() const
  163. {
  164. return Vec3::sLoadFloat3Unsafe(mPositionCOM);
  165. }
  166. /// Compress the rotation
  167. JPH_INLINE void SetRotation(QuatArg inRotation)
  168. {
  169. inRotation.StoreFloat3(&mRotation);
  170. }
  171. /// Uncompress the rotation
  172. JPH_INLINE Quat GetRotation() const
  173. {
  174. return mIsRotationIdentity? Quat::sIdentity() : Quat::sLoadFloat3Unsafe(mRotation);
  175. }
  176. RefConst<Shape> mShape;
  177. Float3 mPositionCOM; ///< Note: Position of center of mass of sub shape!
  178. Float3 mRotation; ///< Note: X, Y, Z of rotation quaternion - note we read 4 bytes beyond this so make sure there's something there
  179. uint32 mUserData; ///< User data value (put here because it falls in padding bytes)
  180. bool mIsRotationIdentity; ///< If mRotation is close to identity (put here because it falls in padding bytes)
  181. // 3 padding bytes left
  182. };
  183. static_assert(sizeof(SubShape) == (JPH_CPU_ADDRESS_BITS == 64? 40 : 36), "Compiler added unexpected padding");
  184. using SubShapes = Array<SubShape>;
  185. /// Access to the sub shapes of this compound
  186. const SubShapes & GetSubShapes() const { return mSubShapes; }
  187. /// Get the total number of sub shapes
  188. uint GetNumSubShapes() const { return (uint)mSubShapes.size(); }
  189. /// Access to a particular sub shape
  190. const SubShape & GetSubShape(uint inIdx) const { return mSubShapes[inIdx]; }
  191. /// Get the user data associated with a shape in this compound
  192. uint32 GetCompoundUserData(uint inIdx) const { return mSubShapes[inIdx].mUserData; }
  193. /// Set the user data associated with a shape in this compound
  194. void SetCompoundUserData(uint inIdx, uint32 inUserData) { mSubShapes[inIdx].mUserData = inUserData; }
  195. /// Check if a sub shape ID is still valid for this shape
  196. /// @param inSubShapeID Sub shape id that indicates the leaf shape relative to this shape
  197. /// @return True if the ID is valid, false if not
  198. inline bool IsSubShapeIDValid(SubShapeID inSubShapeID) const
  199. {
  200. SubShapeID remainder;
  201. return inSubShapeID.PopID(GetSubShapeIDBits(), remainder) < mSubShapes.size();
  202. }
  203. /// Convert SubShapeID to sub shape index
  204. /// @param inSubShapeID Sub shape id that indicates the leaf shape relative to this shape
  205. /// @param outRemainder This is the sub shape ID for the sub shape of the compound after popping off the index
  206. /// @return The index of the sub shape of this compound
  207. inline uint32 GetSubShapeIndexFromID(SubShapeID inSubShapeID, SubShapeID &outRemainder) const
  208. {
  209. uint32 idx = inSubShapeID.PopID(GetSubShapeIDBits(), outRemainder);
  210. JPH_ASSERT(idx < mSubShapes.size(), "Invalid SubShapeID");
  211. return idx;
  212. }
  213. /// @brief Convert a sub shape index to a sub shape ID
  214. /// @param inIdx Index of the sub shape of this compound
  215. /// @param inParentSubShapeID Parent SubShapeID (describing the path to the compound shape)
  216. /// @return A sub shape ID creator that contains the full path to the sub shape with index inIdx
  217. inline SubShapeIDCreator GetSubShapeIDFromIndex(int inIdx, const SubShapeIDCreator &inParentSubShapeID) const
  218. {
  219. return inParentSubShapeID.PushID(inIdx, GetSubShapeIDBits());
  220. }
  221. // See Shape
  222. virtual void SaveBinaryState(StreamOut &inStream) const override;
  223. virtual void SaveSubShapeState(ShapeList &outSubShapes) const override;
  224. virtual void RestoreSubShapeState(const ShapeRefC *inSubShapes, uint inNumShapes) override;
  225. // See Shape::GetStatsRecursive
  226. virtual Stats GetStatsRecursive(VisitedShapes &ioVisitedShapes) const override;
  227. // See Shape::GetVolume
  228. virtual float GetVolume() const override;
  229. // See Shape::IsValidScale
  230. virtual bool IsValidScale(Vec3Arg inScale) const override;
  231. // Register shape functions with the registry
  232. static void sRegister();
  233. protected:
  234. // See: Shape::RestoreBinaryState
  235. virtual void RestoreBinaryState(StreamIn &inStream) override;
  236. // Visitors for collision detection
  237. struct CastRayVisitor;
  238. struct CastRayVisitorCollector;
  239. struct CollidePointVisitor;
  240. struct CastShapeVisitor;
  241. struct CollectTransformedShapesVisitor;
  242. struct CollideCompoundVsShapeVisitor;
  243. struct CollideShapeVsCompoundVisitor;
  244. template <class BoxType> struct GetIntersectingSubShapesVisitor;
  245. /// Determine amount of bits needed to encode sub shape id
  246. inline uint GetSubShapeIDBits() const
  247. {
  248. // Ensure we have enough bits to encode our shape [0, n - 1]
  249. uint32 n = (uint32)mSubShapes.size() - 1;
  250. return 32 - CountLeadingZeros(n);
  251. }
  252. /// Determine the inner radius of this shape
  253. inline void CalculateInnerRadius()
  254. {
  255. mInnerRadius = FLT_MAX;
  256. for (const SubShape &s : mSubShapes)
  257. mInnerRadius = min(mInnerRadius, s.mShape->GetInnerRadius());
  258. }
  259. Vec3 mCenterOfMass { Vec3::sZero() }; ///< Center of mass of the compound
  260. AABox mLocalBounds;
  261. SubShapes mSubShapes;
  262. float mInnerRadius = FLT_MAX; ///< Smallest radius of GetInnerRadius() of child shapes
  263. private:
  264. // Helper functions called by CollisionDispatch
  265. static void sCastCompoundVsShape(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector);
  266. };
  267. JPH_NAMESPACE_END