Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.h
9912 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 Face = SoftBodySharedSettings::Face;39using DihedralBend = SoftBodySharedSettings::DihedralBend;40using Volume = SoftBodySharedSettings::Volume;41using InvBind = SoftBodySharedSettings::InvBind;42using SkinWeight = SoftBodySharedSettings::SkinWeight;43using Skinned = SoftBodySharedSettings::Skinned;44using LRA = SoftBodySharedSettings::LRA;4546/// Initialize the soft body motion properties47void Initialize(const SoftBodyCreationSettings &inSettings);4849/// Get the shared settings of the soft body50const SoftBodySharedSettings * GetSettings() const { return mSettings; }5152/// Get the vertices of the soft body53const Array<Vertex> & GetVertices() const { return mVertices; }54Array<Vertex> & GetVertices() { return mVertices; }5556/// Access an individual vertex57const Vertex & GetVertex(uint inIndex) const { return mVertices[inIndex]; }58Vertex & GetVertex(uint inIndex) { return mVertices[inIndex]; }5960/// Get the materials of the soft body61const PhysicsMaterialList & GetMaterials() const { return mSettings->mMaterials; }6263/// Get the faces of the soft body64const Array<Face> & GetFaces() const { return mSettings->mFaces; }6566/// Access to an individual face67const Face & GetFace(uint inIndex) const { return mSettings->mFaces[inIndex]; }6869/// Get the number of solver iterations70uint32 GetNumIterations() const { return mNumIterations; }71void SetNumIterations(uint32 inNumIterations) { mNumIterations = inNumIterations; }7273/// Get the pressure of the soft body74float GetPressure() const { return mPressure; }75void SetPressure(float inPressure) { mPressure = inPressure; }7677/// Update the position of the body while simulating (set to false for something that is attached to the static world)78bool GetUpdatePosition() const { return mUpdatePosition; }79void SetUpdatePosition(bool inUpdatePosition) { mUpdatePosition = inUpdatePosition; }8081/// Global setting to turn on/off skin constraints82bool GetEnableSkinConstraints() const { return mEnableSkinConstraints; }83void SetEnableSkinConstraints(bool inEnableSkinConstraints) { mEnableSkinConstraints = inEnableSkinConstraints; }8485/// Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints. 0 to hard skin all vertices.86float GetSkinnedMaxDistanceMultiplier() const { return mSkinnedMaxDistanceMultiplier; }87void SetSkinnedMaxDistanceMultiplier(float inSkinnedMaxDistanceMultiplier) { mSkinnedMaxDistanceMultiplier = inSkinnedMaxDistanceMultiplier; }8889/// Get local bounding box90const AABox & GetLocalBounds() const { return mLocalBounds; }9192/// Get the volume of the soft body. Note can become negative if the shape is inside out!93float GetVolume() const { return GetVolumeTimesSix() / 6.0f; }9495/// Calculate the total mass and inertia of this body based on the current state of the vertices96void CalculateMassAndInertia();9798#ifdef JPH_DEBUG_RENDERER99/// Draw the state of a soft body100void DrawVertices(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;101void DrawVertexVelocities(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;102void DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;103void DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;104void DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;105void DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;106void DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;107void DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;108#endif // JPH_DEBUG_RENDERER109110/// Saving state for replay111void SaveState(StateRecorder &inStream) const;112113/// Restoring state for replay114void RestoreState(StateRecorder &inStream);115116/// Skin vertices to supplied joints, information is used by the skinned constraints.117/// @param inCenterOfMassTransform Value of Body::GetCenterOfMassTransform().118/// @param inJointMatrices The joint matrices must be expressed relative to inCenterOfMassTransform.119/// @param inNumJoints Indicates how large the inJointMatrices array is (used only for validating out of bounds).120/// @param inHardSkinAll Can be used to position all vertices on the skinned vertices and can be used to hard reset the soft body.121/// @param ioTempAllocator Allocator.122void SkinVertices(RMat44Arg inCenterOfMassTransform, const Mat44 *inJointMatrices, uint inNumJoints, bool inHardSkinAll, TempAllocator &ioTempAllocator);123124/// This function allows you to update the soft body immediately without going through the PhysicsSystem.125/// This is useful if the soft body is teleported and needs to 'settle' or it can be used if a the soft body126/// is not added to the PhysicsSystem and needs to be updated manually. One reason for not adding it to the127/// PhysicsSystem is that you might want to update a soft body immediately after updating an animated object128/// that has the soft body attached to it. If the soft body is added to the PhysicsSystem it will be updated129/// by it, so calling this function will effectively update it twice. Note that when you use this function,130/// only the current thread will be used, whereas if you update through the PhysicsSystem, multiple threads may131/// be used.132/// Note that this will bypass any sleep checks. Since the dynamic objects that the soft body touches133/// will not move during this call, there can be simulation artifacts if you call this function multiple times134/// without running the physics simulation step.135void CustomUpdate(float inDeltaTime, Body &ioSoftBody, PhysicsSystem &inSystem);136137////////////////////////////////////////////////////////////138// FUNCTIONS BELOW THIS LINE ARE FOR INTERNAL USE ONLY139////////////////////////////////////////////////////////////140141/// Initialize the update context. Not part of the public API.142void InitializeUpdateContext(float inDeltaTime, Body &inSoftBody, const PhysicsSystem &inSystem, SoftBodyUpdateContext &ioContext);143144/// Do a broad phase check and collect all bodies that can possibly collide with this soft body. Not part of the public API.145void DetermineCollidingShapes(const SoftBodyUpdateContext &inContext, const PhysicsSystem &inSystem, const BodyLockInterface &inBodyLockInterface);146147/// Return code for ParallelUpdate148enum class EStatus149{150NoWork = 1 << 0, ///< No work was done because other threads were still working on a batch that cannot run concurrently151DidWork = 1 << 1, ///< Work was done to progress the update152Done = 1 << 2, ///< All work is done153};154155/// Update the soft body, will process a batch of work. Not part of the public API.156EStatus ParallelUpdate(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);157158/// Update the velocities of all rigid bodies that we collided with. Not part of the public API.159void UpdateRigidBodyVelocities(const SoftBodyUpdateContext &inContext, BodyInterface &inBodyInterface);160161private:162// SoftBodyManifold needs to have access to CollidingShape163friend class SoftBodyManifold;164165// Information about a leaf shape that we're colliding with166struct LeafShape167{168LeafShape() = default;169LeafShape(Mat44Arg inTransform, Vec3Arg inScale, const Shape *inShape) : mTransform(inTransform), mScale(inScale), mShape(inShape) { }170171Mat44 mTransform; ///< Transform of the shape relative to the soft body172Vec3 mScale; ///< Scale of the shape173RefConst<Shape> mShape; ///< Shape174};175176// Collect information about the colliding bodies177struct CollidingShape178{179/// Get the velocity of a point on this body180Vec3 GetPointVelocity(Vec3Arg inPointRelativeToCOM) const181{182return mLinearVelocity + mAngularVelocity.Cross(inPointRelativeToCOM);183}184185Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body186Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit187BodyID mBodyID; ///< Body ID of the body we hit188EMotionType mMotionType; ///< Motion type of the body we hit189float mInvMass; ///< Inverse mass of the body we hit190float mFriction; ///< Combined friction of the two bodies191float mRestitution; ///< Combined restitution of the two bodies192float mSoftBodyInvMassScale; ///< Scale factor for the inverse mass of the soft body vertices193bool mUpdateVelocities; ///< If the linear/angular velocity changed and the body needs to be updated194Mat44 mInvInertia; ///< Inverse inertia in local space to the soft body195Vec3 mLinearVelocity; ///< Linear velocity of the body in local space to the soft body196Vec3 mAngularVelocity; ///< Angular velocity of the body in local space to the soft body197Vec3 mOriginalLinearVelocity; ///< Linear velocity of the body in local space to the soft body at start198Vec3 mOriginalAngularVelocity; ///< Angular velocity of the body in local space to the soft body at start199};200201// Collect information about the colliding sensors202struct CollidingSensor203{204Mat44 mCenterOfMassTransform; ///< Transform of the body relative to the soft body205Array<LeafShape> mShapes; ///< Leaf shapes of the body we hit206BodyID mBodyID; ///< Body ID of the body we hit207bool mHasContact; ///< If the sensor collided with the soft body208};209210// Information about the state of all skinned vertices211struct SkinState212{213Vec3 mPreviousPosition = Vec3::sZero(); ///< Previous position of the skinned vertex, used to interpolate between the previous and current position214Vec3 mPosition = Vec3::sNaN(); ///< Current position of the skinned vertex215Vec3 mNormal = Vec3::sNaN(); ///< Normal of the skinned vertex216};217218/// Do a narrow phase check and determine the closest feature that we can collide with219void DetermineCollisionPlanes(uint inVertexStart, uint inNumVertices);220221/// Do a narrow phase check between a single sensor and the soft body222void DetermineSensorCollisions(CollidingSensor &ioSensor);223224/// Apply pressure force and update the vertex velocities225void ApplyPressure(const SoftBodyUpdateContext &inContext);226227/// Integrate the positions of all vertices by 1 sub step228void IntegratePositions(const SoftBodyUpdateContext &inContext);229230/// Enforce all bend constraints231void ApplyDihedralBendConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);232233/// Enforce all volume constraints234void ApplyVolumeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);235236/// Enforce all skin constraints237void ApplySkinConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);238239/// Enforce all edge constraints240void ApplyEdgeConstraints(const SoftBodyUpdateContext &inContext, uint inStartIndex, uint inEndIndex);241242/// Enforce all LRA constraints243void ApplyLRAConstraints(uint inStartIndex, uint inEndIndex);244245/// Enforce all collision constraints & update all velocities according the XPBD algorithm246void ApplyCollisionConstraintsAndUpdateVelocities(const SoftBodyUpdateContext &inContext);247248/// Update the state of the soft body (position, velocity, bounds)249void UpdateSoftBodyState(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);250251/// Start the first solver iteration252void StartFirstIteration(SoftBodyUpdateContext &ioContext);253254/// Executes tasks that need to run on the start of an iteration (i.e. the stuff that can't run in parallel)255void StartNextIteration(const SoftBodyUpdateContext &ioContext);256257/// Helper function for ParallelUpdate that works on batches of collision planes258EStatus ParallelDetermineCollisionPlanes(SoftBodyUpdateContext &ioContext);259260/// Helper function for ParallelUpdate that works on sensor collisions261EStatus ParallelDetermineSensorCollisions(SoftBodyUpdateContext &ioContext);262263/// Helper function for ParallelUpdate that works on batches of constraints264EStatus ParallelApplyConstraints(SoftBodyUpdateContext &ioContext, const PhysicsSettings &inPhysicsSettings);265266/// Helper function to update a single group of constraints267void ProcessGroup(const SoftBodyUpdateContext &ioContext, uint inGroupIndex);268269/// Returns 6 times the volume of the soft body270float GetVolumeTimesSix() const;271272#ifdef JPH_DEBUG_RENDERER273/// Helper function to draw constraints274template <typename GetEndIndex, typename DrawConstraint>275inline void DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const;276277RMat44 mSkinStateTransform = RMat44::sIdentity(); ///< The matrix that transforms mSkinState to world space278#endif // JPH_DEBUG_RENDERER279280RefConst<SoftBodySharedSettings> mSettings; ///< Configuration of the particles and constraints281Array<Vertex> mVertices; ///< Current state of all vertices in the simulation282Array<CollidingShape> mCollidingShapes; ///< List of colliding shapes retrieved during the last update283Array<CollidingSensor> mCollidingSensors; ///< List of colliding sensors retrieved during the last update284Array<SkinState> mSkinState; ///< List of skinned positions (1-on-1 with mVertices but only those that are used by the skinning constraints are filled in)285AABox mLocalBounds; ///< Bounding box of all vertices286AABox mLocalPredictedBounds; ///< Predicted bounding box for all vertices using extrapolation of velocity by last step delta time287uint32 mNumIterations; ///< Number of solver iterations288uint mNumSensors; ///< Workaround for TSAN false positive: store mCollidingSensors.size() in a separate variable.289float mPressure; ///< n * R * T, amount of substance * ideal gas constant * absolute temperature, see https://en.wikipedia.org/wiki/Pressure290float mSkinnedMaxDistanceMultiplier = 1.0f; ///< Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints291bool mUpdatePosition; ///< Update the position of the body while simulating (set to false for something that is attached to the static world)292atomic<bool> mNeedContactCallback = false; ///< True if the soft body has collided with anything in the last update293bool mEnableSkinConstraints = true; ///< If skin constraints are enabled294bool mSkinStatePreviousPositionValid = false; ///< True if the skinning was updated in the last update so that the previous position of the skin state is valid295};296297JPH_NAMESPACE_END298299300