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