SoftBodyMotionProperties.h 15 KB

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