Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
ContactConstraintManager Class Reference

#include <ContactConstraintManager.h>

Inheritance diagram for ContactConstraintManager:
NonCopyable

Classes

class  ContactAllocator
 Contacts are allocated in a lock free hash map. More...
 

Public Types

using CombineFunction = float(*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2)
 
using BodyPairHandle = void *
 Handle used to keep track of the current body pair.
 

Public Member Functions

JPH_OVERRIDE_NEW_DELETE ContactConstraintManager (const PhysicsSettings &inPhysicsSettings)
 Constructor.
 
 ~ContactConstraintManager ()
 
void Init (uint inMaxBodyPairs, uint inMaxContactConstraints)
 
void SetContactListener (ContactListener *inListener)
 Listener that is notified whenever a contact point between two bodies is added/updated/removed.
 
ContactListenerGetContactListener () const
 
void SetCombineFriction (CombineFunction inCombineFriction)
 
CombineFunction GetCombineFriction () const
 
void SetCombineRestitution (CombineFunction inCombineRestitution)
 
CombineFunction GetCombineRestitution () const
 
uint32 GetMaxConstraints () const
 Get the max number of contact constraints that are allowed.
 
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.
 
void PrepareConstraintBuffer (PhysicsUpdateContext *inContext)
 Sets up the constraint buffer. Should be called before starting collision detection.
 
ContactAllocator GetContactAllocator ()
 Get a new allocator context for storing contacts. Note that you should call this once and then add multiple contacts using the context.
 
void GetContactsFromCache (ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outConstraintCreated)
 
BodyPairHandle AddBodyPair (ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2)
 
bool AddContactConstraint (ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPair, Body &inBody1, Body &inBody2, const ContactManifold &inManifold)
 
