ContactConstraintManager.h 24 KB

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