Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/CompoundShape.cpp
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Physics/Collision/Shape/CompoundShape.h>
8
#include <Jolt/Physics/Collision/CollisionDispatch.h>
9
#include <Jolt/Physics/Collision/ShapeCast.h>
10
#include <Jolt/Physics/Collision/CastResult.h>
11
#include <Jolt/Physics/Collision/TransformedShape.h>
12
#include <Jolt/Core/Profiler.h>
13
#include <Jolt/Core/StreamIn.h>
14
#include <Jolt/Core/StreamOut.h>
15
#include <Jolt/ObjectStream/TypeDeclarations.h>
16
#ifdef JPH_DEBUG_RENDERER
17
#include <Jolt/Renderer/DebugRenderer.h>
18
#endif // JPH_DEBUG_RENDERER
19
20
JPH_NAMESPACE_BEGIN
21
22
JPH_IMPLEMENT_SERIALIZABLE_ABSTRACT(CompoundShapeSettings)
23
{
24
JPH_ADD_BASE_CLASS(CompoundShapeSettings, ShapeSettings)
25
26
JPH_ADD_ATTRIBUTE(CompoundShapeSettings, mSubShapes)
27
}
28
29
JPH_IMPLEMENT_SERIALIZABLE_NON_VIRTUAL(CompoundShapeSettings::SubShapeSettings)
30
{
31
JPH_ADD_ATTRIBUTE(CompoundShapeSettings::SubShapeSettings, mShape)
32
JPH_ADD_ATTRIBUTE(CompoundShapeSettings::SubShapeSettings, mPosition)
33
JPH_ADD_ATTRIBUTE(CompoundShapeSettings::SubShapeSettings, mRotation)
34
JPH_ADD_ATTRIBUTE(CompoundShapeSettings::SubShapeSettings, mUserData)
35
}
36
37
void CompoundShapeSettings::AddShape(Vec3Arg inPosition, QuatArg inRotation, const ShapeSettings *inShape, uint32 inUserData)
38
{
39
// Add shape
40
SubShapeSettings shape;
41
shape.mPosition = inPosition;
42
shape.mRotation = inRotation;
43
shape.mShape = inShape;
44
shape.mUserData = inUserData;
45
mSubShapes.push_back(shape);
46
}
47
48
void CompoundShapeSettings::AddShape(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape, uint32 inUserData)
49
{
50
// Add shape
51
SubShapeSettings shape;
52
shape.mPosition = inPosition;
53
shape.mRotation = inRotation;
54
shape.mShapePtr = inShape;
55
shape.mUserData = inUserData;
56
mSubShapes.push_back(shape);
57
}
58
59
bool CompoundShape::MustBeStatic() const
60
{
61
for (const SubShape &shape : mSubShapes)
62
if (shape.mShape->MustBeStatic())
63
return true;
64
65
return false;
66
}
67
68
MassProperties CompoundShape::GetMassProperties() const
69
{
70
MassProperties p;
71
72
// Calculate mass and inertia
73
p.mMass = 0.0f;
74
p.mInertia = Mat44::sZero();
75
for (const SubShape &shape : mSubShapes)
76
{
77
// Rotate and translate inertia of child into place
78
MassProperties child = shape.mShape->GetMassProperties();
79
child.Rotate(Mat44::sRotation(shape.GetRotation()));
80
child.Translate(shape.GetPositionCOM());
81
82
// Accumulate mass and inertia
83
p.mMass += child.mMass;
84
p.mInertia += child.mInertia;
85
}
86
87
// Ensure that inertia is a 3x3 matrix, adding inertias causes the bottom right element to change
88
p.mInertia.SetColumn4(3, Vec4(0, 0, 0, 1));
89
90
return p;
91
}
92
93
AABox CompoundShape::GetWorldSpaceBounds(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale) const
94
{
95
if (mSubShapes.empty())
96
{
97
// If there are no sub-shapes, we must return an empty box to avoid overflows in the broadphase
98
return AABox(inCenterOfMassTransform.GetTranslation(), inCenterOfMassTransform.GetTranslation());
99
}
100
else if (mSubShapes.size() <= 10)
101
{
102
AABox bounds;
103
for (const SubShape &shape : mSubShapes)
104
{
105
Mat44 transform = inCenterOfMassTransform * shape.GetLocalTransformNoScale(inScale);
106
bounds.Encapsulate(shape.mShape->GetWorldSpaceBounds(transform, shape.TransformScale(inScale)));
107
}
108
return bounds;
109
}
110
else
111
{
112
// If there are too many shapes, use the base class function (this will result in a slightly wider bounding box)
113
return Shape::GetWorldSpaceBounds(inCenterOfMassTransform, inScale);
114
}
115
}
116
117
uint CompoundShape::GetSubShapeIDBitsRecursive() const
118
{
119
// Add max of child bits to our bits
120
uint child_bits = 0;
121
for (const SubShape &shape : mSubShapes)
122
child_bits = max(child_bits, shape.mShape->GetSubShapeIDBitsRecursive());
123
return child_bits + GetSubShapeIDBits();
124
}
125
126
const PhysicsMaterial *CompoundShape::GetMaterial(const SubShapeID &inSubShapeID) const
127
{
128
// Decode sub shape index
129
SubShapeID remainder;
130
uint32 index = GetSubShapeIndexFromID(inSubShapeID, remainder);
131
132
// Pass call on
133
return mSubShapes[index].mShape->GetMaterial(remainder);
134
}
135
136
const Shape *CompoundShape::GetLeafShape(const SubShapeID &inSubShapeID, SubShapeID &outRemainder) const
137
{
138
// Decode sub shape index
139
SubShapeID remainder;
140
uint32 index = GetSubShapeIndexFromID(inSubShapeID, remainder);
141
if (index >= mSubShapes.size())
142
{
143
// No longer valid index
144
outRemainder = SubShapeID();
145
return nullptr;
146
}
147
148
// Pass call on
149
return mSubShapes[index].mShape->GetLeafShape(remainder, outRemainder);
150
}
151
152
uint64 CompoundShape::GetSubShapeUserData(const SubShapeID &inSubShapeID) const
153
{
154
// Decode sub shape index
155
SubShapeID remainder;
156
uint32 index = GetSubShapeIndexFromID(inSubShapeID, remainder);
157
if (index >= mSubShapes.size())
158
return 0; // No longer valid index
159
160
// Pass call on
161
return mSubShapes[index].mShape->GetSubShapeUserData(remainder);
162
}
163
164
TransformedShape CompoundShape::GetSubShapeTransformedShape(const SubShapeID &inSubShapeID, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, SubShapeID &outRemainder) const
165
{
166
// Get the sub shape
167
const SubShape &sub_shape = mSubShapes[GetSubShapeIndexFromID(inSubShapeID, outRemainder)];
168
169
// Calculate transform for sub shape
170
Vec3 position = inPositionCOM + inRotation * (inScale * sub_shape.GetPositionCOM());
171
Quat rotation = inRotation * sub_shape.GetRotation();
172
Vec3 scale = sub_shape.TransformScale(inScale);
173
174
// Return transformed shape
175
TransformedShape ts(RVec3(position), rotation, sub_shape.mShape, BodyID());
176
ts.SetShapeScale(scale);
177
return ts;
178
}
179
180
Vec3 CompoundShape::GetSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inLocalSurfacePosition) const
181
{
182
// Decode sub shape index
183
SubShapeID remainder;
184
uint32 index = GetSubShapeIndexFromID(inSubShapeID, remainder);
185
186
// Transform surface position to local space and pass call on
187
const SubShape &shape = mSubShapes[index];
188
Mat44 transform = Mat44::sInverseRotationTranslation(shape.GetRotation(), shape.GetPositionCOM());
189
Vec3 normal = shape.mShape->GetSurfaceNormal(remainder, transform * inLocalSurfacePosition);
190
191
// Transform normal to this shape's space
192
return transform.Multiply3x3Transposed(normal);
193
}
194
195
void CompoundShape::GetSupportingFace(const SubShapeID &inSubShapeID, Vec3Arg inDirection, Vec3Arg inScale, Mat44Arg inCenterOfMassTransform, SupportingFace &outVertices) const
196
{
197
// Decode sub shape index
198
SubShapeID remainder;
199
uint32 index = GetSubShapeIndexFromID(inSubShapeID, remainder);
200
201
// Apply transform and pass on to sub shape
202
const SubShape &shape = mSubShapes[index];
203
Mat44 transform = shape.GetLocalTransformNoScale(inScale);
204
shape.mShape->GetSupportingFace(remainder, transform.Multiply3x3Transposed(inDirection), shape.TransformScale(inScale), inCenterOfMassTransform * transform, outVertices);
205
}
206
207
void CompoundShape::GetSubmergedVolume(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const Plane &inSurface, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outCenterOfBuoyancy JPH_IF_DEBUG_RENDERER(, RVec3Arg inBaseOffset)) const
208
{
209
outTotalVolume = 0.0f;
210
outSubmergedVolume = 0.0f;
211
outCenterOfBuoyancy = Vec3::sZero();
212
213
for (const SubShape &shape : mSubShapes)
214
{
215
// Get center of mass transform of child
216
Mat44 transform = inCenterOfMassTransform * shape.GetLocalTransformNoScale(inScale);
217
218
// Recurse to child
219
float total_volume, submerged_volume;
220
Vec3 center_of_buoyancy;
221
shape.mShape->GetSubmergedVolume(transform, shape.TransformScale(inScale), inSurface, total_volume, submerged_volume, center_of_buoyancy JPH_IF_DEBUG_RENDERER(, inBaseOffset));
222
223
// Accumulate volumes
224
outTotalVolume += total_volume;
225
outSubmergedVolume += submerged_volume;
226
227
// The center of buoyancy is the weighted average of the center of buoyancy of our child shapes
228
outCenterOfBuoyancy += submerged_volume * center_of_buoyancy;
229
}
230
231
if (outSubmergedVolume > 0.0f)
232
outCenterOfBuoyancy /= outSubmergedVolume;
233
234
#ifdef JPH_DEBUG_RENDERER
235
// Draw center of buoyancy
236
if (sDrawSubmergedVolumes)
237
DebugRenderer::sInstance->DrawWireSphere(inBaseOffset + outCenterOfBuoyancy, 0.05f, Color::sRed, 1);
238
#endif // JPH_DEBUG_RENDERER
239
}
240
241
#ifdef JPH_DEBUG_RENDERER
242
void CompoundShape::Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const
243
{
244
for (const SubShape &shape : mSubShapes)
245
{
246
Mat44 transform = shape.GetLocalTransformNoScale(inScale);
247
shape.mShape->Draw(inRenderer, inCenterOfMassTransform * transform, shape.TransformScale(inScale), inColor, inUseMaterialColors, inDrawWireframe);
248
}
249
}
250
251
void CompoundShape::DrawGetSupportFunction(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inDrawSupportDirection) const
252
{
253
for (const SubShape &shape : mSubShapes)
254
{
255
Mat44 transform = shape.GetLocalTransformNoScale(inScale);
256
shape.mShape->DrawGetSupportFunction(inRenderer, inCenterOfMassTransform * transform, shape.TransformScale(inScale), inColor, inDrawSupportDirection);
257
}
258
}
259
260
void CompoundShape::DrawGetSupportingFace(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale) const
261
{
262
for (const SubShape &shape : mSubShapes)
263
{
264
Mat44 transform = shape.GetLocalTransformNoScale(inScale);
265
shape.mShape->DrawGetSupportingFace(inRenderer, inCenterOfMassTransform * transform, shape.TransformScale(inScale));
266
}
267
}
268
#endif // JPH_DEBUG_RENDERER
269
270
void CompoundShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const CollideSoftBodyVertexIterator &inVertices, uint inNumVertices, int inCollidingShapeIndex) const
271
{
272
for (const SubShape &shape : mSubShapes)
273
{
274
Mat44 transform = shape.GetLocalTransformNoScale(inScale);
275
shape.mShape->CollideSoftBodyVertices(inCenterOfMassTransform * transform, shape.TransformScale(inScale), inVertices, inNumVertices, inCollidingShapeIndex);
276
}
277
}
278
279
void CompoundShape::TransformShape(Mat44Arg inCenterOfMassTransform, TransformedShapeCollector &ioCollector) const
280
{
281
for (const SubShape &shape : mSubShapes)
282
shape.mShape->TransformShape(inCenterOfMassTransform * Mat44::sRotationTranslation(shape.GetRotation(), shape.GetPositionCOM()), ioCollector);
283
}
284
285
void CompoundShape::sCastCompoundVsShape(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
286
{
287
JPH_PROFILE_FUNCTION();
288
289
// Fetch compound shape from cast shape
290
JPH_ASSERT(inShapeCast.mShape->GetType() == EShapeType::Compound);
291
const CompoundShape *compound = static_cast<const CompoundShape *>(inShapeCast.mShape);
292
293
// Number of sub shapes
294
int n = (int)compound->mSubShapes.size();
295
296
// Determine amount of bits for sub shape
297
uint sub_shape_bits = compound->GetSubShapeIDBits();
298
299
// Recurse to sub shapes
300
for (int i = 0; i < n; ++i)
301
{
302
const SubShape &shape = compound->mSubShapes[i];
303
304
// Create ID for sub shape
305
SubShapeIDCreator shape1_sub_shape_id = inSubShapeIDCreator1.PushID(i, sub_shape_bits);
306
307
// Transform the shape cast and update the shape
308
Mat44 transform = inShapeCast.mCenterOfMassStart * shape.GetLocalTransformNoScale(inShapeCast.mScale);
309
Vec3 scale = shape.TransformScale(inShapeCast.mScale);
310
ShapeCast shape_cast(shape.mShape, scale, transform, inShapeCast.mDirection);
311
312
CollisionDispatch::sCastShapeVsShapeLocalSpace(shape_cast, inShapeCastSettings, inShape, inScale, inShapeFilter, inCenterOfMassTransform2, shape1_sub_shape_id, inSubShapeIDCreator2, ioCollector);
313
314
if (ioCollector.ShouldEarlyOut())
315
break;
316
}
317
}
318
319
void CompoundShape::SaveBinaryState(StreamOut &inStream) const
320
{
321
Shape::SaveBinaryState(inStream);
322
323
inStream.Write(mCenterOfMass);
324
inStream.Write(mLocalBounds.mMin);
325
inStream.Write(mLocalBounds.mMax);
326
inStream.Write(mInnerRadius);
327
328
// Write sub shapes
329
inStream.Write(mSubShapes, [](const SubShape &inElement, StreamOut &inS) {
330
inS.Write(inElement.mUserData);
331
inS.Write(inElement.mPositionCOM);
332
inS.Write(inElement.mRotation);
333
});
334
}
335
336
void CompoundShape::RestoreBinaryState(StreamIn &inStream)
337
{
338
Shape::RestoreBinaryState(inStream);
339
340
inStream.Read(mCenterOfMass);
341
inStream.Read(mLocalBounds.mMin);
342
inStream.Read(mLocalBounds.mMax);
343
inStream.Read(mInnerRadius);
344
345
// Read sub shapes
346
inStream.Read(mSubShapes, [](StreamIn &inS, SubShape &outElement) {
347
inS.Read(outElement.mUserData);
348
inS.Read(outElement.mPositionCOM);
349
inS.Read(outElement.mRotation);
350
outElement.mIsRotationIdentity = outElement.mRotation == Float3(0, 0, 0);
351
});
352
}
353
354
void CompoundShape::SaveSubShapeState(ShapeList &outSubShapes) const
355
{
356
outSubShapes.clear();
357
outSubShapes.reserve(mSubShapes.size());
358
for (const SubShape &shape : mSubShapes)
359
outSubShapes.push_back(shape.mShape);
360
}
361
362
void CompoundShape::RestoreSubShapeState(const ShapeRefC *inSubShapes, uint inNumShapes)
363
{
364
JPH_ASSERT(mSubShapes.size() == inNumShapes);
365
for (uint i = 0; i < inNumShapes; ++i)
366
mSubShapes[i].mShape = inSubShapes[i];
367
}
368
369
Shape::Stats CompoundShape::GetStatsRecursive(VisitedShapes &ioVisitedShapes) const
370
{
371
// Get own stats
372
Stats stats = Shape::GetStatsRecursive(ioVisitedShapes);
373
374
// Add child stats
375
for (const SubShape &shape : mSubShapes)
376
{
377
Stats child_stats = shape.mShape->GetStatsRecursive(ioVisitedShapes);
378
stats.mSizeBytes += child_stats.mSizeBytes;
379
stats.mNumTriangles += child_stats.mNumTriangles;
380
}
381
382
return stats;
383
}
384
385
float CompoundShape::GetVolume() const
386
{
387
float volume = 0.0f;
388
for (const SubShape &shape : mSubShapes)
389
volume += shape.mShape->GetVolume();
390
return volume;
391
}
392
393
bool CompoundShape::IsValidScale(Vec3Arg inScale) const
394
{
395
if (!Shape::IsValidScale(inScale))
396
return false;
397
398
for (const SubShape &shape : mSubShapes)
399
{
400
// Test if the scale is non-uniform and the shape is rotated
401
if (!shape.IsValidScale(inScale))
402
return false;
403
404
// Test the child shape
405
if (!shape.mShape->IsValidScale(shape.TransformScale(inScale)))
406
return false;
407
}
408
409
return true;
410
}
411
412
Vec3 CompoundShape::MakeScaleValid(Vec3Arg inScale) const
413
{
414
Vec3 scale = ScaleHelpers::MakeNonZeroScale(inScale);
415
if (CompoundShape::IsValidScale(scale))
416
return scale;
417
418
Vec3 abs_uniform_scale = ScaleHelpers::MakeUniformScale(scale.Abs());
419
Vec3 uniform_scale = scale.GetSign() * abs_uniform_scale;
420
if (CompoundShape::IsValidScale(uniform_scale))
421
return uniform_scale;
422
423
return Sign(scale.GetX()) * abs_uniform_scale;
424
}
425
426
void CompoundShape::sRegister()
427
{
428
for (EShapeSubType s1 : sCompoundSubShapeTypes)
429
for (EShapeSubType s2 : sAllSubShapeTypes)
430
CollisionDispatch::sRegisterCastShape(s1, s2, sCastCompoundVsShape);
431
}
432
433
JPH_NAMESPACE_END
434
435