void FinalizeContactCacheAndCallContactPointRemovedCallbacks (uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
 
bool WereBodiesInContact (const BodyID &inBody1ID, const BodyID &inBody2ID) const
 
uint32 GetNumConstraints () const
 Get the number of contact constraints that were found.
 
void SortContacts (uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd) const
 Sort contact constraints deterministically.
 
void GetAffectedBodies (uint32 inConstraintIdx, const Body *&outBody1, const Body *&outBody2) const
 Get the affected bodies for a given constraint.
 
template<class MotionPropertiesCallback >
void WarmStartVelocityConstraints (const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, MotionPropertiesCallback &ioCallback)
 Apply last frame's impulses as an initial guess for this frame's impulses.
 
bool SolveVelocityConstraints (const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
 
void StoreAppliedImpulses (const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const
 Save back the lambdas to the contact cache for the next warm start.
 
bool SolvePositionConstraints (const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
 
void RecycleConstraintBuffer ()
 Recycle the constraint buffer. Should be called between collision simulation steps.
 
void FinishConstraintBuffer ()
 Terminate the constraint buffer. Should be called after simulation ends.
 
void OnCCDContactAdded (ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings)
 
void SaveState (StateRecorder &inStream, const StateRecorderFilter *inFilter) const
 Saving state for replay.
 
bool RestoreState (StateRecorder &inStream)
 Restoring state for replay. Returns false when failed.
 
- Public Member Functions inherited from NonCopyable
 NonCopyable ()=default
 
 NonCopyable (const NonCopyable &)=delete
 
void operator= (const NonCopyable &)=delete
 

Static Public Attributes

static const int MaxContactPoints = 4
 Max 4 contact points are needed for a stable manifold.
 
static bool sDrawContactPoint = false
 
static bool sDrawSupportingFaces = false
 
static bool sDrawContactPointReduction = false
 
static bool sDrawContactManifolds = false
 

Member Typedef Documentation

◆ BodyPairHandle

Handle used to keep track of the current body pair.

◆ CombineFunction

using ContactConstraintManager::CombineFunction = float (*)(const Body &inBody1, const SubShapeID &inSubShapeID1, const Body &inBody2, const SubShapeID &inSubShapeID2)

Callback function to combine the restitution or friction of two bodies Note that when merging manifolds (when PhysicsSettings::mUseManifoldReduction is true) you will only get a callback for the merged manifold. It is not possible in that case to get all sub shape ID pairs that were colliding, you'll get the first encountered pair.

Constructor & Destructor Documentation

◆ ContactConstraintManager()

ContactConstraintManager::ContactConstraintManager ( const PhysicsSettings inPhysicsSettings)
explicit

Constructor.

◆ ~ContactConstraintManager()

ContactConstraintManager::~ContactConstraintManager ( )

Member Function Documentation

◆ AddBodyPair()

ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair ( ContactAllocator ioContactAllocator,
const Body inBody1,
const Body inBody2 
)

Create a handle for a colliding body pair so that contact constraints can be added between them. Needs to be called once per body pair per frame before calling AddContactConstraint.

◆ AddContactConstraint()

bool ContactConstraintManager::AddContactConstraint ( ContactAllocator ioContactAllocator,
BodyPairHandle  inBodyPair,
Body inBody1,
Body inBody2,
const ContactManifold inManifold 
)

Add a contact constraint for this frame.

Parameters
ioContactAllocatorThe allocator that reserves memory for the contacts
inBodyPairThe handle for the contact cache for this body pair
inBody1The first body that is colliding
inBody2The second body that is colliding
inManifoldThe manifold that describes the collision
Returns
true if a contact constraint was created (can be false in the case of a sensor)

This is using the approach described in 'Modeling and Solving Constraints' by Erin Catto presented at GDC 2009 (and later years with slight modifications). We're using the formulas from slide 50 - 53 combined.

Euler velocity integration:

v1' = v1 + M^-1 P

Impulse:

P = J^T lambda

Constraint force:

lambda = -K^-1 J v1

Inverse effective mass:

K = J M^-1 J^T

Constraint equation (limits movement in 1 axis):

C = (p2 - p1) . n

Jacobian (for position constraint)

J = [-n, -r1 x n, n, r2 x n]

n = contact normal (pointing away from body 1). p1, p2 = positions of collision on body 1 and 2. r1, r2 = contact point relative to center of mass of body 1 and body 2 (r1 = p1 - x1, r2 = p2 - x2). v1, v2 = (linear velocity, angular velocity): 6 vectors containing linear and angular velocity for body 1 and 2. M = mass matrix, a diagonal matrix of the mass and inertia with diagonal [m1, I1, m2, I2].

◆ FinalizeContactCacheAndCallContactPointRemovedCallbacks()

void ContactConstraintManager::FinalizeContactCacheAndCallContactPointRemovedCallbacks ( uint  inExpectedNumBodyPairs,
uint  inExpectedNumManifolds 
)

Finalizes the contact cache, the contact cache that was generated during the calls to AddContactConstraint in this update will be used from now on to read from. After finalizing the contact cache, the contact removed callbacks will be called. 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 in the next update.

◆ FinishConstraintBuffer()

void ContactConstraintManager::FinishConstraintBuffer ( )

Terminate the constraint buffer. Should be called after simulation ends.

◆ GetAffectedBodies()

void ContactConstraintManager::GetAffectedBodies ( uint32  inConstraintIdx,
const Body *&  outBody1,
const Body *&  outBody2 
) const
inline

Get the affected bodies for a given constraint.

◆ GetCombineFriction()

CombineFunction ContactConstraintManager::GetCombineFriction ( ) const
inline

◆ GetCombineRestitution()

CombineFunction ContactConstraintManager::GetCombineRestitution ( ) const
inline

◆ GetContactAllocator()

ContactAllocator ContactConstraintManager::GetContactAllocator ( )
inline

Get a new allocator context for storing contacts. Note that you should call this once and then add multiple contacts using the context.

◆ GetContactListener()

ContactListener * ContactConstraintManager::GetContactListener ( ) const
inline

◆ GetContactsFromCache()

void ContactConstraintManager::GetContactsFromCache ( ContactAllocator ioContactAllocator,
Body inBody1,
Body inBody2,
bool &  outPairHandled,
bool &  outConstraintCreated 
)

Check if the contact points from the previous frame are reusable and if so copy them. When the cache was usable and the pair has been handled: outPairHandled = true. When a contact constraint was produced: outConstraintCreated = true.

◆ GetMaxConstraints()

uint32 ContactConstraintManager::GetMaxConstraints ( ) const
inline

Get the max number of contact constraints that are allowed.

◆ GetNumConstraints()

uint32 ContactConstraintManager::GetNumConstraints ( ) const
inline

Get the number of contact constraints that were found.

◆ Init()

void ContactConstraintManager::Init ( uint  inMaxBodyPairs,
uint  inMaxContactConstraints 
)

Initialize the system.

Parameters
inMaxBodyPairsMaximum 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
inMaxContactConstraintsMaximum amount of contact constraints to process (anything else will fall through the world)

◆ OnCCDContactAdded()

void ContactConstraintManager::OnCCDContactAdded ( ContactAllocator ioContactAllocator,
const Body inBody1,
const Body inBody2,
const ContactManifold inManifold,
ContactSettings outSettings 
)

Called by continuous collision detection to notify the contact listener that a contact was added

Parameters
ioContactAllocatorThe allocator that reserves memory for the contacts
inBody1The first body that is colliding
inBody2The second body that is colliding
inManifoldThe manifold that describes the collision
outSettingsThe calculated contact settings (may be overridden by the contact listener)

◆ PrepareConstraintBuffer()

void ContactConstraintManager::PrepareConstraintBuffer ( PhysicsUpdateContext inContext)

Sets up the constraint buffer. Should be called before starting collision detection.

◆ RecycleConstraintBuffer()

void ContactConstraintManager::RecycleConstraintBuffer ( )

Recycle the constraint buffer. Should be called between collision simulation steps.

◆ RestoreState()

bool ContactConstraintManager::RestoreState ( StateRecorder inStream)

Restoring state for replay. Returns false when failed.

◆ SaveState()

void ContactConstraintManager::SaveState ( StateRecorder inStream,
const StateRecorderFilter inFilter 
) const

Saving state for replay.

◆ SetCombineFriction()

void ContactConstraintManager::SetCombineFriction ( CombineFunction  inCombineFriction)
inline

Set the function that combines the friction of two bodies and returns it Default method is the geometric mean: sqrt(friction1 * friction2).

◆ SetCombineRestitution()

void ContactConstraintManager::SetCombineRestitution ( CombineFunction  inCombineRestitution)
inline

Set the function that combines the restitution of two bodies and returns it Default method is max(restitution1, restitution1)

◆ SetContactListener()

void ContactConstraintManager::SetContactListener ( ContactListener inListener)
inline

Listener that is notified whenever a contact point between two bodies is added/updated/removed.

◆ SolvePositionConstraints()

bool ContactConstraintManager::SolvePositionConstraints ( const uint32 inConstraintIdxBegin,
const uint32 inConstraintIdxEnd 
)

Solve position constraints. This is using the approach described in 'Modeling and Solving Constraints' by Erin Catto presented at GDC 2007. On slide 78 it is suggested to split up the Baumgarte stabilization for positional drift so that it does not actually add to the momentum. We combine an Euler velocity integrate + a position integrate and then discard the velocity change.

Constraint force:

lambda = -K^-1 b

Baumgarte stabilization:

b = beta / dt C

beta = baumgarte stabilization factor. dt = delta time.

◆ SolveVelocityConstraints()

bool ContactConstraintManager::SolveVelocityConstraints ( const uint32 inConstraintIdxBegin,
const uint32 inConstraintIdxEnd 
)

Solve velocity constraints, when almost nothing changes this should only apply very small impulses since we're warm starting with the total impulse applied in the last frame above.

Friction wise we're using the Coulomb friction model which says that:

|F_T| <= mu |F_N|

Where F_T is the tangential force, F_N is the normal force and mu is the friction coefficient

In impulse terms this becomes:

|lambda_T| <= mu |lambda_N|

And the constraint that needs to be applied is exactly the same as a non penetration constraint except that we use a tangent instead of a normal. The tangent should point in the direction of the tangential velocity of the point:

J = [-T, -r1 x T, T, r2 x T]

Where T is the tangent.

See slide 42 and 43.

Restitution is implemented as a velocity bias (see slide 41):

b = e v_n^-

e = the restitution coefficient, v_n^- is the normal velocity prior to the collision

Restitution is only applied when v_n^- is large enough and the points are moving towards collision

◆ SortContacts()

void ContactConstraintManager::SortContacts ( uint32 inConstraintIdxBegin,
uint32 inConstraintIdxEnd 
) const

Sort contact constraints deterministically.

◆ StoreAppliedImpulses()

void ContactConstraintManager::StoreAppliedImpulses ( const uint32 inConstraintIdxBegin,
const uint32 inConstraintIdxEnd 
) const

Save back the lambdas to the contact cache for the next warm start.

◆ ValidateContactPoint()

ValidateResult ContactConstraintManager::ValidateContactPoint ( const Body inBody1,
const Body inBody2,
RVec3Arg  inBaseOffset,
const CollideShapeResult inCollisionResult 
) const
inline

Check with the listener if inBody1 and inBody2 could collide, returns false if not.

◆ WarmStartVelocityConstraints()

template<class MotionPropertiesCallback >
template void ContactConstraintManager::WarmStartVelocityConstraints< DummyCalculateSolverSteps > ( const uint32 inConstraintIdxBegin,
const uint32 inConstraintIdxEnd,
float  inWarmStartImpulseRatio,
MotionPropertiesCallback &  ioCallback 
)

Apply last frame's impulses as an initial guess for this frame's impulses.

◆ WereBodiesInContact()

bool ContactConstraintManager::WereBodiesInContact ( const BodyID inBody1ID,
const BodyID inBody2ID 
) const

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. Uses the read collision cache to determine if 2 bodies are in contact.

Member Data Documentation

◆ MaxContactPoints

const int ContactConstraintManager::MaxContactPoints = 4
static

Max 4 contact points are needed for a stable manifold.

◆ sDrawContactManifolds

bool ContactConstraintManager::sDrawContactManifolds = false
static

◆ sDrawContactPoint

bool ContactConstraintManager::sDrawContactPoint = false
static

◆ sDrawContactPointReduction

bool ContactConstraintManager::sDrawContactPointReduction = false
static

◆ sDrawSupportingFaces

bool ContactConstraintManager::sDrawSupportingFaces = false
static

The documentation for this class was generated from the following files: