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