Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
ContactConstraintManager.h
Go to the documentation of this file.
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
17
19#include <atomic>
21
23
24struct PhysicsSettings;
26
28{
29public:
31
33 explicit ContactConstraintManager(const PhysicsSettings &inPhysicsSettings);
35
39 void Init(uint inMaxBodyPairs, uint inMaxContactConstraints);
40
42 void SetContactListener(ContactListener *inListener) { mContactListener = inListener; }
43 ContactListener * GetContactListener() const { return mContactListener; }
44
48 using CombineFunction = float (*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2);
49
52 void SetCombineFriction(CombineFunction inCombineFriction) { mCombineFriction = inCombineFriction; }
53
56 void SetCombineRestitution(CombineFunction inCombineRestitution) { mCombineRestitution = inCombineRestitution; }
57
59 uint32 GetMaxConstraints() const { return mMaxConstraints; }
60
62 inline ValidateResult ValidateContactPoint(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) const
63 {
64 if (mContactListener == nullptr)
65 return ValidateResult::AcceptAllContactsForThisBodyPair;
66
67 return mContactListener->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
68 }
69
72
74 static const int MaxContactPoints = 4;
75
78 {
79 public:
81
84 EPhysicsUpdateError mErrors = EPhysicsUpdateError::None;
85 };
86
88 ContactAllocator GetContactAllocator() { return mCache[mCacheWriteIdx].GetContactAllocator(); }
89
93 void GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outConstraintCreated);
94
96 using BodyPairHandle = void *;
97
100 BodyPairHandle AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2);
101
143 bool AddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPair, Body &inBody1, Body &inBody2, const ContactManifold &inManifold);
144
149 void FinalizeContactCacheAndCallContactPointRemovedCallbacks(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
150
153 bool WereBodiesInContact(const BodyID &inBody1ID, const BodyID &inBody2ID) const;
154
156 uint32 GetNumConstraints() const { return min<uint32>(mNumConstraints, mMaxConstraints); }
157
159 void SortContacts(uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd) const;
160
162 inline void GetAffectedBodies(uint32 inConstraintIdx, const Body *&outBody1, const Body *&outBody2) const
163 {
164 const ContactConstraint &constraint = mConstraints[inConstraintIdx];
165 outBody1 = constraint.mBody1;
166 outBody2 = constraint.mBody2;
167 }
168
170 void SetupVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime);
171
173 void WarmStartVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio);
174
205 bool SolveVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd);
206
208 void StoreAppliedImpulses(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const;
209
226 bool SolvePositionConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd);
227
230
233
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;
248#endif // JPH_DEBUG_RENDERER
249
251 void SaveState(StateRecorder &inStream) const;
252
254 bool RestoreState(StateRecorder &inStream);
255
256private:
258 class CachedContactPoint
259 {
260 public:
262 void SaveState(StateRecorder &inStream) const;
263 void RestoreState(StateRecorder &inStream);
264
267 Float3 mPosition1;
268 Float3 mPosition2;
269
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
279 class CachedManifold
280 {
281 public:
283 static int sGetRequiredExtraSize(int inNumContactPoints) { return max(0, inNumContactPoints - 1) * sizeof(CachedContactPoint); }
284
286 static int sGetRequiredTotalSize(int inNumContactPoints) { return sizeof(CachedManifold) + sGetRequiredExtraSize(inNumContactPoints); }
287
289 void SaveState(StateRecorder &inStream) const;
290 void RestoreState(StateRecorder &inStream);
291
293 uint32 mNextWithSameBodyPair;
294
297 Float3 mContactNormal;
298
300 enum class EFlags : uint16
301 {
302 ContactPersisted = 1,
303 CCDContact = 2
304 };
305
307 mutable atomic<uint16> mFlags { 0 };
308
310 uint16 mNumContactPoints;
311
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
321 using MKeyValue = ManifoldMap::KeyValue;
322 using MKVAndCreated = pair<MKeyValue *, bool>;
323
325 class CachedBodyPair
326 {
327 public:
329 void SaveState(StateRecorder &inStream) const;
330 void RestoreState(StateRecorder &inStream);
331
334 Float3 mDeltaPosition;
335
338 Float3 mDeltaRotation;
339
341 uint32 mFirstCachedManifold;
342 };
343
344 static_assert(sizeof(CachedBodyPair) == 28, "Unexpected size");
345 static_assert(alignof(CachedBodyPair) == 4, "Assuming 4 byte aligned");
346
349 using BPKeyValue = BodyPairMap::KeyValue;
350
352 class ManifoldCache
353 {
354 public:
356 void Init(uint inMaxBodyPairs, uint inMaxContactConstraints, uint inCachedManifoldsSize);
357
359 void Clear();
360
363 void Prepare(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
364
366 ContactAllocator GetContactAllocator() { return ContactAllocator(mAllocator, cAllocatorBlockSize); }
367
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
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
385 uint GetNumManifolds() const { return mCachedManifolds.GetNumKeyValues(); }
386
388 uint GetNumBodyPairs() const { return mCachedBodyPairs.GetNumKeyValues(); }
389
391 void Finalize();
392#endif
393
395 void SaveState(StateRecorder &inStream) const;
396 bool RestoreState(const ManifoldCache &inReadCache, StateRecorder &inStream);
397
398 private:
400 static constexpr uint32 cAllocatorBlockSize = 4096;
401
403 LFHMAllocator mAllocator;
404
406 ManifoldMap mCachedManifolds { mAllocator };
407
409 BodyPairMap mCachedBodyPairs { mAllocator };
410
411#ifdef JPH_ENABLE_ASSERTS
412 bool mIsFinalized = false;
413#endif
414 };
415
416 ManifoldCache mCache[2];
417 int mCacheWriteIdx = 0;
418
420 class WorldContactPoint
421 {
422 public:
424 void CalculateNonPenetrationConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, RVec3Arg inWorldSpacePosition1, RVec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal);
425 template <EMotionType Type1, EMotionType Type2>
426 JPH_INLINE void CalculateFrictionAndNonPenetrationConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, Mat44Arg inInvI1, Mat44Arg inInvI2, RVec3Arg inWorldSpacePosition1, RVec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal, Vec3Arg inWorldSpaceTangent1, Vec3Arg inWorldSpaceTangent2, float inCombinedRestitution, float inCombinedFriction, float inMinVelocityForRestitution);
427
429 AxisConstraintPart mNonPenetrationConstraint;
430 AxisConstraintPart mFrictionConstraint1;
431 AxisConstraintPart mFrictionConstraint2;
432
434 CachedContactPoint * mContactPoint;
435 };
436
437 using WorldContactPoints = StaticArray<WorldContactPoint, MaxContactPoints>;
438
440 class ContactConstraint
441 {
442 public:
443 #ifdef JPH_DEBUG_RENDERER
445 void Draw(DebugRenderer *inRenderer, ColorArg inManifoldColor) const;
446 #endif // JPH_DEBUG_RENDERER
447
449 JPH_INLINE void GetTangents(Vec3 &outTangent1, Vec3 &outTangent2) const
450 {
451 outTangent1 = mWorldSpaceNormal.GetNormalizedPerpendicular();
452 outTangent2 = mWorldSpaceNormal.Cross(outTangent1);
453 }
454
455 Vec3 mWorldSpaceNormal;
456 Body * mBody1;
457 Body * mBody2;
458 uint64 mSortKey;
459 float mCombinedFriction;
460 float mCombinedRestitution;
461 WorldContactPoints mContactPoints;
462 };
463
465 template <EMotionType Type1, EMotionType Type2>
466 JPH_INLINE void TemplatedCalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, float inDeltaTime, RMat44Arg inTransformBody1, RMat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2, Mat44Arg inInvI1, Mat44Arg inInvI2);
467
469 inline void CalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, float inDeltaTime, RMat44Arg inTransformBody1, RMat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2);
470
472 template <EMotionType Type1, EMotionType Type2>
473 bool TemplatedAddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold, Mat44Arg inInvI1, Mat44Arg inInvI2);
474
476 template <EMotionType Type1, EMotionType Type2>
477 JPH_INLINE static void sWarmStartConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2, float inWarmStartImpulseRatio);
478
480 template <EMotionType Type1, EMotionType Type2>
481 JPH_INLINE static bool sSolveVelocityConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2);
482
484 const PhysicsSettings & mPhysicsSettings;
485
487 ContactListener * mContactListener = nullptr;
488
490 CombineFunction mCombineFriction = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return sqrt(inBody1.GetFriction() * inBody2.GetFriction()); };
491 CombineFunction mCombineRestitution = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return max(inBody1.GetRestitution(), inBody2.GetRestitution()); };
492
494 ContactConstraint * mConstraints = nullptr;
495 uint32 mMaxConstraints = 0;
496 atomic<uint32> mNumConstraints { 0 };
497
499 PhysicsUpdateContext * mUpdateContext;
500};
501
ValidateResult
Definition: ContactListener.h:51
#define JPH_SUPPRESS_WARNINGS_STD_BEGIN
Definition: Core.h:245
uint32_t uint32
Definition: Core.h:312
#define JPH_SUPPRESS_WARNINGS_STD_END
Definition: Core.h:255
unsigned int uint
Definition: Core.h:309
#define JPH_NAMESPACE_END
Definition: Core.h:240
uint16_t uint16
Definition: Core.h:311
uint64_t uint64
Definition: Core.h:313
#define JPH_NAMESPACE_BEGIN
Definition: Core.h:234
EPhysicsUpdateError
Enum used by PhysicsSystem to report error conditions during the PhysicsSystem::Update call....
Definition: EPhysicsUpdateError.h:11
#define JPH_OVERRIDE_NEW_DELETE
Macro to override the new and delete functions.
Definition: Memory.h:29
std::vector< T, STLAllocator< T > > Array
Definition: STLAllocator.h:81
Definition: AxisConstraintPart.h:42
Definition: Body.h:33
float GetRestitution() const
Restitution (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision respon...
Definition: Body.h:105
float GetFriction() const
Friction (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals f...
Definition: Body.h:101
ID of a body. This is a way of reasoning about bodies in a multithreaded simulation while avoiding ra...
Definition: BodyID.h:13
Class that contains all information of two colliding shapes.
Definition: CollideShape.h:19
Class that holds an RGBA color with 8-bits per component.
Definition: Color.h:16
Contacts are allocated in a lock free hash map.
Definition: ContactConstraintManager.h:78
EPhysicsUpdateError mErrors
Errors reported on this allocator.
Definition: ContactConstraintManager.h:84
uint mNumBodyPairs
Total number of body pairs added using this allocator.
Definition: ContactConstraintManager.h:82
uint mNumManifolds
Total number of manifolds added using this allocator.
Definition: ContactConstraintManager.h:83
Definition: ContactConstraintManager.h:28
void FinishConstraintBuffer()
Terminate the constraint buffer. Should be called after simulation ends.
Definition: ContactConstraintManager.cpp:1598
BodyPairHandle AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2)
Definition: ContactConstraintManager.cpp:880
void WarmStartVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio)
Apply last frame's impulses as an initial guess for this frame's impulses.
Definition: ContactConstraintManager.cpp:1391
static const int MaxContactPoints
Max 4 contact points are needed for a stable manifold.
Definition: ContactConstraintManager.h:74
static bool sDrawContactPoint
Definition: ContactConstraintManager.h:244
bool RestoreState(StateRecorder &inStream)
Restoring state for replay. Returns false when failed.
Definition: ContactConstraintManager.cpp:1614
void FinalizeContactCacheAndCallContactPointRemovedCallbacks(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
Definition: ContactConstraintManager.cpp:1305
void SetupVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime)
AddContactConstraint will also setup the velocity constraints for the first sub step....
Definition: ContactConstraintManager.cpp:1350
void RecycleConstraintBuffer()
Recycle the constraint buffer. Should be called between collision simulation steps.
Definition: ContactConstraintManager.cpp:1592
bool SolvePositionConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
Definition: ContactConstraintManager.cpp:1545
bool WereBodiesInContact(const BodyID &inBody1ID, const BodyID &inBody2ID) const
Definition: ContactConstraintManager.cpp:1336
ValidateResult ValidateContactPoint(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) const
Check with the listener if inBody1 and inBody2 could collide, returns false if not.
Definition: ContactConstraintManager.h:62
uint32 GetMaxConstraints() const
Get the max number of contact constraints that are allowed.
Definition: ContactConstraintManager.h:59
static bool sDrawContactPointReduction
Definition: ContactConstraintManager.h:246
void PrepareConstraintBuffer(PhysicsUpdateContext *inContext)
Sets up the constraint buffer. Should be called before starting collision detection.
Definition: ContactConstraintManager.cpp:613
void * BodyPairHandle
Handle used to keep track of the current body pair.
Definition: ContactConstraintManager.h:96
bool SolveVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
Definition: ContactConstraintManager.cpp:1467
ContactListener * GetContactListener() const
Definition: ContactConstraintManager.h:43
static bool sDrawSupportingFaces
Definition: ContactConstraintManager.h:245
void GetAffectedBodies(uint32 inConstraintIdx, const Body *&outBody1, const Body *&outBody2) const
Get the affected bodies for a given constraint.
Definition: ContactConstraintManager.h:162
void Init(uint inMaxBodyPairs, uint inMaxContactConstraints)
Definition: ContactConstraintManager.cpp:601
void OnCCDContactAdded(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings)
Definition: ContactConstraintManager.cpp:1204
~ContactConstraintManager()
Definition: ContactConstraintManager.cpp:596
uint32 GetNumConstraints() const
Get the number of contact constraints that were found.
Definition: ContactConstraintManager.h:156
void SetCombineFriction(CombineFunction inCombineFriction)
Definition: ContactConstraintManager.h:52
void GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outConstraintCreated)
Definition: ContactConstraintManager.cpp:685
void StoreAppliedImpulses(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const
Save back the lambdas to the contact cache for the next warm start.
Definition: ContactConstraintManager.cpp:1529
void SetContactListener(ContactListener *inListener)
Listener that is notified whenever a contact point between two bodies is added/updated/removed.
Definition: ContactConstraintManager.h:42
float(*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2) CombineFunction
Definition: ContactConstraintManager.h:48
bool AddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPair, Body &inBody1, Body &inBody2, const ContactManifold &inManifold)
Definition: ContactConstraintManager.cpp:1109
void SetCombineRestitution(CombineFunction inCombineRestitution)
Definition: ContactConstraintManager.h:56
ContactAllocator GetContactAllocator()
Get a new allocator context for storing contacts. Note that you should call this once and then add mu...
Definition: ContactConstraintManager.h:88
void SaveState(StateRecorder &inStream) const
Saving state for replay.
Definition: ContactConstraintManager.cpp:1609
void SortContacts(uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd) const
Sort contact constraints deterministically.
Definition: ContactConstraintManager.cpp:1280
static bool sDrawContactManifolds
Definition: ContactConstraintManager.h:247
Definition: ContactListener.h:62
virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult)
Definition: ContactListener.h:76
Manifold class, describes the contact surface between two bodies.
Definition: ContactListener.h:20
Definition: ContactListener.h:41
Simple triangle renderer for debugging purposes.
Definition: DebugRenderer.h:25
Class that holds 3 floats. Used as a storage class. Convert to Vec3 for calculations.
Definition: Float3.h:13
Definition: LockFreeHashMap.h:49
LFHMAllocatorContext(LFHMAllocator &inAllocator, uint32 inBlockSize)
Construct a new allocator context.
Definition: LockFreeHashMap.inl:80
Allocator for a lock free hash map.
Definition: LockFreeHashMap.h:14
Definition: LockFreeHashMap.h:72
Holds a 4x4 matrix of floats, but supports also operations on the 3x3 upper left part of the matrix.
Definition: Mat44.h:13
The Body class only keeps track of state for static bodies, the MotionProperties class keeps the addi...
Definition: MotionProperties.h:20
Class that makes another class non-copyable. Usage: Inherit from NonCopyable.
Definition: NonCopyable.h:11
Information used during the Update call.
Definition: PhysicsUpdateContext.h:23
Definition: StateRecorder.h:15
Simple variable length array backed by a fixed size buffer.
Definition: StaticArray.h:12
A sub shape id contains a path to an element (usually a triangle or other primitive type) of a compou...
Definition: SubShapeID.h:23
A pair of bodies and their sub shape ID's. Can be used as a key in a map to find a contact point.
Definition: SubShapeIDPair.h:15
Definition: Vec3.h:16
JPH_INLINE Vec3 Cross(Vec3Arg inV2) const
Cross product.
Definition: Vec3.inl:582
JPH_INLINE Vec3 GetNormalizedPerpendicular() const
Get normalized vector that is perpendicular to this vector.
Definition: Vec3.inl:812
Templatized vector class.
Definition: Vector.h:12
Structure that holds a body pair.
Definition: BodyPair.h:14
Definition: PhysicsSettings.h:28