CompoundShape.h 14 KB

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