Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/ContactConstraintManager.h
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Core/StaticArray.h>
8
#include <Jolt/Core/LockFreeHashMap.h>
9
#include <Jolt/Physics/EPhysicsUpdateError.h>
10
#include <Jolt/Physics/Body/BodyPair.h>
11
#include <Jolt/Physics/Collision/Shape/SubShapeIDPair.h>
12
#include <Jolt/Physics/Collision/ManifoldBetweenTwoFaces.h>
13
#include <Jolt/Physics/Constraints/ConstraintPart/AxisConstraintPart.h>
14
#include <Jolt/Physics/Constraints/ConstraintPart/DualAxisConstraintPart.h>
15
#include <Jolt/Core/HashCombine.h>
16
#include <Jolt/Core/NonCopyable.h>
17
18
JPH_SUPPRESS_WARNINGS_STD_BEGIN
19
#include <atomic>
20
JPH_SUPPRESS_WARNINGS_STD_END
21
22
JPH_NAMESPACE_BEGIN
23
24
struct PhysicsSettings;
25
class PhysicsUpdateContext;
26
27
class JPH_EXPORT ContactConstraintManager : public NonCopyable
28
{
29
public:
30
JPH_OVERRIDE_NEW_DELETE
31
32
/// Constructor
33
explicit ContactConstraintManager(const PhysicsSettings &inPhysicsSettings);
34
~ContactConstraintManager();
35
36
/// Initialize the system.
37
/// @param inMaxBodyPairs Maximum amount of body pairs to process (anything else will fall through the world), this number should generally be much higher than the max amount of contact points as there will be lots of bodies close that are not actually touching
38
/// @param inMaxContactConstraints Maximum amount of contact constraints to process (anything else will fall through the world)
39
void Init(uint inMaxBodyPairs, uint inMaxContactConstraints);
40
41
/// Listener that is notified whenever a contact point between two bodies is added/updated/removed
42
void SetContactListener(ContactListener *inListener) { mContactListener = inListener; }
43
ContactListener * GetContactListener() const { return mContactListener; }
44
45
/// Callback function to combine the restitution or friction of two bodies
46
/// Note that when merging manifolds (when PhysicsSettings::mUseManifoldReduction is true) you will only get a callback for the merged manifold.
47
/// It is not possible in that case to get all sub shape ID pairs that were colliding, you'll get the first encountered pair.
48
using CombineFunction = float (*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2);
49
50
/// Set the function that combines the friction of two bodies and returns it
51
/// Default method is the geometric mean: sqrt(friction1 * friction2).
52
void SetCombineFriction(CombineFunction inCombineFriction) { mCombineFriction = inCombineFriction; }
53
CombineFunction GetCombineFriction() const { return mCombineFriction; }
54
55
/// Set the function that combines the restitution of two bodies and returns it
56
/// Default method is max(restitution1, restitution1)
57
void SetCombineRestitution(CombineFunction inCombineRestitution) { mCombineRestitution = inCombineRestitution; }
58
CombineFunction GetCombineRestitution() const { return mCombineRestitution; }
59
60
/// Get the max number of contact constraints that are allowed
61
uint32 GetMaxConstraints() const { return mMaxConstraints; }
62
63
/// Check with the listener if inBody1 and inBody2 could collide, returns false if not
64
inline ValidateResult ValidateContactPoint(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) const
65
{
66
if (mContactListener == nullptr)
67
return ValidateResult::AcceptAllContactsForThisBodyPair;
68
69
return mContactListener->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
70
}
71
72
/// Sets up the constraint buffer. Should be called before starting collision detection.
73
void PrepareConstraintBuffer(PhysicsUpdateContext *inContext);
74
75
/// Max 4 contact points are needed for a stable manifold
76
static const int MaxContactPoints = 4;
77
78
/// Contacts are allocated in a lock free hash map
79
class ContactAllocator : public LFHMAllocatorContext
80
{
81
public:
82
using LFHMAllocatorContext::LFHMAllocatorContext;
83
84
uint mNumBodyPairs = 0; ///< Total number of body pairs added using this allocator
85
uint mNumManifolds = 0; ///< Total number of manifolds added using this allocator
86
EPhysicsUpdateError mErrors = EPhysicsUpdateError::None; ///< Errors reported on this allocator
87
};
88
89
/// Get a new allocator context for storing contacts. Note that you should call this once and then add multiple contacts using the context.
90
ContactAllocator GetContactAllocator() { return mCache[mCacheWriteIdx].GetContactAllocator(); }
91
92
/// Check if the contact points from the previous frame are reusable and if so copy them.
93
/// When the cache was usable and the pair has been handled: outPairHandled = true.
94
/// When a contact constraint was produced: outConstraintCreated = true.
95
void GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outConstraintCreated);
96
97
/// Handle used to keep track of the current body pair
98
using BodyPairHandle = void *;
99
100
/// Create a handle for a colliding body pair so that contact constraints can be added between them.
101
/// Needs to be called once per body pair per frame before calling AddContactConstraint.
102
BodyPairHandle AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2);
103
104
/// Add a contact constraint for this frame.
105
///
106
/// @param ioContactAllocator The allocator that reserves memory for the contacts
107
/// @param inBodyPair The handle for the contact cache for this body pair
108
/// @param inBody1 The first body that is colliding
109
/// @param inBody2 The second body that is colliding
110
/// @param inManifold The manifold that describes the collision
111
/// @return true if a contact constraint was created (can be false in the case of a sensor)
112
///
113
/// This is using the approach described in 'Modeling and Solving Constraints' by Erin Catto presented at GDC 2009 (and later years with slight modifications).
114
/// We're using the formulas from slide 50 - 53 combined.
115
///
116
/// Euler velocity integration:
117
///
118
/// v1' = v1 + M^-1 P
119
///
120
/// Impulse:
121
///
122
/// P = J^T lambda
123
///
124
/// Constraint force:
125
///
126
/// lambda = -K^-1 J v1
127
///
128
/// Inverse effective mass:
129
///
130
/// K = J M^-1 J^T
131
///
132
/// Constraint equation (limits movement in 1 axis):
133
///
134
/// C = (p2 - p1) . n
135
///
136
/// Jacobian (for position constraint)
137
///
138
/// J = [-n, -r1 x n, n, r2 x n]
139
///
140
/// n = contact normal (pointing away from body 1).
141
/// p1, p2 = positions of collision on body 1 and 2.
142
/// r1, r2 = contact point relative to center of mass of body 1 and body 2 (r1 = p1 - x1, r2 = p2 - x2).
143
/// v1, v2 = (linear velocity, angular velocity): 6 vectors containing linear and angular velocity for body 1 and 2.
144
/// M = mass matrix, a diagonal matrix of the mass and inertia with diagonal [m1, I1, m2, I2].
145
bool AddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPair, Body &inBody1, Body &inBody2, const ContactManifold &inManifold);
146
147
/// Finalizes the contact cache, the contact cache that was generated during the calls to AddContactConstraint in this update
148
/// will be used from now on to read from. After finalizing the contact cache, the contact removed callbacks will be called.
149
/// inExpectedNumBodyPairs / inExpectedNumManifolds are the amount of body pairs / manifolds found in the previous step and is
150
/// used to determine the amount of buckets the contact cache hash map will use in the next update.
151
void FinalizeContactCacheAndCallContactPointRemovedCallbacks(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
152
153
/// Check if 2 bodies were in contact during the last simulation step. Since contacts are only detected between active bodies, at least one of the bodies must be active.
154
/// Uses the read collision cache to determine if 2 bodies are in contact.
155
bool WereBodiesInContact(const BodyID &inBody1ID, const BodyID &inBody2ID) const;
156
157
/// Get the number of contact constraints that were found
158
uint32 GetNumConstraints() const { return min<uint32>(mNumConstraints, mMaxConstraints); }
159
160
/// Sort contact constraints deterministically
161
void SortContacts(uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd) const;
162
163
/// Get the affected bodies for a given constraint
164
inline void GetAffectedBodies(uint32 inConstraintIdx, const Body *&outBody1, const Body *&outBody2) const
165
{
166
const ContactConstraint &constraint = mConstraints[inConstraintIdx];
167
outBody1 = constraint.mBody1;
168
outBody2 = constraint.mBody2;
169
}
170
171
/// Apply last frame's impulses as an initial guess for this frame's impulses
172
template <class MotionPropertiesCallback>
173
void WarmStartVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, MotionPropertiesCallback &ioCallback);
174
175
/// Solve velocity constraints, when almost nothing changes this should only apply very small impulses
176
/// since we're warm starting with the total impulse applied in the last frame above.
177
///
178
/// Friction wise we're using the Coulomb friction model which says that:
179
///
180
/// |F_T| <= mu |F_N|
181
///
182
/// Where F_T is the tangential force, F_N is the normal force and mu is the friction coefficient
183
///
184
/// In impulse terms this becomes:
185
///
186
/// |lambda_T| <= mu |lambda_N|
187
///
188
/// And the constraint that needs to be applied is exactly the same as a non penetration constraint
189
/// except that we use a tangent instead of a normal. The tangent should point in the direction of the
190
/// tangential velocity of the point:
191
///
192
/// J = [-T, -r1 x T, T, r2 x T]
193
///
194
/// Where T is the tangent.
195
///
196
/// See slide 42 and 43.
197
///
198
/// Restitution is implemented as a velocity bias (see slide 41):
199
///
200
/// b = e v_n^-
201
///
202
/// e = the restitution coefficient, v_n^- is the normal velocity prior to the collision
203
///
204
/// Restitution is only applied when v_n^- is large enough and the points are moving towards collision
205
bool SolveVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd);
206
207
/// Save back the lambdas to the contact cache for the next warm start
208
void StoreAppliedImpulses(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const;
209
210
/// Solve position constraints.
211
/// This is using the approach described in 'Modeling and Solving Constraints' by Erin Catto presented at GDC 2007.
212
/// On slide 78 it is suggested to split up the Baumgarte stabilization for positional drift so that it does not
213
/// actually add to the momentum. We combine an Euler velocity integrate + a position integrate and then discard the velocity
214
/// change.
215
///
216
/// Constraint force:
217
///
218
/// lambda = -K^-1 b
219
///
220
/// Baumgarte stabilization:
221
///
222
/// b = beta / dt C
223
///
224
/// beta = baumgarte stabilization factor.
225
/// dt = delta time.
226
bool SolvePositionConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd);
227
228
/// Recycle the constraint buffer. Should be called between collision simulation steps.
229
void RecycleConstraintBuffer();
230
231
/// Terminate the constraint buffer. Should be called after simulation ends.
232
void FinishConstraintBuffer();
233
234
/// Called by continuous collision detection to notify the contact listener that a contact was added
235
/// @param ioContactAllocator The allocator that reserves memory for the contacts
236
/// @param inBody1 The first body that is colliding
237
/// @param inBody2 The second body that is colliding
238
/// @param inManifold The manifold that describes the collision
239
/// @param outSettings The calculated contact settings (may be overridden by the contact listener)
240
void OnCCDContactAdded(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings);
241
242
#ifdef JPH_DEBUG_RENDERER
243
// Drawing properties
244
static bool sDrawContactPoint;
245
static bool sDrawSupportingFaces;
246
static bool sDrawContactPointReduction;
247
static bool sDrawContactManifolds;
248
#endif // JPH_DEBUG_RENDERER
249
250
/// Saving state for replay
251
void SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const;
252
253
/// Restoring state for replay. Returns false when failed.
254
bool RestoreState(StateRecorder &inStream, const StateRecorderFilter *inFilter);
255
256
private:
257
/// Local space contact point, used for caching impulses
258
class CachedContactPoint
259
{
260
public:
261
/// Saving / restoring state for replay
262
void SaveState(StateRecorder &inStream) const;
263
void RestoreState(StateRecorder &inStream);
264
265
/// Local space positions on body 1 and 2.
266
/// Note: these values are read through sLoadFloat3Unsafe.
267
Float3 mPosition1;
268
Float3 mPosition2;
269
270
/// Total applied impulse during the last update that it was used
271
float mNonPenetrationLambda;
272
Vector<2> mFrictionLambda;
273
};
274
275
static_assert(sizeof(CachedContactPoint) == 36, "Unexpected size");
276
static_assert(alignof(CachedContactPoint) == 4, "Assuming 4 byte aligned");
277
278
/// A single cached manifold
279
class CachedManifold
280
{
281
public:
282
/// Calculate size in bytes needed beyond the size of the class to store inNumContactPoints
283
static int sGetRequiredExtraSize(int inNumContactPoints) { return max(0, inNumContactPoints - 1) * sizeof(CachedContactPoint); }
284
285
/// Calculate total class size needed for storing inNumContactPoints
286
static int sGetRequiredTotalSize(int inNumContactPoints) { return sizeof(CachedManifold) + sGetRequiredExtraSize(inNumContactPoints); }
287
288
/// Saving / restoring state for replay
289
void SaveState(StateRecorder &inStream) const;
290
void RestoreState(StateRecorder &inStream);
291
292
/// Handle to next cached contact points in ManifoldCache::mCachedManifolds for the same body pair
293
uint32 mNextWithSameBodyPair;
294
295
/// Contact normal in the space of 2.
296
/// Note: this value is read through sLoadFloat3Unsafe.
297
Float3 mContactNormal;
298
299
/// Flags for this cached manifold
300
enum class EFlags : uint16
301
{
302
ContactPersisted = 1, ///< If this cache entry was reused in the next simulation update
303
CCDContact = 2 ///< This is a cached manifold reported by continuous collision detection and was only used to create a contact callback
304
};
305
306
/// @see EFlags
307
mutable atomic<uint16> mFlags { 0 };
308
309
/// Number of contact points in the array below
310
uint16 mNumContactPoints;
311
312
/// Contact points that this manifold consists of
313
CachedContactPoint mContactPoints[1];
314
};
315
316
static_assert(sizeof(CachedManifold) == 56, "This structure is expect to not contain any waste due to alignment");
317
static_assert(alignof(CachedManifold) == 4, "Assuming 4 byte aligned");
318
319
/// Define a map that maps SubShapeIDPair -> manifold
320
using ManifoldMap = LockFreeHashMap<SubShapeIDPair, CachedManifold>;
321
using MKeyValue = ManifoldMap::KeyValue;
322
using MKVAndCreated = std::pair<MKeyValue *, bool>;
323
324
/// Start of list of contact points for a particular pair of bodies
325
class CachedBodyPair
326
{
327
public:
328
/// Saving / restoring state for replay
329
void SaveState(StateRecorder &inStream) const;
330
void RestoreState(StateRecorder &inStream);
331
332
/// Local space position difference from Body A to Body B.
333
/// Note: this value is read through sLoadFloat3Unsafe
334
Float3 mDeltaPosition;
335
336
/// Local space rotation difference from Body A to Body B, fourth component of quaternion is not stored but is guaranteed >= 0.
337
/// Note: this value is read through sLoadFloat3Unsafe
338
Float3 mDeltaRotation;
339
340
/// Handle to first manifold in ManifoldCache::mCachedManifolds
341
uint32 mFirstCachedManifold;
342
};
343
344
static_assert(sizeof(CachedBodyPair) == 28, "Unexpected size");
345
static_assert(alignof(CachedBodyPair) == 4, "Assuming 4 byte aligned");
346
347
/// Define a map that maps BodyPair -> CachedBodyPair
348
using BodyPairMap = LockFreeHashMap<BodyPair, CachedBodyPair>;
349
using BPKeyValue = BodyPairMap::KeyValue;
350
351
/// Holds all caches that are needed to quickly find cached body pairs / manifolds
352
class ManifoldCache
353
{
354
public:
355
/// Initialize the cache
356
void Init(uint inMaxBodyPairs, uint inMaxContactConstraints, uint inCachedManifoldsSize);
357
358
/// Reset all entries from the cache
359
void Clear();
360
361
/// Prepare cache before creating new contacts.
362
/// inExpectedNumBodyPairs / inExpectedNumManifolds are the amount of body pairs / manifolds found in the previous step and is used to determine the amount of buckets the contact cache hash map will use.
363
void Prepare(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
364
365
/// Get a new allocator context for storing contacts. Note that you should call this once and then add multiple contacts using the context.
366
ContactAllocator GetContactAllocator() { return ContactAllocator(mAllocator, cAllocatorBlockSize); }
367
368
/// Find / create cached entry for SubShapeIDPair -> CachedManifold
369
const MKeyValue * Find(const SubShapeIDPair &inKey, uint64 inKeyHash) const;
370
MKeyValue * Create(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints);
371
MKVAndCreated FindOrCreate(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints);
372
uint32 ToHandle(const MKeyValue *inKeyValue) const;
373
const MKeyValue * FromHandle(uint32 inHandle) const;
374
375
/// Find / create entry for BodyPair -> CachedBodyPair
376
const BPKeyValue * Find(const BodyPair &inKey, uint64 inKeyHash) const;
377
BPKeyValue * Create(ContactAllocator &ioContactAllocator, const BodyPair &inKey, uint64 inKeyHash);
378
void GetAllBodyPairsSorted(Array<const BPKeyValue *> &outAll) const;
379
void GetAllManifoldsSorted(const CachedBodyPair &inBodyPair, Array<const MKeyValue *> &outAll) const;
380
void GetAllCCDManifoldsSorted(Array<const MKeyValue *> &outAll) const;
381
void ContactPointRemovedCallbacks(ContactListener *inListener);
382
383
#ifdef JPH_ENABLE_ASSERTS
384
/// Get the amount of manifolds in the cache
385
uint GetNumManifolds() const { return mCachedManifolds.GetNumKeyValues(); }
386
387
/// Get the amount of body pairs in the cache
388
uint GetNumBodyPairs() const { return mCachedBodyPairs.GetNumKeyValues(); }
389
390
/// Before a cache is finalized you can only do Create(), after only Find() or Clear()
391
void Finalize();
392
#endif
393
394
/// Saving / restoring state for replay
395
void SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const;
396
bool RestoreState(const ManifoldCache &inReadCache, StateRecorder &inStream, const StateRecorderFilter *inFilter);
397
398
private:
399
/// Block size used when allocating new blocks in the contact cache
400
static constexpr uint32 cAllocatorBlockSize = 4096;
401
402
/// Allocator used by both mCachedManifolds and mCachedBodyPairs, this makes it more likely that a body pair and its manifolds are close in memory
403
LFHMAllocator mAllocator;
404
405
/// Simple hash map for SubShapeIDPair -> CachedManifold
406
ManifoldMap mCachedManifolds { mAllocator };
407
408
/// Simple hash map for BodyPair -> CachedBodyPair
409
BodyPairMap mCachedBodyPairs { mAllocator };
410
411
#ifdef JPH_ENABLE_ASSERTS
412
bool mIsFinalized = false; ///< Marks if this buffer is complete
413
#endif
414
};
415
416
ManifoldCache mCache[2]; ///< We have one cache to read from and one to write to
417
int mCacheWriteIdx = 0; ///< Which cache we're currently writing to
418
419
/// World space contact point, used for solving penetrations
420
class WorldContactPoint
421
{
422
public:
423
/// Calculate constraint properties below
424
void CalculateNonPenetrationConstraintProperties(const Body &inBody1, float inInvMass1, float inInvInertiaScale1, const Body &inBody2, float inInvMass2, float inInvInertiaScale2, RVec3Arg inWorldSpacePosition1, RVec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal);
425
426
template <EMotionType Type1, EMotionType Type2>
427
JPH_INLINE void TemplatedCalculateFrictionAndNonPenetrationConstraintProperties(float inDeltaTime, float inGravityDeltaTimeDotNormal, const Body &inBody1, const Body &inBody2, float inInvM1, float inInvM2, Mat44Arg inInvI1, Mat44Arg inInvI2, RVec3Arg inWorldSpacePosition1, RVec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal, Vec3Arg inWorldSpaceTangent1, Vec3Arg inWorldSpaceTangent2, const ContactSettings &inSettings, float inMinVelocityForRestitution);
428
429
/// The constraint parts
430
AxisConstraintPart mNonPenetrationConstraint;
431
AxisConstraintPart mFrictionConstraint1;
432
AxisConstraintPart mFrictionConstraint2;
433
434
/// Contact cache
435
CachedContactPoint * mContactPoint;
436
};
437
438
using WorldContactPoints = StaticArray<WorldContactPoint, MaxContactPoints>;
439
440
/// Contact constraint class, used for solving penetrations
441
class ContactConstraint
442
{
443
public:
444
#ifdef JPH_DEBUG_RENDERER
445
/// Draw the state of the contact constraint
446
void Draw(DebugRenderer *inRenderer, ColorArg inManifoldColor) const;
447
#endif // JPH_DEBUG_RENDERER
448
449
/// Convert the world space normal to a Vec3
450
JPH_INLINE Vec3 GetWorldSpaceNormal() const
451
{
452
return Vec3::sLoadFloat3Unsafe(mWorldSpaceNormal);
453
}
454
455
/// Get the tangents for this contact constraint
456
JPH_INLINE void GetTangents(Vec3 &outTangent1, Vec3 &outTangent2) const
457
{
458
Vec3 ws_normal = GetWorldSpaceNormal();
459
outTangent1 = ws_normal.GetNormalizedPerpendicular();
460
outTangent2 = ws_normal.Cross(outTangent1);
461
}
462
463
Body * mBody1;
464
Body * mBody2;
465
uint64 mSortKey;
466
Float3 mWorldSpaceNormal;
467
float mCombinedFriction;
468
float mInvMass1;
469
float mInvInertiaScale1;
470
float mInvMass2;
471
float mInvInertiaScale2;
472
WorldContactPoints mContactPoints;
473
};
474
475
public:
476
/// The maximum value that can be passed to Init for inMaxContactConstraints. Note you should really use a lower value, using this value will cost a lot of memory!
477
static constexpr uint cMaxContactConstraintsLimit = ~uint(0) / sizeof(ContactConstraint);
478
479
/// The maximum value that can be passed to Init for inMaxBodyPairs. Note you should really use a lower value, using this value will cost a lot of memory!
480
static constexpr uint cMaxBodyPairsLimit = ~uint(0) / sizeof(BodyPairMap::KeyValue);
481
482
private:
483
/// Internal helper function to calculate the friction and non-penetration constraint properties. Templated to the motion type to reduce the amount of branches and calculations.
484
template <EMotionType Type1, EMotionType Type2>
485
JPH_INLINE void TemplatedCalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, const ContactSettings &inSettings, float inDeltaTime, Vec3Arg inGravityDeltaTime, RMat44Arg inTransformBody1, RMat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2);
486
487
/// Internal helper function to calculate the friction and non-penetration constraint properties.
488
inline void CalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, const ContactSettings &inSettings, float inDeltaTime, Vec3Arg inGravityDeltaTime, RMat44Arg inTransformBody1, RMat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2);
489
490
/// Internal helper function to add a contact constraint. Templated to the motion type to reduce the amount of branches and calculations.
491
template <EMotionType Type1, EMotionType Type2>
492
bool TemplatedAddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold);
493
494
/// Internal helper function to warm start contact constraint. Templated to the motion type to reduce the amount of branches and calculations.
495
template <EMotionType Type1, EMotionType Type2>
496
JPH_INLINE static void sWarmStartConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2, float inWarmStartImpulseRatio);
497
498
/// Internal helper function to solve a single contact constraint. Templated to the motion type to reduce the amount of branches and calculations.
499
template <EMotionType Type1, EMotionType Type2>
500
JPH_INLINE static bool sSolveVelocityConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2);
501
502
/// The main physics settings instance
503
const PhysicsSettings & mPhysicsSettings;
504
505
/// Listener that is notified whenever a contact point between two bodies is added/updated/removed
506
ContactListener * mContactListener = nullptr;
507
508
/// Functions that are used to combine friction and restitution of 2 bodies
509
CombineFunction mCombineFriction = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return sqrt(inBody1.GetFriction() * inBody2.GetFriction()); };
510
CombineFunction mCombineRestitution = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return max(inBody1.GetRestitution(), inBody2.GetRestitution()); };
511
512
/// The constraints that were added this frame
513
ContactConstraint * mConstraints = nullptr;
514
uint32 mMaxConstraints = 0;
515
atomic<uint32> mNumConstraints { 0 };
516
517
/// Context used for this physics update
518
PhysicsUpdateContext * mUpdateContext;
519
};
520
521
JPH_NAMESPACE_END
522
523