Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodySharedSettings.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/Core/Reference.h>
8
#include <Jolt/Physics/Collision/PhysicsMaterial.h>
9
#include <Jolt/Core/StreamUtils.h>
10
11
JPH_NAMESPACE_BEGIN
12
13
/// This class defines the setup of all particles and their constraints.
14
/// It is used during the simulation and can be shared between multiple soft bodies.
15
class JPH_EXPORT SoftBodySharedSettings : public RefTarget<SoftBodySharedSettings>
16
{
17
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, SoftBodySharedSettings)
18
19
public:
20
/// Which type of bend constraint should be created
21
enum class EBendType
22
{
23
None, ///< No bend constraints will be created
24
Distance, ///< A simple distance constraint
25
Dihedral, ///< A dihedral bend constraint (most expensive, but also supports triangles that are initially not in the same plane)
26
};
27
28
/// The type of long range attachment constraint to create
29
enum class ELRAType
30
{
31
None, ///< Don't create a LRA constraint
32
EuclideanDistance, ///< Create a LRA constraint based on Euclidean distance between the closest kinematic vertex and this vertex
33
GeodesicDistance, ///< Create a LRA constraint based on the geodesic distance between the closest kinematic vertex and this vertex (follows the edge constraints)
34
};
35
36
/// Per vertex attributes used during the CreateConstraints function.
37
/// For an edge or shear constraint, the compliance is averaged between the two attached vertices.
38
/// For a bend constraint, the compliance is averaged between the two vertices on the shared edge.
39
struct JPH_EXPORT VertexAttributes
40
{
41
/// Constructor
42
VertexAttributes() = default;
43
VertexAttributes(float inCompliance, float inShearCompliance, float inBendCompliance, ELRAType inLRAType = ELRAType::None, float inLRAMaxDistanceMultiplier = 1.0f) : mCompliance(inCompliance), mShearCompliance(inShearCompliance), mBendCompliance(inBendCompliance), mLRAType(inLRAType), mLRAMaxDistanceMultiplier(inLRAMaxDistanceMultiplier) { }
44
45
float mCompliance = 0.0f; ///< The compliance of the normal edges. Set to FLT_MAX to disable regular edges for any edge involving this vertex.
46
float mShearCompliance = 0.0f; ///< The compliance of the shear edges. Set to FLT_MAX to disable shear edges for any edge involving this vertex.
47
float mBendCompliance = FLT_MAX; ///< The compliance of the bend edges. Set to FLT_MAX to disable bend edges for any bend constraint involving this vertex.
48
ELRAType mLRAType = ELRAType::None; ///< The type of long range attachment constraint to create.
49
float mLRAMaxDistanceMultiplier = 1.0f; ///< Multiplier for the max distance of the LRA constraint, e.g. 1.01 means the max distance is 1% longer than the calculated distance in the rest pose.
50
};
51
52
/// Automatically create constraints based on the faces of the soft body
53
/// @param inVertexAttributes A list of attributes for each vertex (1-on-1 with mVertices, note that if the list is smaller than mVertices the last element will be repeated). This defines the properties of the constraints that are created.
54
/// @param inVertexAttributesLength The length of inVertexAttributes
55
/// @param inBendType The type of bend constraint to create
56
/// @param inAngleTolerance Shear edges are created when two connected triangles form a quad (are roughly in the same plane and form a square with roughly 90 degree angles). This defines the tolerance (in radians).
57
void CreateConstraints(const VertexAttributes *inVertexAttributes, uint inVertexAttributesLength, EBendType inBendType = EBendType::Distance, float inAngleTolerance = DegreesToRadians(8.0f));
58
59
/// Calculate the initial lengths of all springs of the edges of this soft body (if you use CreateConstraint, this is already done)
60
void CalculateEdgeLengths();
61
62
/// Calculate the max lengths for the long range attachment constraints based on Euclidean distance (if you use CreateConstraints, this is already done)
63
/// @param inMaxDistanceMultiplier Multiplier for the max distance of the LRA constraint, e.g. 1.01 means the max distance is 1% longer than the calculated distance in the rest pose.
64
void CalculateLRALengths(float inMaxDistanceMultiplier = 1.0f);
65
66
/// Calculate the constants for the bend constraints (if you use CreateConstraints, this is already done)
67
void CalculateBendConstraintConstants();
68
69
/// Calculates the initial volume of all tetrahedra of this soft body
70
void CalculateVolumeConstraintVolumes();
71
72
/// Calculate information needed to be able to calculate the skinned constraint normals at run-time
73
void CalculateSkinnedConstraintNormals();
74
75
/// Information about the optimization of the soft body, the indices of certain elements may have changed.
76
class OptimizationResults
77
{
78
public:
79
Array<uint> mEdgeRemap; ///< Maps old edge index to new edge index
80
Array<uint> mLRARemap; ///< Maps old LRA index to new LRA index
81
Array<uint> mDihedralBendRemap; ///< Maps old dihedral bend index to new dihedral bend index
82
Array<uint> mVolumeRemap; ///< Maps old volume constraint index to new volume constraint index
83
Array<uint> mSkinnedRemap; ///< Maps old skinned constraint index to new skinned constraint index
84
};
85
86
/// Optimize the soft body settings for simulation. This will reorder constraints so they can be executed in parallel.
87
void Optimize(OptimizationResults &outResults);
88
89
/// Optimize the soft body settings without results
90
void Optimize() { OptimizationResults results; Optimize(results); }
91
92
/// Clone this object
93
Ref<SoftBodySharedSettings> Clone() const;
94
95
/// Saves the state of this object in binary form to inStream. Doesn't store the material list.
96
void SaveBinaryState(StreamOut &inStream) const;
97
98
/// Restore the state of this object from inStream. Doesn't restore the material list.
99
void RestoreBinaryState(StreamIn &inStream);
100
101
using SharedSettingsToIDMap = StreamUtils::ObjectToIDMap<SoftBodySharedSettings>;
102
using IDToSharedSettingsMap = StreamUtils::IDToObjectMap<SoftBodySharedSettings>;
103
using MaterialToIDMap = StreamUtils::ObjectToIDMap<PhysicsMaterial>;
104
using IDToMaterialMap = StreamUtils::IDToObjectMap<PhysicsMaterial>;
105
106
/// Save this shared settings and its materials. Pass in an empty map ioSettingsMap / ioMaterialMap or reuse the same map while saving multiple settings objects to the same stream in order to avoid writing duplicates.
107
void SaveWithMaterials(StreamOut &inStream, SharedSettingsToIDMap &ioSettingsMap, MaterialToIDMap &ioMaterialMap) const;
108
109
using SettingsResult = Result<Ref<SoftBodySharedSettings>>;
110
111
/// Restore a shape and materials. Pass in an empty map in ioSettingsMap / ioMaterialMap or reuse the same map while reading multiple settings objects from the same stream in order to restore duplicates.
112
static SettingsResult sRestoreWithMaterials(StreamIn &inStream, IDToSharedSettingsMap &ioSettingsMap, IDToMaterialMap &ioMaterialMap);
113
114
/// Create a cube. This can be used to create a simple soft body for testing purposes.
115
/// It will contain edge constraints, volume constraints and faces.
116
/// @param inGridSize Number of points along each axis
117
/// @param inGridSpacing Distance between points
118
static Ref<SoftBodySharedSettings> sCreateCube(uint inGridSize, float inGridSpacing);
119
120
/// A vertex is a particle, the data in this structure is only used during creation of the soft body and not during simulation
121
struct JPH_EXPORT Vertex
122
{
123
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Vertex)
124
125
/// Constructor
126
Vertex() = default;
127
Vertex(const Float3 &inPosition, const Float3 &inVelocity = Float3(0, 0, 0), float inInvMass = 1.0f) : mPosition(inPosition), mVelocity(inVelocity), mInvMass(inInvMass) { }
128
129
Float3 mPosition { 0, 0, 0 }; ///< Initial position of the vertex
130
Float3 mVelocity { 0, 0, 0 }; ///< Initial velocity of the vertex
131
float mInvMass = 1.0f; ///< Initial inverse of the mass of the vertex
132
};
133
134
/// A face defines the surface of the body
135
struct JPH_EXPORT Face
136
{
137
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Face)
138
139
/// Constructor
140
Face() = default;
141
Face(uint32 inVertex1, uint32 inVertex2, uint32 inVertex3, uint32 inMaterialIndex = 0) : mVertex { inVertex1, inVertex2, inVertex3 }, mMaterialIndex(inMaterialIndex) { }
142
143
/// Check if this is a degenerate face (a face which points to the same vertex twice)
144
bool IsDegenerate() const { return mVertex[0] == mVertex[1] || mVertex[0] == mVertex[2] || mVertex[1] == mVertex[2]; }
145
146
uint32 mVertex[3]; ///< Indices of the vertices that form the face
147
uint32 mMaterialIndex = 0; ///< Index of the material of the face in SoftBodySharedSettings::mMaterials
148
};
149
150
/// An edge keeps two vertices at a constant distance using a spring: |x1 - x2| = rest length
151
struct JPH_EXPORT Edge
152
{
153
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Edge)
154
155
/// Constructor
156
Edge() = default;
157
Edge(uint32 inVertex1, uint32 inVertex2, float inCompliance = 0.0f) : mVertex { inVertex1, inVertex2 }, mCompliance(inCompliance) { }
158
159
/// Return the lowest vertex index of this constraint
160
uint32 GetMinVertexIndex() const { return min(mVertex[0], mVertex[1]); }
161
162
uint32 mVertex[2]; ///< Indices of the vertices that form the edge
163
float mRestLength = 1.0f; ///< Rest length of the spring
164
float mCompliance = 0.0f; ///< Inverse of the stiffness of the spring
165
};
166
167
/**
168
* A dihedral bend constraint keeps the angle between two triangles constant along their shared edge.
169
*
170
* x2
171
* / \
172
* / t0 \
173
* x0----x1
174
* \ t1 /
175
* \ /
176
* x3
177
*
178
* x0..x3 are the vertices, t0 and t1 are the triangles that share the edge x0..x1
179
*
180
* Based on:
181
* - "Position Based Dynamics" - Matthias Muller et al.
182
* - "Strain Based Dynamics" - Matthias Muller et al.
183
* - "Simulation of Clothing with Folds and Wrinkles" - R. Bridson et al.
184
*/
185
struct JPH_EXPORT DihedralBend
186
{
187
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, DihedralBend)
188
189
/// Constructor
190
DihedralBend() = default;
191
DihedralBend(uint32 inVertex1, uint32 inVertex2, uint32 inVertex3, uint32 inVertex4, float inCompliance = 0.0f) : mVertex { inVertex1, inVertex2, inVertex3, inVertex4 }, mCompliance(inCompliance) { }
192
193
/// Return the lowest vertex index of this constraint
194
uint32 GetMinVertexIndex() const { return min(min(mVertex[0], mVertex[1]), min(mVertex[2], mVertex[3])); }
195
196
uint32 mVertex[4]; ///< Indices of the vertices of the 2 triangles that share an edge (the first 2 vertices are the shared edge)
197
float mCompliance = 0.0f; ///< Inverse of the stiffness of the constraint
198
float mInitialAngle = 0.0f; ///< Initial angle between the normals of the triangles (pi - dihedral angle).
199
};
200
201
/// Volume constraint, keeps the volume of a tetrahedron constant
202
struct JPH_EXPORT Volume
203
{
204
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Volume)
205
206
/// Constructor
207
Volume() = default;
208
Volume(uint32 inVertex1, uint32 inVertex2, uint32 inVertex3, uint32 inVertex4, float inCompliance = 0.0f) : mVertex { inVertex1, inVertex2, inVertex3, inVertex4 }, mCompliance(inCompliance) { }
209
210
/// Return the lowest vertex index of this constraint
211
uint32 GetMinVertexIndex() const { return min(min(mVertex[0], mVertex[1]), min(mVertex[2], mVertex[3])); }
212
213
uint32 mVertex[4]; ///< Indices of the vertices that form the tetrahedron
214
float mSixRestVolume = 1.0f; ///< 6 times the rest volume of the tetrahedron (calculated by CalculateVolumeConstraintVolumes())
215
float mCompliance = 0.0f; ///< Inverse of the stiffness of the constraint
216
};
217
218
/// An inverse bind matrix take a skinned vertex from its bind pose into joint local space
219
class JPH_EXPORT InvBind
220
{
221
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, InvBind)
222
223
public:
224
/// Constructor
225
InvBind() = default;
226
InvBind(uint32 inJointIndex, Mat44Arg inInvBind) : mJointIndex(inJointIndex), mInvBind(inInvBind) { }
227
228
uint32 mJointIndex = 0; ///< Joint index to which this is attached
229
Mat44 mInvBind = Mat44::sIdentity(); ///< The inverse bind matrix, this takes a vertex in its bind pose (Vertex::mPosition) to joint local space
230
};
231
232
/// A joint and its skin weight
233
class JPH_EXPORT SkinWeight
234
{
235
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, SkinWeight)
236
237
public:
238
/// Constructor
239
SkinWeight() = default;
240
SkinWeight(uint32 inInvBindIndex, float inWeight) : mInvBindIndex(inInvBindIndex), mWeight(inWeight) { }
241
242
uint32 mInvBindIndex = 0; ///< Index in mInvBindMatrices
243
float mWeight = 0.0f; ///< Weight with which it is skinned
244
};
245
246
/// A constraint that skins a vertex to joints and limits the distance that the simulated vertex can travel from this vertex
247
class JPH_EXPORT Skinned
248
{
249
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Skinned)
250
251
public:
252
/// Constructor
253
Skinned() = default;
254
Skinned(uint32 inVertex, float inMaxDistance, float inBackStopDistance, float inBackStopRadius) : mVertex(inVertex), mMaxDistance(inMaxDistance), mBackStopDistance(inBackStopDistance), mBackStopRadius(inBackStopRadius) { }
255
256
/// Normalize the weights so that they add up to 1
257
void NormalizeWeights()
258
{
259
// Get the total weight
260
float total = 0.0f;
261
for (const SkinWeight &w : mWeights)
262
total += w.mWeight;
263
264
// Normalize
265
if (total > 0.0f)
266
for (SkinWeight &w : mWeights)
267
w.mWeight /= total;
268
}
269
270
/// Maximum number of skin weights
271
static constexpr uint cMaxSkinWeights = 4;
272
273
uint32 mVertex = 0; ///< Index in mVertices which indicates which vertex is being skinned
274
SkinWeight mWeights[cMaxSkinWeights]; ///< Skin weights, the bind pose of the vertex is assumed to be stored in Vertex::mPosition. The first weight that is zero indicates the end of the list. Weights should add up to 1.
275
float mMaxDistance = FLT_MAX; ///< Maximum distance that this vertex can reach from the skinned vertex, disabled when FLT_MAX. 0 when you want to hard skin the vertex to the skinned vertex.
276
float mBackStopDistance = FLT_MAX; ///< Disabled if mBackStopDistance >= mMaxDistance. The faces surrounding mVertex determine an average normal. mBackStopDistance behind the vertex in the opposite direction of this normal, the back stop sphere starts. The simulated vertex will be pushed out of this sphere and it can be used to approximate the volume of the skinned mesh behind the skinned vertex.
277
float mBackStopRadius = 40.0f; ///< Radius of the backstop sphere. By default this is a fairly large radius so the sphere approximates a plane.
278
uint32 mNormalInfo = 0; ///< Information needed to calculate the normal of this vertex, lowest 24 bit is start index in mSkinnedConstraintNormals, highest 8 bit is number of faces (generated by CalculateSkinnedConstraintNormals())
279
};
280
281
/// A long range attachment constraint, this is a constraint that sets a max distance between a kinematic vertex and a dynamic vertex
282
/// See: "Long Range Attachments - A Method to Simulate Inextensible Clothing in Computer Games", Tae-Yong Kim, Nuttapong Chentanez and Matthias Mueller-Fischer
283
class JPH_EXPORT LRA
284
{
285
JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, LRA)
286
287
public:
288
/// Constructor
289
LRA() = default;
290
LRA(uint32 inVertex1, uint32 inVertex2, float inMaxDistance) : mVertex { inVertex1, inVertex2 }, mMaxDistance(inMaxDistance) { }
291
292
/// Return the lowest vertex index of this constraint
293
uint32 GetMinVertexIndex() const { return min(mVertex[0], mVertex[1]); }
294
295
uint32 mVertex[2]; ///< The vertices that are connected. The first vertex should be kinematic, the 2nd dynamic.
296
float mMaxDistance = 0.0f; ///< The maximum distance between the vertices
297
};
298
299
/// Add a face to this soft body
300
void AddFace(const Face &inFace) { JPH_ASSERT(!inFace.IsDegenerate()); mFaces.push_back(inFace); }
301
302
Array<Vertex> mVertices; ///< The list of vertices or particles of the body
303
Array<Face> mFaces; ///< The list of faces of the body
304
Array<Edge> mEdgeConstraints; ///< The list of edges or springs of the body
305
Array<DihedralBend> mDihedralBendConstraints; ///< The list of dihedral bend constraints of the body
306
Array<Volume> mVolumeConstraints; ///< The list of volume constraints of the body that keep the volume of tetrahedra in the soft body constant
307
Array<Skinned> mSkinnedConstraints; ///< The list of vertices that are constrained to a skinned vertex
308
Array<InvBind> mInvBindMatrices; ///< The list of inverse bind matrices for skinning vertices
309
Array<LRA> mLRAConstraints; ///< The list of long range attachment constraints
310
PhysicsMaterialList mMaterials { PhysicsMaterial::sDefault }; ///< The materials of the faces of the body, referenced by Face::mMaterialIndex
311
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
312
313
private:
314
friend class SoftBodyMotionProperties;
315
316
/// Calculate the closest kinematic vertex array
317
void CalculateClosestKinematic();
318
319
/// Tracks the closest kinematic vertex
320
struct ClosestKinematic
321
{
322
uint32 mVertex = 0xffffffff; ///< Vertex index of closest kinematic vertex
323
float mDistance = FLT_MAX; ///< Distance to the closest kinematic vertex
324
};
325
326
/// Tracks the end indices of the various constraint groups
327
struct UpdateGroup
328
{
329
uint mEdgeEndIndex; ///< The end index of the edge constraints in this group
330
uint mLRAEndIndex; ///< The end index of the LRA constraints in this group
331
uint mDihedralBendEndIndex; ///< The end index of the dihedral bend constraints in this group
332
uint mVolumeEndIndex; ///< The end index of the volume constraints in this group
333
uint mSkinnedEndIndex; ///< The end index of the skinned constraints in this group
334
};
335
336
Array<ClosestKinematic> mClosestKinematic; ///< The closest kinematic vertex to each vertex in mVertices
337
Array<UpdateGroup> mUpdateGroups; ///< The end indices for each group of constraints that can be updated in parallel
338
Array<uint32> mSkinnedConstraintNormals; ///< A list of indices in the mFaces array used by mSkinnedConstraints, calculated by CalculateSkinnedConstraintNormals()
339
};
340
341
JPH_NAMESPACE_END
342
343