CompoundShape.h 15 KB

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