SoftBodyMotionProperties.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Geometry/AABox.h>
  6. #include <Jolt/Physics/Body/BodyID.h>
  7. #include <Jolt/Physics/Body/MotionProperties.h>
  8. #include <Jolt/Physics/Collision/TransformedShape.h>
  9. #include <Jolt/Physics/SoftBody/SoftBodySharedSettings.h>
  10. #include <Jolt/Physics/SoftBody/SoftBodyVertex.h>
  11. #include <Jolt/Physics/SoftBody/SoftBodyUpdateContext.h>
  12. JPH_NAMESPACE_BEGIN
  13. class PhysicsSystem;
  14. class BodyInterface;
  15. class BodyLockInterface;
  16. struct PhysicsSettings;
  17. class Body;
  18. class Shape;
  19. class SoftBodyCreationSettings;
  20. class TempAllocator;
  21. #ifdef JPH_DEBUG_RENDERER
  22. class DebugRenderer;
  23. enum class ESoftBodyConstraintColor;
  24. #endif // JPH_DEBUG_RENDERER
  25. /// This class contains the runtime information of a soft body.
  26. //
  27. // Based on: XPBD, Extended Position Based Dynamics, Matthias Muller, Ten Minute Physics
  28. // See: https://matthias-research.github.io/pages/tenMinutePhysics/09-xpbd.pdf
  29. class JPH_EXPORT SoftBodyMotionProperties : public MotionProperties
  30. {
  31. public:
  32. using Vertex = SoftBodyVertex;
  33. using Edge = SoftBodySharedSettings::Edge;
  34. using RodStretchShear = SoftBodySharedSettings::RodStretchShear;
  35. using RodBendTwist = SoftBodySharedSettings::RodBendTwist;
  36. using Face = SoftBodySharedSettings::Face;
  37. using DihedralBend = SoftBodySharedSettings::DihedralBend;
  38. using Volume = SoftBodySharedSettings::Volume;
  39. using InvBind = SoftBodySharedSettings::InvBind;
  40. using SkinWeight = SoftBodySharedSettings::SkinWeight;
  41. using Skinned = SoftBodySharedSettings::Skinned;
  42. using LRA = SoftBodySharedSettings::LRA;
  43. /// Initialize the soft body motion properties
  44. void Initialize(const SoftBodyCreationSettings &inSettings);
  45. /// Get the shared settings of the soft body
  46. const SoftBodySharedSettings * GetSettings() const { return mSettings; }
  47. /// Get the vertices of the soft body
  48. const Array<Vertex> & GetVertices() const { return mVertices; }
  49. Array<Vertex> & GetVertices() { return mVertices; }
  50. /// Access an individual vertex
  51. const Vertex & GetVertex(uint inIndex) const { return mVertices[inIndex]; }
  52. Vertex & GetVertex(uint inIndex) { return mVertices[inIndex]; }
  53. /// Access to the state of rods
  54. Quat GetRodRotation(uint inIndex) const { return mRodStates[inIndex].mRotation; }
  55. Vec3 GetRodAngularVelocity(uint inIndex) const { return mRodStates[inIndex].mAngularVelocity; }
  56. /// Get the materials of the soft body
  57. const PhysicsMaterialList & GetMaterials() const { return mSettings->mMaterials; }
  58. /// Get the faces of the soft body
  59. const Array<Face> & GetFaces() const { return mSettings->mFaces; }
  60. /// Access to an individual face
  61. const Face & GetFace(uint inIndex) const { return mSettings->mFaces[inIndex]; }
  62. /// Get the number of solver iterations
  63. uint32 GetNumIterations() const { return mNumIterations; }
  64. void SetNumIterations(uint32 inNumIterations) { mNumIterations = inNumIterations; }
  65. /// Get the pressure of the soft body
  66. float GetPressure() const { return mPressure; }
  67. void SetPressure(float inPressure) { mPressure = inPressure; }
  68. /// Update the position of the body while simulating (set to false for something that is attached to the static world)
  69. bool GetUpdatePosition() const { return mUpdatePosition; }
  70. void SetUpdatePosition(bool inUpdatePosition) { mUpdatePosition = inUpdatePosition; }
  71. /// If the faces in this soft body should be treated as double sided for the purpose of collision detection (ray cast / collide shape / cast shape)
  72. bool GetFacesDoubleSided() const { return mFacesDoubleSided; }
  73. void SetFacesDoubleSided(bool inDoubleSided) { mFacesDoubleSided = inDoubleSided; }
  74. /// Global setting to turn on/off skin constraints
  75. bool GetEnableSkinConstraints() const { return mEnableSkinConstraints; }
  76. void SetEnableSkinConstraints(bool inEnableSkinConstraints) { mEnableSkinConstraints = inEnableSkinConstraints; }
  77. /// Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints. 0 to hard skin all vertices.
  78. float GetSkinnedMaxDistanceMultiplier() const { return mSkinnedMaxDistanceMultiplier; }
  79. void SetSkinnedMaxDistanceMultiplier(float inSkinnedMaxDistanceMultiplier) { mSkinnedMaxDistanceMultiplier = inSkinnedMaxDistanceMultiplier; }
  80. /// How big the particles are, can be used to push the vertices a little bit away from the surface of other bodies to prevent z-fighting
  81. float GetVertexRadius() const { return mVertexRadius; }
  82. void SetVertexRadius(float inVertexRadius) { JPH_ASSERT(mVertexRadius >= 0.0f); mVertexRadius = inVertexRadius; }
  83. /// Get local bounding box
  84. const AABox & GetLocalBounds() const { return mLocalBounds; }
  85. /// Get the volume of the soft body. Note can become negative if the shape is inside out!
  86. float GetVolume() const { return GetVolumeTimesSix() / 6.0f; }
  87. /// Calculate the total mass and inertia of this body based on the current state of the vertices
  88. void CalculateMassAndInertia();
  89. #ifdef JPH_DEBUG_RENDERER
  90. /// Draw the state of a soft body
  91. void DrawVertices(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
  92. void DrawVertexVelocities(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
  93. void DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  94. void DrawRods(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  95. void DrawRodStates(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  96. void DrawRodBendTwistConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  97. void DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  98. void DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  99. void DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  100. void DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
  101. void DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
  102. #endif // JPH_DEBUG_RENDERER
  103. /// Saving state for replay
  104. void SaveState(StateRecorder &inStream) const;
  105. /// Restoring state for replay
  106. void RestoreState(StateRecorder &inStream);
  107. /// Skin vertices to supplied joints, information is used by the skinned constraints.
  108. /// @param inCenterOfMassTransform Value of Body::GetCenterOfMassTransform().
  109. /// @param inJointMatrices The joint matrices must be expressed relative to inCenterOfMassTransform.
  110. /// @param inNumJoints Indicates how large the inJointMatrices array is (used only for validating out of bounds).
  111. /// @param inHardSkinAll Can be used to position all vertices on the skinned vertices and can be used to hard reset the soft body.
  112. /// @param ioTempAllocator Allocator.
  113. void SkinVertices(RMat44Arg inCenterOfMassTransform, const Mat44 *inJointMatrices, uint inNumJoints, bool inHardSkinAll, TempAllocator &ioTempAllocator);
  114. /// This function allows you to update the soft body immediately without going through the PhysicsSystem.
  115. /// This is useful if the soft body is teleported and needs to 'settle' or it can be used if a the soft body
  116. /// is not added to the PhysicsSystem and needs to be updated manually. One reason for not adding it to the
  117. /// PhysicsSystem is that you might want to update a soft body immediately after updating an animated object
  118. /// that has the soft body attached to it. If the soft body is added to the PhysicsSystem it will be updated
  119. /// by it, so calling this function will effectively update it twice. Note that when you use this function,
  120. /// only the current thread will be used, whereas if you update through the PhysicsSystem, multiple threads may
  121. /// be used.
  122. /// Note that this will bypass any sleep checks. Since the dynamic objects that the soft body touches
  123. /// will not move during this call, there can be simulation artifacts if you call this function multiple times
  124. /// without running the physics simulation step.
  125. void CustomUpdate(float inDeltaTime, Body &ioSoftBody, PhysicsSystem &inSystem);
  126. ////////////////////////////////////////////////////////////
  127. // FUNCTIONS BELOW THIS LINE ARE FOR INTERNAL USE ONLY
  128. ////////////////////////////////////////////////////////////
  129. /// Initialize the update context. Not part of the public API.
  130. void InitializeUpdateContext(float inDeltaTime, Body &inSoftBody, const PhysicsSystem &inSystem, SoftBodyUpdateContext &ioContext);
  131. /// Do a broad phase check and collect all bodies that can possibly collide with this soft body. Not part of the public API.
  132. void DetermineCollidingShapes(const SoftBodyUpdateContext &inContext, const PhysicsSystem &inSystem, const BodyLockInterface &inBodyLockInterface);
  133. /// Return code for ParallelUpdate
  134. enum class EStatus
  135. {
  136. NoWork = 1 << 0, ///< No work was done because other threads were still working on a batch that cannot run concurrently
  137. DidWork = 1 << 1, ///< Work was done to progress the update
  138. Done = 1 << 2, ///< All work is done
  139. };
  140. /// Update the soft body, will process a batch of work. Not part of the public API.
  141. EStatus ParallelUpdate(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);
  142. /// Update the velocities of all rigid bodies that we collided with. Not part of the public API.
  143. void UpdateRigidBodyVelocities(const SoftBodyUpdateContext &inContext, BodyInterface &inBodyInterface);
  144. private:
  145. // SoftBodyManifold needs to have access to CollidingShape
  146. friend class SoftBodyManifold;
  147. // Information about a leaf shape that we're colliding with
  148. struct LeafShape
  149. {
  150. LeafShape() = default;
  151. LeafShape(Mat44Arg inTransform, Vec3Arg inScale, const Shape *inShape) : mTransform(inTransform), mScale(inScale), mShape(inShape) { }
  152. Mat44 mTransform; ///< Transform of the shape relative to the soft body
  153. Vec3 mScale; ///< Scale of the shape
  154. RefConst<Shape> mShape; ///< Shape
  155. };
  156. // Collect information about the colliding bodies
  157. struct CollidingShape
  158. {
  159. /// Get the velocity of a point on this body
  160. Vec3 GetPointVelocity(Vec3Arg inPointRelativeToCOM) const
  161. {
  162. return mLinearVelocity + mAngularVelocity.Cross(inPointRelativeToCOM);
  163. }
  164. Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body
  165. Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit
  166. BodyID mBodyID; ///< Body ID of the body we hit
  167. EMotionType mMotionType; ///< Motion type of the body we hit
  168. float mInvMass; ///< Inverse mass of the body we hit
  169. float mFriction; ///< Combined friction of the two bodies
  170. float mRestitution; ///< Combined restitution of the two bodies
  171. float mSoftBodyInvMassScale; ///< Scale factor for the inverse mass of the soft body vertices
  172. bool mUpdateVelocities; ///< If the linear/angular velocity changed and the body needs to be updated
  173. Mat44 mInvInertia; ///< Inverse inertia in local space to the soft body
  174. Vec3 mLinearVelocity; ///< Linear velocity of the body in local space to the soft body
  175. Vec3 mAngularVelocity; ///< Angular velocity of the body in local space to the soft body
  176. Vec3 mOriginalLinearVelocity; ///< Linear velocity of the body in local space to the soft body at start
  177. Vec3 mOriginalAngularVelocity; ///< Angular velocity of the body in local space to the soft body at start
  178. };
  179. // Collect information about the colliding sensors
  180. struct CollidingSensor
  181. {
  182. Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body
  183. Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit
  184. BodyID mBodyID; ///< Body ID of the body we hit
  185. bool mHasContact; ///< If the sensor collided with the soft body
  186. };
  187. // Information about the current state of a rod.
  188. struct RodState
  189. {
  190. Quat mRotation; ///< Rotation of the rod, relative to center of mass transform
  191. union
  192. {
  193. Vec3 mAngularVelocity; ///< Angular velocity of the rod, relative to center of mass transform, valid only outside of the simulation.
  194. Quat mPreviousRotationInternal; ///< Internal use only. Previous rotation of the rod, relative to center of mass transform, valid only during the simulation.
  195. };
  196. };
  197. // Information about the state of all skinned vertices
  198. struct SkinState
  199. {
  200. Vec3 mPreviousPosition = Vec3::sZero(); ///< Previous position of the skinned vertex, used to interpolate between the previous and current position
  201. Vec3 mPosition = Vec3::sNaN(); ///< Current position of the skinned vertex
  202. Vec3 mNormal = Vec3::sNaN(); ///< Normal of the skinned vertex
  203. };
  204. /// Do a narrow phase check and determine the closest feature that we can collide with
  205. void DetermineCollisionPlanes(uint inVertexStart, uint inNumVertices);
  206. /// Do a narrow phase check between a single sensor and the soft body
  207. void DetermineSensorCollisions(CollidingSensor &ioSensor);
  208. /// Apply pressure force and update the vertex velocities
  209. void ApplyPressure(const SoftBodyUpdateContext &inContext);
  210. /// Integrate the positions of all vertices by 1 sub step
  211. void IntegratePositions(const SoftBodyUpdateContext &inContext);
  212. /// Enforce all bend constraints
  213. void ApplyDihedralBendConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  214. /// Enforce all volume constraints
  215. void ApplyVolumeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  216. /// Enforce all skin constraints
  217. void ApplySkinConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  218. /// Enforce all edge constraints
  219. void ApplyEdgeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  220. /// Enforce all rod constraints
  221. void ApplyRodStretchShearConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  222. void ApplyRodBendTwistConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);
  223. /// Enforce all LRA constraints
  224. void ApplyLRAConstraints(uint inStartIndex, uint inEndIndex);
  225. /// Enforce all collision constraints & update all velocities according the XPBD algorithm
  226. void ApplyCollisionConstraintsAndUpdateVelocities(const SoftBodyUpdateContext &inContext);
  227. /// Update the state of the soft body (position, velocity, bounds)
  228. void UpdateSoftBodyState(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);
  229. /// Start the first solver iteration
  230. void StartFirstIteration(SoftBodyUpdateContext &ioContext);
  231. /// Executes tasks that need to run on the start of an iteration (i.e. the stuff that can't run in parallel)
  232. void StartNextIteration(const SoftBodyUpdateContext &ioContext);
  233. /// Helper function for ParallelUpdate that works on batches of collision planes
  234. EStatus ParallelDetermineCollisionPlanes(SoftBodyUpdateContext &ioContext);
  235. /// Helper function for ParallelUpdate that works on sensor collisions
  236. EStatus ParallelDetermineSensorCollisions(SoftBodyUpdateContext &ioContext);
  237. /// Helper function for ParallelUpdate that works on batches of constraints
  238. EStatus ParallelApplyConstraints(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);
  239. /// Helper function to update a single group of constraints
  240. void ProcessGroup(const SoftBodyUpdateContext &ioContext, uint inGroupIndex);
  241. /// Returns 6 times the volume of the soft body
  242. float GetVolumeTimesSix() const;
  243. #ifdef JPH_DEBUG_RENDERER
  244. /// Helper function to draw constraints
  245. template <typename GetEndIndex, typename DrawConstraint>
  246. inline void DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const;
  247. RMat44 mSkinStateTransform = RMat44::sIdentity(); ///< The matrix that transforms mSkinState to world space
  248. #endif // JPH_DEBUG_RENDERER
  249. RefConst<SoftBodySharedSettings> mSettings; ///< Configuration of the particles and constraints
  250. Array<Vertex> mVertices; ///< Current state of all vertices in the simulation
  251. Array<RodState> mRodStates; ///< Current state of all rods in the simulation
  252. Array<CollidingShape> mCollidingShapes; ///< List of colliding shapes retrieved during the last update
  253. Array<CollidingSensor> mCollidingSensors; ///< List of colliding sensors retrieved during the last update
  254. Array<SkinState> mSkinState; ///< List of skinned positions (1-on-1 with mVertices but only those that are used by the skinning constraints are filled in)
  255. AABox mLocalBounds; ///< Bounding box of all vertices
  256. AABox mLocalPredictedBounds; ///< Predicted bounding box for all vertices using extrapolation of velocity by last step delta time
  257. uint32 mNumIterations; ///< Number of solver iterations
  258. uint mNumSensors; ///< Workaround for TSAN false positive: store mCollidingSensors.size() in a separate variable.
  259. float mPressure; ///< n * R * T, amount of substance * ideal gas constant * absolute temperature, see https://en.wikipedia.org/wiki/Pressure
  260. float mSkinnedMaxDistanceMultiplier = 1.0f; ///< Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints
  261. float mVertexRadius = 0.0f; ///< How big the particles are, can be used to push the vertices a little bit away from the surface of other bodies to prevent z-fighting
  262. bool mUpdatePosition; ///< Update the position of the body while simulating (set to false for something that is attached to the static world)
  263. bool mFacesDoubleSided; ///< If the faces in this soft body should be treated as double sided for the purpose of collision detection (ray cast / collide shape / cast shape)
  264. atomic<bool> mNeedContactCallback = false; ///< True if the soft body has collided with anything in the last update
  265. bool mEnableSkinConstraints = true; ///< If skin constraints are enabled
  266. bool mSkinStatePreviousPositionValid = false; ///< True if the skinning was updated in the last update so that the previous position of the skin state is valid
  267. };
  268. JPH_NAMESPACE_END