43 void Init(
uint inMaxBodyPairs,
uint inMaxContactConstraints);
70 if (mContactListener ==
nullptr)
73 return mContactListener->OnContactValidate(inBody1, inBody2, inBaseOffset, inCollisionResult);
77 void PrepareConstraintBuffer(PhysicsUpdateContext *inContext);
80 static const int MaxContactPoints = 4;
98 void GetContactsFromCache(ContactAllocator &ioContactAllocator,
Body &inBody1,
Body &inBody2,
bool &outPairHandled);
154 void FinalizeContactCacheAndCallContactPointRemovedCallbacks(
uint inExpectedNumBodyPairs,
uint inExpectedNumManifolds);
158 bool WereBodiesInContact(
const BodyID &inBody1ID,
const BodyID &inBody2ID)
const;
164 void ConstraintIdxToConstraintOffset(
uint32 *ioConstraintIdxBegin,
const uint32 *inConstraintIdxEnd)
const;
167 void SortContacts(
uint32 *ioConstraintOffsetBegin,
uint32 *inConstraintOffsetEnd)
const;
172 const ContactConstraintBase &constraint = *
reinterpret_cast<const ContactConstraintBase *
>(mConstraints + inConstraintOffset);
173 outBody1 = constraint.mBody1;
174 outBody2 = constraint.mBody2;
178 template <
class MotionPropertiesCallback>
179 void WarmStartVelocityConstraints(
const uint32 *inConstraintOffsetBegin,
const uint32 *inConstraintOffsetEnd,
float inWarmStartImpulseRatio, MotionPropertiesCallback &ioCallback);
211 bool SolveVelocityConstraints(
const uint32 *inConstraintOffsetBegin,
const uint32 *inConstraintOffsetEnd);
214 void StoreAppliedImpulses(
const uint32 *inConstraintOffsetBegin,
const uint32 *inConstraintOffsetEnd)
const;
232 bool SolvePositionConstraints(
const uint32 *inConstraintOffsetBegin,
const uint32 *inConstraintOffsetEnd);
235 void RecycleConstraintBuffer();
238 void FinishConstraintBuffer();
248#ifdef JPH_DEBUG_RENDERER
264 class CachedContactPoint
277 float mNonPenetrationLambda;
281 static_assert(
sizeof(CachedContactPoint) == 36,
"Unexpected size");
282 static_assert(
alignof(CachedContactPoint) == 4,
"Assuming 4 byte aligned");
289 static constexpr int sGetRequiredExtraSize(
int inNumContactPoints) {
return max(0, inNumContactPoints - 1) *
sizeof(CachedContactPoint); }
292 static constexpr int sGetRequiredTotalSize(
int inNumContactPoints) {
return sizeof(CachedManifold) + sGetRequiredExtraSize(inNumContactPoints); }
299 uint32 mNextWithSameBodyPair;
306 enum class EFlags :
uint16
308 ContactPersisted = 1,
313 mutable atomic<uint16> mFlags { 0 };
319 CachedContactPoint mContactPoints[1];
322 static_assert(
sizeof(CachedManifold) == 56,
"This structure is expect to not contain any waste due to alignment");
323 static_assert(
alignof(CachedManifold) == 4,
"Assuming 4 byte aligned");
327 using MKeyValue = ManifoldMap::KeyValue;
328 using MKVAndCreated = std::pair<MKeyValue *, bool>;
347 uint32 mFirstCachedManifold;
350 static_assert(
sizeof(CachedBodyPair) == 28,
"Unexpected size");
351 static_assert(
alignof(CachedBodyPair) == 4,
"Assuming 4 byte aligned");
355 using BPKeyValue = BodyPairMap::KeyValue;
362 void Init(
uint inMaxBodyPairs,
uint inMaxContactConstraints,
uint inCachedManifoldsSize);
369 void Prepare(
uint inExpectedNumBodyPairs,
uint inExpectedNumManifolds);
372 ContactAllocator GetContactAllocator() {
return ContactAllocator(mAllocator, cAllocatorBlockSize); }
376 MKeyValue * Create(ContactAllocator &ioContactAllocator,
const SubShapeIDPair &inKey,
uint64 inKeyHash,
int inNumContactPoints);
377 MKVAndCreated FindOrCreate(ContactAllocator &ioContactAllocator,
const SubShapeIDPair &inKey,
uint64 inKeyHash,
int inNumContactPoints);
378 uint32 ToHandle(
const MKeyValue *inKeyValue)
const;
379 const MKeyValue * FromHandle(
uint32 inHandle)
const;
382 const BPKeyValue * Find(
const BodyPair &inKey,
uint64 inKeyHash)
const;
383 BPKeyValue * Create(ContactAllocator &ioContactAllocator,
const BodyPair &inKey,
uint64 inKeyHash);
389#ifdef JPH_ENABLE_ASSERTS
391 uint GetNumManifolds()
const {
return mCachedManifolds.GetNumKeyValues(); }
394 uint GetNumBodyPairs()
const {
return mCachedBodyPairs.GetNumKeyValues(); }
406 static constexpr uint32 cAllocatorBlockSize = 4096;
412 ManifoldMap mCachedManifolds { mAllocator };
415 BodyPairMap mCachedBodyPairs { mAllocator };
417#ifdef JPH_ENABLE_ASSERTS
418 bool mIsFinalized =
false;
422 ManifoldCache mCache[2];
423 int mCacheWriteIdx = 0;
426 template <EMotionType Type1, EMotionType Type2>
427 class WorldContactPoint
433 JPH_INLINE
void CalculateFrictionAndNonPenetrationConstraintProperties(
float inDeltaTime,
Vec3Arg inGravity,
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);
436 ConstraintPart mNonPenetrationConstraint;
437 ConstraintPart mFrictionConstraint1;
438 ConstraintPart mFrictionConstraint2;
442 CachedContactPoint * mContactPoint;
445 class ContactConstraintBase
449 JPH_INLINE
Vec3 GetWorldSpaceNormal()
const
455 JPH_INLINE
void GetTangents(
Vec3 &outTangent1,
Vec3 &outTangent2)
const
457 Vec3 ws_normal = GetWorldSpaceNormal();
459 outTangent2 = ws_normal.
Cross(outTangent1);
466 float mCombinedFriction;
468 float mInvInertiaScale1;
470 float mInvInertiaScale2;
475 template <EMotionType Type1, EMotionType Type2>
476 class ContactConstraint :
public ContactConstraintBase
479 #ifdef JPH_DEBUG_RENDERER
484 WorldContactPoint<Type1, Type2> mContactPoints[1];
489 static constexpr uint32 cMaxConstraintSize =
sizeof(ContactConstraint<EMotionType::Dynamic, EMotionType::Dynamic>) + (MaxContactPoints - 1) *
sizeof(WorldContactPoint<EMotionType::Dynamic, EMotionType::Dynamic>);
492 static constexpr uint cMaxContactConstraintsLimit =
~uint(0) / cMaxConstraintSize;
495 static constexpr uint cMaxBodyPairsLimit =
~uint(0) /
sizeof(BodyPairMap::KeyValue);
499 template <EMotionType Type1, EMotionType Type2>
500 JPH_INLINE ContactConstraint<Type1, Type2> *CreateConstraint(
bool &ioActivateAndLinkBodies,
Body &inBody1,
Body &inBody2,
uint64 inSortKey,
Vec3Arg inWorldSpaceNormal,
const ContactSettings &inSettings,
uint32 inNumContactPoints);
503 template <EMotionType Type1, EMotionType Type2>
504 void TemplatedGetContactsFromCache(
ContactAllocator &ioContactAllocator,
Body &inBody1,
Body &inBody2,
const CachedBodyPair &inCachedBodyPair, CachedBodyPair &outCachedBodyPair);
507 template <EMotionType Type1, EMotionType Type2>
511 template <EMotionType Type1, EMotionType Type2>
515 template <EMotionType Type1, EMotionType Type2>
519 template <EMotionType Type1, EMotionType Type2>
520 static void sWarmStartConstraint(ContactConstraintBase &ioConstraint,
MotionProperties *ioMotionProperties1,
MotionProperties *ioMotionProperties2,
float inWarmStartImpulseRatio);
523 template <EMotionType Type1, EMotionType Type2>
527 template <EMotionType Type1, EMotionType Type2>
528 static void sStoreAppliedImpulses(ContactConstraintBase &ioConstraint);
531 template <EMotionType Type1, EMotionType Type2>
532 static bool sSolvePositionConstraint(ContactConstraintBase &ioConstraint,
Body &ioBody1,
Body &ioBody2,
const PhysicsSettings &inSettings);
545 uint8 * mConstraints =
nullptr;
546 uint32 * mConstraintIdxToOffset =
nullptr;
547 uint32 mMaxConstraints = 0;
548 atomic<uint64> mNumConstraintsAndNextConstraintOffset { 0 };
551 PhysicsUpdateContext * mUpdateContext;
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
LFHMAllocatorContext(LFHMAllocator &inAllocator, uint32 inBlockSize)
Construct a new allocator context.
Definition LockFreeHashMap.inl:88
Structure that holds a body pair.
Definition BodyPair.h:14