Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h
21928 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2023 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Geometry/AABox.h>7#include <Jolt/Physics/Body/BodyID.h>8#include <Jolt/Physics/Body/MotionProperties.h>9#include <Jolt/Physics/Collision/TransformedShape.h>10#include <Jolt/Physics/SoftBody/SoftBodySharedSettings.h>11#include <Jolt/Physics/SoftBody/SoftBodyVertex.h>12#include <Jolt/Physics/SoftBody/SoftBodyUpdateContext.h>1314JPH_NAMESPACE_BEGIN1516class PhysicsSystem;17class BodyInterface;18class BodyLockInterface;19struct PhysicsSettings;20class Body;21class Shape;22class SoftBodyCreationSettings;23class TempAllocator;24#ifdef JPH_DEBUG_RENDERER25class DebugRenderer;26enum class ESoftBodyConstraintColor;27#endif // JPH_DEBUG_RENDERER2829/// This class contains the runtime information of a soft body.30//31// Based on: XPBD, Extended Position Based Dynamics, Matthias Muller, Ten Minute Physics32// See: https://matthias-research.github.io/pages/tenMinutePhysics/09-xpbd.pdf33class JPH_EXPORT SoftBodyMotionProperties : public MotionProperties34{35public:36using Vertex = SoftBodyVertex;37using Edge = SoftBodySharedSettings::Edge;38using RodStretchShear = SoftBodySharedSettings::RodStretchShear;39using RodBendTwist = SoftBodySharedSettings::RodBendTwist;40using Face = SoftBodySharedSettings::Face;41using DihedralBend = SoftBodySharedSettings::DihedralBend;42using Volume = SoftBodySharedSettings::Volume;43using InvBind = SoftBodySharedSettings::InvBind;44using SkinWeight = SoftBodySharedSettings::SkinWeight;45using Skinned = SoftBodySharedSettings::Skinned;46using LRA = SoftBodySharedSettings::LRA;4748/// Initialize the soft body motion properties49void Initialize(const SoftBodyCreationSettings &inSettings);5051/// Get the shared settings of the soft body52const SoftBodySharedSettings * GetSettings() const { return mSettings; }5354/// Get the vertices of the soft body55const Array<Vertex> & GetVertices() const { return mVertices; }56Array<Vertex> & GetVertices() { return mVertices; }5758/// Access an individual vertex59const Vertex & GetVertex(uint inIndex) const { return mVertices[inIndex]; }60Vertex & GetVertex(uint inIndex) { return mVertices[inIndex]; }6162/// Access to the state of rods63Quat GetRodRotation(uint inIndex) const { return mRodStates[inIndex].mRotation; }64Vec3 GetRodAngularVelocity(uint inIndex) const { return mRodStates[inIndex].mAngularVelocity; }6566/// Get the materials of the soft body67const PhysicsMaterialList & GetMaterials() const { return mSettings->mMaterials; }6869/// Get the faces of the soft body70const Array<Face> & GetFaces() const { return mSettings->mFaces; }7172/// Access to an individual face73const Face & GetFace(uint inIndex) const { return mSettings->mFaces[inIndex]; }7475/// Get the number of solver iterations76uint32 GetNumIterations() const { return mNumIterations; }77void SetNumIterations(uint32 inNumIterations) { mNumIterations = inNumIterations; }7879/// Get the pressure of the soft body80float GetPressure() const { return mPressure; }81void SetPressure(float inPressure) { mPressure = inPressure; }8283/// Update the position of the body while simulating (set to false for something that is attached to the static world)84bool GetUpdatePosition() const { return mUpdatePosition; }85void SetUpdatePosition(bool inUpdatePosition) { mUpdatePosition = inUpdatePosition; }8687/// 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)88bool GetFacesDoubleSided() const { return mFacesDoubleSided; }89void SetFacesDoubleSided(bool inDoubleSided) { mFacesDoubleSided = inDoubleSided; }9091/// Global setting to turn on/off skin constraints92bool GetEnableSkinConstraints() const { return mEnableSkinConstraints; }93void SetEnableSkinConstraints(bool inEnableSkinConstraints) { mEnableSkinConstraints = inEnableSkinConstraints; }9495/// Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints. 0 to hard skin all vertices.96float GetSkinnedMaxDistanceMultiplier() const { return mSkinnedMaxDistanceMultiplier; }97void SetSkinnedMaxDistanceMultiplier(float inSkinnedMaxDistanceMultiplier) { mSkinnedMaxDistanceMultiplier = inSkinnedMaxDistanceMultiplier; }9899/// 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-fighting100float GetVertexRadius() const { return mVertexRadius; }101void SetVertexRadius(float inVertexRadius) { JPH_ASSERT(mVertexRadius >= 0.0f); mVertexRadius = inVertexRadius; }102103/// Get local bounding box104const AABox & GetLocalBounds() const { return mLocalBounds; }105106/// Get the volume of the soft body. Note can become negative if the shape is inside out!107float GetVolume() const { return GetVolumeTimesSix() / 6.0f; }108109/// Calculate the total mass and inertia of this body based on the current state of the vertices110void CalculateMassAndInertia();111112#ifdef JPH_DEBUG_RENDERER113/// Draw the state of a soft body114void DrawVertices(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;115void DrawVertexVelocities(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;116void DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;117void DrawRods(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;118void DrawRodStates(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;119void DrawRodBendTwistConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;120void DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;121void DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;122void DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;123void DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;124void DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;125#endif // JPH_DEBUG_RENDERER126127/// Saving state for replay128void SaveState(StateRecorder &inStream) const;129130/// Restoring state for replay131void RestoreState(StateRecorder &inStream);132133/// Skin vertices to supplied joints, information is used by the skinned constraints.134/// @param inCenterOfMassTransform Value of Body::GetCenterOfMassTransform().135/// @param inJointMatrices The joint matrices must be expressed relative to inCenterOfMassTransform.136/// @param inNumJoints Indicates how large the inJointMatrices array is (used only for validating out of bounds).137/// @param inHardSkinAll Can be used to position all vertices on the skinned vertices and can be used to hard reset the soft body.138/// @param ioTempAllocator Allocator.139void SkinVertices(RMat44Arg inCenterOfMassTransform, const Mat44 *inJointMatrices, uint inNumJoints, bool inHardSkinAll, TempAllocator &ioTempAllocator);140141/// This function allows you to update the soft body immediately without going through the PhysicsSystem.142/// This is useful if the soft body is teleported and needs to 'settle' or it can be used if a the soft body143/// is not added to the PhysicsSystem and needs to be updated manually. One reason for not adding it to the144/// PhysicsSystem is that you might want to update a soft body immediately after updating an animated object145/// that has the soft body attached to it. If the soft body is added to the PhysicsSystem it will be updated146/// by it, so calling this function will effectively update it twice. Note that when you use this function,147/// only the current thread will be used, whereas if you update through the PhysicsSystem, multiple threads may148/// be used.149/// Note that this will bypass any sleep checks. Since the dynamic objects that the soft body touches150/// will not move during this call, there can be simulation artifacts if you call this function multiple times151/// without running the physics simulation step.152void CustomUpdate(float inDeltaTime, Body &ioSoftBody, PhysicsSystem &inSystem);153154////////////////////////////////////////////////////////////155// FUNCTIONS BELOW THIS LINE ARE FOR INTERNAL USE ONLY156////////////////////////////////////////////////////////////157158/// Initialize the update context. Not part of the public API.159void InitializeUpdateContext(float inDeltaTime, Body &inSoftBody, const PhysicsSystem &inSystem, SoftBodyUpdateContext &ioContext);160161/// Do a broad phase check and collect all bodies that can possibly collide with this soft body. Not part of the public API.162void DetermineCollidingShapes(const SoftBodyUpdateContext &inContext, const PhysicsSystem &inSystem, const BodyLockInterface &inBodyLockInterface);163164/// Return code for ParallelUpdate165enum class EStatus166{167NoWork = 1 << 0, ///< No work was done because other threads were still working on a batch that cannot run concurrently168DidWork = 1 << 1, ///< Work was done to progress the update169Done = 1 << 2, ///< All work is done170};171172/// Update the soft body, will process a batch of work. Not part of the public API.173EStatus ParallelUpdate(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);174175/// Update the velocities of all rigid bodies that we collided with. Not part of the public API.176void UpdateRigidBodyVelocities(const SoftBodyUpdateContext &inContext, BodyInterface &inBodyInterface);177178private:179// SoftBodyManifold needs to have access to CollidingShape180friend class SoftBodyManifold;181182// Information about a leaf shape that we're colliding with183struct LeafShape184{185LeafShape() = default;186LeafShape(Mat44Arg inTransform, Vec3Arg inScale, const Shape *inShape) : mTransform(inTransform), mScale(inScale), mShape(inShape) { }187188Mat44 mTransform; ///< Transform of the shape relative to the soft body189Vec3 mScale; ///< Scale of the shape190RefConst<Shape> mShape; ///< Shape191};192193// Collect information about the colliding bodies194struct CollidingShape195{196/// Get the velocity of a point on this body197Vec3 GetPointVelocity(Vec3Arg inPointRelativeToCOM) const198{199return mLinearVelocity + mAngularVelocity.Cross(inPointRelativeToCOM);200}201202Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body203Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit204BodyID mBodyID; ///< Body ID of the body we hit205EMotionType mMotionType; ///< Motion type of the body we hit206float mInvMass; ///< Inverse mass of the body we hit207float mFriction; ///< Combined friction of the two bodies208float mRestitution; ///< Combined restitution of the two bodies209float mSoftBodyInvMassScale; ///< Scale factor for the inverse mass of the soft body vertices210bool mUpdateVelocities; ///< If the linear/angular velocity changed and the body needs to be updated211Mat44 mInvInertia; ///< Inverse inertia in local space to the soft body212Vec3 mLinearVelocity; ///< Linear velocity of the body in local space to the soft body213Vec3 mAngularVelocity; ///< Angular velocity of the body in local space to the soft body214Vec3 mOriginalLinearVelocity; ///< Linear velocity of the body in local space to the soft body at start215Vec3 mOriginalAngularVelocity; ///< Angular velocity of the body in local space to the soft body at start216};217218// Collect information about the colliding sensors219struct CollidingSensor220{221Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body222Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit223BodyID mBodyID; ///< Body ID of the body we hit224bool mHasContact; ///< If the sensor collided with the soft body225};226227// Information about the current state of a rod.228struct RodState229{230Quat mRotation; ///< Rotation of the rod, relative to center of mass transform231union232{233Vec3 mAngularVelocity; ///< Angular velocity of the rod, relative to center of mass transform, valid only outside of the simulation.234Quat mPreviousRotationInternal; ///< Internal use only. Previous rotation of the rod, relative to center of mass transform, valid only during the simulation.235};236};237238// Information about the state of all skinned vertices239struct SkinState240{241Vec3 mPreviousPosition = Vec3::sZero(); ///< Previous position of the skinned vertex, used to interpolate between the previous and current position242Vec3 mPosition = Vec3::sNaN(); ///< Current position of the skinned vertex243Vec3 mNormal = Vec3::sNaN(); ///< Normal of the skinned vertex244};245246/// Do a narrow phase check and determine the closest feature that we can collide with247void DetermineCollisionPlanes(uint inVertexStart, uint inNumVertices);248249/// Do a narrow phase check between a single sensor and the soft body250void DetermineSensorCollisions(CollidingSensor &ioSensor);251252/// Apply pressure force and update the vertex velocities253void ApplyPressure(const SoftBodyUpdateContext &inContext);254255/// Integrate the positions of all vertices by 1 sub step256void IntegratePositions(const SoftBodyUpdateContext &inContext);257258/// Enforce all bend constraints259void ApplyDihedralBendConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);260261/// Enforce all volume constraints262void ApplyVolumeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);263264/// Enforce all skin constraints265void ApplySkinConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);266267/// Enforce all edge constraints268void ApplyEdgeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);269270/// Enforce all rod constraints271void ApplyRodStretchShearConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);272void ApplyRodBendTwistConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);273274/// Enforce all LRA constraints275void ApplyLRAConstraints(uint inStartIndex, uint inEndIndex);276277/// Enforce all collision constraints & update all velocities according the XPBD algorithm278void ApplyCollisionConstraintsAndUpdateVelocities(const SoftBodyUpdateContext &inContext);279280/// Update the state of the soft body (position, velocity, bounds)281void UpdateSoftBodyState(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);282283/// Start the first solver iteration284void StartFirstIteration(SoftBodyUpdateContext &ioContext);285286/// Executes tasks that need to run on the start of an iteration (i.e. the stuff that can't run in parallel)287void StartNextIteration(const SoftBodyUpdateContext &ioContext);288289/// Helper function for ParallelUpdate that works on batches of collision planes290EStatus ParallelDetermineCollisionPlanes(SoftBodyUpdateContext &ioContext);291292/// Helper function for ParallelUpdate that works on sensor collisions293EStatus ParallelDetermineSensorCollisions(SoftBodyUpdateContext &ioContext);294295/// Helper function for ParallelUpdate that works on batches of constraints296EStatus ParallelApplyConstraints(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);297298/// Helper function to update a single group of constraints299void ProcessGroup(const SoftBodyUpdateContext &ioContext, uint inGroupIndex);300301/// Returns 6 times the volume of the soft body302float GetVolumeTimesSix() const;303304#ifdef JPH_DEBUG_RENDERER305/// Helper function to draw constraints306template <typename GetEndIndex, typename DrawConstraint>307inline void DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const;308309RMat44 mSkinStateTransform = RMat44::sIdentity(); ///< The matrix that transforms mSkinState to world space310#endif // JPH_DEBUG_RENDERER311312RefConst<SoftBodySharedSettings> mSettings; ///< Configuration of the particles and constraints313Array<Vertex> mVertices; ///< Current state of all vertices in the simulation314Array<RodState> mRodStates; ///< Current state of all rods in the simulation315Array<CollidingShape> mCollidingShapes; ///< List of colliding shapes retrieved during the last update316Array<CollidingSensor> mCollidingSensors; ///< List of colliding sensors retrieved during the last update317Array<SkinState> mSkinState; ///< List of skinned positions (1-on-1 with mVertices but only those that are used by the skinning constraints are filled in)318AABox mLocalBounds; ///< Bounding box of all vertices319AABox mLocalPredictedBounds; ///< Predicted bounding box for all vertices using extrapolation of velocity by last step delta time320uint32 mNumIterations; ///< Number of solver iterations321uint mNumSensors; ///< Workaround for TSAN false positive: store mCollidingSensors.size() in a separate variable.322float mPressure; ///< n * R * T, amount of substance * ideal gas constant * absolute temperature, see https://en.wikipedia.org/wiki/Pressure323float mSkinnedMaxDistanceMultiplier = 1.0f; ///< Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints324float 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-fighting325bool mUpdatePosition; ///< Update the position of the body while simulating (set to false for something that is attached to the static world)326bool 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)327atomic<bool> mNeedContactCallback = false; ///< True if the soft body has collided with anything in the last update328bool mEnableSkinConstraints = true; ///< If skin constraints are enabled329bool mSkinStatePreviousPositionValid = false; ///< True if the skinning was updated in the last update so that the previous position of the skin state is valid330};331332JPH_NAMESPACE_END333334335