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
18#include <Jolt/Math/Vector.h>
19
21#include <atomic>
23
25
26struct PhysicsSettings;
27class PhysicsUpdateContext;
28
33{
34public:
36
38 explicit ContactConstraintManager(const PhysicsSettings &inPhysicsSettings);
40
44 void Init(uint inMaxBodyPairs, uint inMaxContactConstraints);
45
47 void SetContactListener(ContactListener *inListener) { mContactListener = inListener; }
48 ContactListener * GetContactListener() const { return mContactListener; }
49
53 using CombineFunction = float (*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2);
54
57 void SetCombineFriction(CombineFunction inCombineFriction) { mCombineFriction = inCombineFriction; }
58 CombineFunction GetCombineFriction() const { return mCombineFriction; }
59
62 void SetCombineRestitution(CombineFunction inCombineRestitution) { mCombineRestitution = inCombineRestitution; }
63 CombineFunction GetCombineRestitution() const { return mCombineRestitution; }
64
66 uint32 GetMaxConstraints() const { return mMaxConstraints; }
67
69 inline ValidateResult ValidateContactPoint(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) const
70 {
71 if (mContactListener == nullptr)
73
74 return mContactListener->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
75 }
76
78 void PrepareConstraintBuffer(PhysicsUpdateContext *inContext);
79
81 static const int MaxContactPoints = 4;
82
85 {
86 public:
88
89 uint mNumBodyPairs = 0;
90 uint mNumManifolds = 0;
92 };
93
95 ContactAllocator GetContactAllocator() { return mCache[mCacheWriteIdx].GetContactAllocator(); }
96
99 void GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled);
100
102 using BodyPairHandle = void *;
103
106 BodyPairHandle AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2);
107
149 void AddContactConstraint(ContactAllocator &ioContactAllocator, bool &ioActivateAndLinkBodies, BodyPairHandle inBodyPair, Body &inBody1, Body &inBody2, const ContactManifold &inManifold);
150
155 void FinalizeContactCacheAndCallContactPointRemovedCallbacks(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
156
159 bool WereBodiesInContact(const BodyID &inBody1ID, const BodyID &inBody2ID) const;
160
162 uint32 GetNumConstraints() const { return min<uint32>(uint32(mNumConstraintsAndNextConstraintOffset.load(memory_order_relaxed)), mMaxConstraints); }
163
165 void ConstraintIdxToConstraintOffset(uint32 *ioConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const;
166
168 void SortContacts(uint32 *ioConstraintOffsetBegin, uint32 *inConstraintOffsetEnd) const;
169
171 inline void GetAffectedBodies(uint32 inConstraintOffset, const Body *&outBody1, const Body *&outBody2) const
172 {
173 const ContactConstraintBase &constraint = *reinterpret_cast<const ContactConstraintBase *>(mConstraints + inConstraintOffset);
174 outBody1 = constraint.mBody1;
175 outBody2 = constraint.mBody2;
176 }
177
179 template <class MotionPropertiesCallback>
180 void WarmStartVelocityConstraints(const uint32 *inConstraintOffsetBegin, const uint32 *inConstraintOffsetEnd, float inWarmStartImpulseRatio, MotionPropertiesCallback &ioCallback);
181
212 bool SolveVelocityConstraints(const uint32 *inConstraintOffsetBegin, const uint32 *inConstraintOffsetEnd);
213
215 void StoreAppliedImpulses(const uint32 *inConstraintOffsetBegin, const uint32 *inConstraintOffsetEnd) const;
216
233 bool SolvePositionConstraints(const uint32 *inConstraintOffsetBegin, const uint32 *inConstraintOffsetEnd);
234
236 void RecycleConstraintBuffer();
237
239 void FinishConstraintBuffer();
240
247 void OnCCDContactAdded(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings);
248
249#ifdef JPH_DEBUG_RENDERER
250 // Drawing properties
251 static bool sDrawContactPoint;
255#endif // JPH_DEBUG_RENDERER
256
258 void SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const;
259
261 bool RestoreState(StateRecorder &inStream, const StateRecorderFilter *inFilter);
262
263private:
265 class CachedContactPoint
266 {
267 public:
269 void SaveState(StateRecorder &inStream) const;
270 void RestoreState(StateRecorder &inStream);
271
274 Float3 mPosition1;
275 Float3 mPosition2;
276
278 float mNonPenetrationLambda;
279 };
280
281 static_assert(sizeof(CachedContactPoint) == 28, "Unexpected size");
282 static_assert(alignof(CachedContactPoint) == 4, "Assuming 4 byte aligned");
283
285 class CachedManifold
286 {
287 public:
289 static constexpr int sGetRequiredExtraSize(int inNumContactPoints) { return max(0, inNumContactPoints - 1) * sizeof(CachedContactPoint); }
290
292 static constexpr int sGetRequiredTotalSize(int inNumContactPoints) { return sizeof(CachedManifold) + sGetRequiredExtraSize(inNumContactPoints); }
293
295 void SaveState(StateRecorder &inStream) const;
296 void RestoreState(StateRecorder &inStream);
297
299 uint32 mNextWithSameBodyPair;
300
303 Float3 mContactNormal;
304
306 Vector<2> mFrictionLambda;
307 float mAngularFrictionLambda;
308
310 enum class EFlags : uint16
311 {
312 ContactPersisted = 1,
313 CCDContact = 2
314 };
315
317 mutable atomic<uint16> mFlags { 0 };
318
320 uint16 mNumContactPoints;
321
323 CachedContactPoint mContactPoints[1];
324 };
325
326 static_assert(sizeof(CachedManifold) == 60, "This structure is expect to not contain any waste due to alignment");
327 static_assert(alignof(CachedManifold) == 4, "Assuming 4 byte aligned");
328
331 using MKeyValue = ManifoldMap::KeyValue;
332 using MKVAndCreated = std::pair<MKeyValue *, bool>;
333
335 class CachedBodyPair
336 {
337 public:
339 void SaveState(StateRecorder &inStream) const;
340 void RestoreState(StateRecorder &inStream);
341
344 Float3 mDeltaPosition;
345
348 Float3 mDeltaRotation;
349
351 uint32 mFirstCachedManifold;
352 };
353
354 static_assert(sizeof(CachedBodyPair) == 28, "Unexpected size");
355 static_assert(alignof(CachedBodyPair) == 4, "Assuming 4 byte aligned");
356
359 using BPKeyValue = BodyPairMap::KeyValue;
360
362 class ManifoldCache
363 {
364 public:
366 void Init(uint inMaxBodyPairs, uint inMaxContactConstraints, uint inCachedManifoldsSize);
367
369 void Clear();
370
373 void Prepare(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds);
374
376 ContactAllocator GetContactAllocator() { return ContactAllocator(mAllocator, cAllocatorBlockSize); }
377
379 const MKeyValue * Find(const SubShapeIDPair &inKey, uint64 inKeyHash) const;
380 MKeyValue * Create(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints);
381 MKVAndCreated FindOrCreate(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints);
382 uint32 ToHandle(const MKeyValue *inKeyValue) const;
383 const MKeyValue * FromHandle(uint32 inHandle) const;
384 MKeyValue * FromHandle(uint32 inHandle);
385
387 const BPKeyValue * Find(const BodyPair &inKey, uint64 inKeyHash) const;
388 BPKeyValue * Create(ContactAllocator &ioContactAllocator, const BodyPair &inKey, uint64 inKeyHash);
389 void GetAllBodyPairsSorted(Array<const BPKeyValue *> &outAll) const;
390 void GetAllManifoldsSorted(const CachedBodyPair &inBodyPair, Array<const MKeyValue *> &outAll) const;
391 void GetAllCCDManifoldsSorted(Array<const MKeyValue *> &outAll) const;
392 void ContactPointRemovedCallbacks(ContactListener *inListener);
393
394#ifdef JPH_ENABLE_ASSERTS
396 uint GetNumManifolds() const { return mCachedManifolds.GetNumKeyValues(); }
397
399 uint GetNumBodyPairs() const { return mCachedBodyPairs.GetNumKeyValues(); }
400
402 void Finalize();
403#endif
404
406 void SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const;
407 bool RestoreState(const ManifoldCache &inReadCache, StateRecorder &inStream, const StateRecorderFilter *inFilter);
408
409 private:
411 static constexpr uint32 cAllocatorBlockSize = 4096;
412
414 LFHMAllocator mAllocator;
415
417 ManifoldMap mCachedManifolds { mAllocator };
418
420 BodyPairMap mCachedBodyPairs { mAllocator };
421
422#ifdef JPH_ENABLE_ASSERTS
423 bool mIsFinalized = false;
424#endif
425 };
426
427 ManifoldCache mCache[2];
428 int mCacheWriteIdx = 0;
429 ManifoldCache * mReadCache = nullptr;
430 ManifoldCache * mWriteCache = nullptr;
431
433 template <EMotionType Type1, EMotionType Type2>
434 class WorldContactPoint
435 {
436 public:
437 using ConstraintPart = ContactConstraintPart<Type1, Type2>;
438
440 JPH_INLINE void CalculateNonPenetrationConstraintProperties(float inDeltaTime, Vec3Arg inGravity, const Body &inBody1, const Body &inBody2, float inInvM1, float inInvM2, Mat44Arg inInvI1, Mat44Arg inInvI2, RVec3Arg inWorldSpacePosition1, RVec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal, const ContactSettings &inSettings, float inMinVelocityForRestitution);
441
443 ConstraintPart mNonPenetrationConstraint;
444 // Note that this needs to be followed by data of size float, see comment at ContactConstraintPart
445
447 float mDistanceToFrictionCenter;
448 };
449
450 class ContactConstraintBase
451 {
452 public:
454 JPH_INLINE Vec3 GetWorldSpaceNormal() const
455 {
456 return Vec3::sLoadFloat3Unsafe(mWorldSpaceNormal);
457 }
458
460 JPH_INLINE void GetTangents(Vec3 &outTangent1, Vec3 &outTangent2) const
461 {
462 Vec3 ws_normal = GetWorldSpaceNormal();
463 outTangent1 = ws_normal.GetNormalizedPerpendicular();
464 outTangent2 = ws_normal.Cross(outTangent1);
465 }
466
467 Body * mBody1;
468 Body * mBody2;
469 uint64 mSortKey;
470 Float3 mWorldSpaceNormal;
471 float mCombinedFriction;
472 float mInvMass1;
473 float mInvInertiaScale1;
474 float mInvMass2;
475 float mInvInertiaScale2;
476 uint32 mCachedManifoldHandle;
477 uint32 mNumContactPoints;
478 };
479
481 template <EMotionType Type1, EMotionType Type2>
482 class ContactConstraint : public ContactConstraintBase
483 {
484 public:
486 JPH_INLINE void CalculateFrictionConstraintProperties(const Body &inBody1, const Body &inBody2, float inInvM1, float inInvM2, Mat44Arg inInvI1, Mat44Arg inInvI2, const RVec3 *inWorldSpaceContacts, Vec3Arg inWorldSpaceNormal, Vec3Arg inWorldSpaceTangent1, Vec3Arg inWorldSpaceTangent2, const ContactSettings &inSettings);
487
488 #ifdef JPH_DEBUG_RENDERER
490 void Draw(DebugRenderer *inRenderer, const ManifoldCache &inManifoldCache, ColorArg inManifoldColor) const;
491 #endif // JPH_DEBUG_RENDERER
492
493 ContactConstraintPart<Type1, Type2> mFrictionConstraint1;
494 ContactConstraintPart<Type1, Type2> mFrictionConstraint2;
495 AngularFrictionConstraintPart<Type1, Type2> mAngularFrictionConstraint;
496
497 WorldContactPoint<Type1, Type2> mContactPoints[1];
498 };
499
500public:
502 static constexpr uint32 cMaxConstraintSize = sizeof(ContactConstraint<EMotionType::Dynamic, EMotionType::Dynamic>) + (MaxContactPoints - 1) * sizeof(WorldContactPoint<EMotionType::Dynamic, EMotionType::Dynamic>);
503
505 static constexpr uint cMaxContactConstraintsLimit = ~uint(0) / cMaxConstraintSize;
506
508 static constexpr uint cMaxBodyPairsLimit = ~uint(0) / sizeof(BodyPairMap::KeyValue);
509
510private:
512 template <EMotionType Type1, EMotionType Type2>
513 JPH_INLINE ContactConstraint<Type1, Type2> *CreateConstraint(bool &ioActivateAndLinkBodies, Body &inBody1, Body &inBody2, uint64 inSortKey, uint32 inCachedManifoldHandle, Vec3Arg inWorldSpaceNormal, const ContactSettings &inSettings, uint32 inNumContactPoints);
514
516 template <EMotionType Type1, EMotionType Type2>
517 void TemplatedGetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, const CachedBodyPair &inCachedBodyPair, CachedBodyPair &outCachedBodyPair);
518
520 template <EMotionType Type1, EMotionType Type2>
521 void TemplatedAddContactConstraint(ContactAllocator &ioContactAllocator, bool &ioActivateAndLinkBodies, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold);
522
524 template <EMotionType Type1, EMotionType Type2>
525 static JPH_INLINE void sGetVelocities(const MotionProperties *inMotionProperties1, const MotionProperties *inMotionProperties2, Vec3 &outLinearVelocity1, Vec3 &outAngularVelocity1, Vec3 &outLinearVelocity2, Vec3 &outAngularVelocity2);
526
528 template <EMotionType Type1, EMotionType Type2>
529 static JPH_INLINE void sSetVelocities(MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2, Vec3Arg inLinearVelocity1, Vec3Arg inAngularVelocity1, Vec3Arg inLinearVelocity2, Vec3Arg inAngularVelocity2);
530
532 template <EMotionType Type1, EMotionType Type2>
533 static void sWarmStartConstraint(ContactConstraintBase &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2, float inWarmStartImpulseRatio);
534
536 template <EMotionType Type1, EMotionType Type2>
537 static bool sSolveVelocityConstraint(ContactConstraintBase &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2);
538
540 template <EMotionType Type1, EMotionType Type2>
541 static void sStoreAppliedImpulses(ContactConstraintBase &ioConstraint, ManifoldCache &inManifoldCache);
542
544 template <EMotionType Type1, EMotionType Type2>
545 static bool sSolvePositionConstraint(ContactConstraintBase &ioConstraint, Body &ioBody1, Body &ioBody2, const PhysicsSettings &inSettings, const ManifoldCache &inManifoldCache);
546
548 const PhysicsSettings & mPhysicsSettings;
549
551 ContactListener * mContactListener = nullptr;
552
554 CombineFunction mCombineFriction = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return Sqrt(inBody1.GetFriction() * inBody2.GetFriction()); };
555 CombineFunction mCombineRestitution = [](const Body &inBody1, const SubShapeID &, const Body &inBody2, const SubShapeID &) { return max(inBody1.GetRestitution(), inBody2.GetRestitution()); };
556
558 uint8 * mConstraints = nullptr;
559 uint32 * mConstraintIdxToOffset = nullptr;
560 uint32 mMaxConstraints = 0;
561 atomic<uint64> mNumConstraintsAndNextConstraintOffset { 0 }; // Lower 32 bits: number of constraints, upper 32 bits next constraint offset
562
564 PhysicsUpdateContext * mUpdateContext;
565};
566
ValidateResult
Definition ContactListener.h:57
@ AcceptAllContactsForThisBodyPair
Accept this and any further contact points for this body pair.
std::uint8_t uint8
Definition Core.h:511
#define JPH_EXPORT
Definition Core.h:283
#define JPH_SUPPRESS_WARNINGS_STD_BEGIN
Definition Core.h:439
#define JPH_SUPPRESS_WARNINGS_STD_END
Definition Core.h:452
std::uint64_t uint64
Definition Core.h:515
unsigned int uint
Definition Core.h:510
#define JPH_NAMESPACE_END
Definition Core.h:434
std::uint32_t uint32
Definition Core.h:513
#define JPH_NAMESPACE_BEGIN
Definition Core.h:428
std::uint16_t uint16
Definition Core.h:512
EPhysicsUpdateError
Enum used by PhysicsSystem to report error conditions during the PhysicsSystem::Update call....
Definition EPhysicsUpdateError.h:11
JPH_INLINE float Sqrt(float inV)
Take the square root of a float value.
Definition Math.h:76
#define JPH_OVERRIDE_NEW_DELETE
Macro to override the new and delete functions.
Definition Memory.h:50
This is a copy of AngleConstraintPart, specialized to handle contact constraints. See the documentati...
Definition AngularFrictionConstraintPart.h:41
Definition Array.h:36
Definition Body.h:39
float GetRestitution() const
Restitution (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision respon...
Definition Body.h:146
float GetFriction() const
Friction (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals f...
Definition Body.h:142
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:85
Definition ContactConstraintManager.h:33
static bool sDrawContactPoint
Definition ContactConstraintManager.h:251
CombineFunction GetCombineFriction() const
Definition ContactConstraintManager.h:58
CombineFunction GetCombineRestitution() const
Definition ContactConstraintManager.h:63
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:69
uint32 GetMaxConstraints() const
Get the max number of contact constraints that are allowed.
Definition ContactConstraintManager.h:66
static bool sDrawContactPointReduction
Definition ContactConstraintManager.h:253
void * BodyPairHandle
Handle used to keep track of the current body pair.
Definition ContactConstraintManager.h:102
void GetAffectedBodies(uint32 inConstraintOffset, const Body *&outBody1, const Body *&outBody2) const
Get the affected bodies for a given constraint.
Definition ContactConstraintManager.h:171
ContactListener * GetContactListener() const
Definition ContactConstraintManager.h:48
static bool sDrawSupportingFaces
Definition ContactConstraintManager.h:252
uint32 GetNumConstraints() const
Get the number of contact constraints that were found.
Definition ContactConstraintManager.h:162
void SetCombineFriction(CombineFunction inCombineFriction)
Definition ContactConstraintManager.h:57
void SetContactListener(ContactListener *inListener)
Listener that is notified whenever a contact point between two bodies is added/updated/removed.
Definition ContactConstraintManager.h:47
float(*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2) CombineFunction
Definition ContactConstraintManager.h:53
void SetCombineRestitution(CombineFunction inCombineRestitution)
Definition ContactConstraintManager.h:62
ContactAllocator GetContactAllocator()
Get a new allocator context for storing contacts. Note that you should call this once and then add mu...
Definition ContactConstraintManager.h:95
static bool sDrawContactManifolds
Definition ContactConstraintManager.h:254
This is a copy of AxisConstraintPart, specialized to handle contact constraints. See the documentatio...
Definition ContactConstraintPart.h:87
Definition ContactListener.h:79
Manifold class, describes the contact surface between two bodies.
Definition ContactListener.h:20
Definition ContactListener.h:41
Definition DebugRenderer.h:47
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:88
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:29
Class that makes another class non-copyable. Usage: Inherit from NonCopyable.
Definition NonCopyable.h:11
User callbacks that allow determining which parts of the simulation should be saved by a StateRecorde...
Definition StateRecorder.h:79
Definition StateRecorder.h:110
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:17
JPH_INLINE Vec3 Cross(Vec3Arg inV2) const
Cross product.
Definition Vec3.inl:855
JPH_INLINE Vec3 GetNormalizedPerpendicular() const
Get normalized vector that is perpendicular to this vector.
Definition Vec3.inl:1119
static JPH_INLINE Vec3 sLoadFloat3Unsafe(const Float3 &inV)
Load 3 floats from memory (reads 32 bits extra which it doesn't use)
Definition Vec3.inl:167
Templatized vector class.
Definition Vector.h:12
Structure that holds a body pair.
Definition BodyPair.h:14
Definition PhysicsSettings.h:31