ContactConstraintManager.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Physics/Constraints/ContactConstraintManager.h>
  5. #include <Jolt/Physics/Body/Body.h>
  6. #include <Jolt/Physics/PhysicsUpdateContext.h>
  7. #include <Jolt/Physics/PhysicsSettings.h>
  8. #include <Jolt/Physics/IslandBuilder.h>
  9. #include <Jolt/Physics/DeterminismLog.h>
  10. #include <Jolt/Core/TempAllocator.h>
  11. #include <Jolt/Core/QuickSort.h>
  12. #ifdef JPH_DEBUG_RENDERER
  13. #include <Jolt/Renderer/DebugRenderer.h>
  14. #endif // JPH_DEBUG_RENDERER
  15. JPH_NAMESPACE_BEGIN
  16. #ifdef JPH_DEBUG_RENDERER
  17. bool ContactConstraintManager::sDrawContactPoint = false;
  18. bool ContactConstraintManager::sDrawSupportingFaces = false;
  19. bool ContactConstraintManager::sDrawContactPointReduction = false;
  20. bool ContactConstraintManager::sDrawContactManifolds = false;
  21. #endif // JPH_DEBUG_RENDERER
  22. //#define JPH_MANIFOLD_CACHE_DEBUG
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. // ContactConstraintManager::WorldContactPoint
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. void ContactConstraintManager::WorldContactPoint::CalculateNonPenetrationConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, Vec3Arg inWorldSpacePosition1, Vec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal)
  27. {
  28. // Calculate collision points relative to body
  29. Vec3 p = 0.5f * (inWorldSpacePosition1 + inWorldSpacePosition2);
  30. Vec3 r1 = p - inBody1.GetCenterOfMassPosition();
  31. Vec3 r2 = p - inBody2.GetCenterOfMassPosition();
  32. mNonPenetrationConstraint.CalculateConstraintProperties(inDeltaTime, inBody1, r1, inBody2, r2, inWorldSpaceNormal);
  33. }
  34. template <EMotionType Type1, EMotionType Type2>
  35. JPH_INLINE void ContactConstraintManager::WorldContactPoint::CalculateFrictionAndNonPenetrationConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, Mat44Arg inInvI1, Mat44Arg inInvI2, Vec3Arg inWorldSpacePosition1, Vec3Arg inWorldSpacePosition2, Vec3Arg inWorldSpaceNormal, Vec3Arg inWorldSpaceTangent1, Vec3Arg inWorldSpaceTangent2, float inCombinedRestitution, float inCombinedFriction, float inMinVelocityForRestitution)
  36. {
  37. JPH_DET_LOG("CalculateFrictionAndNonPenetrationConstraintProperties: p1: " << inWorldSpacePosition1 << " p2: " << inWorldSpacePosition2
  38. << " normal: " << inWorldSpaceNormal << " tangent1: " << inWorldSpaceTangent1 << " tangent2: " << inWorldSpaceTangent2
  39. << " restitution: " << inCombinedRestitution << " friction: " << inCombinedFriction << " minv: " << inMinVelocityForRestitution);
  40. // Calculate collision points relative to body
  41. Vec3 p = 0.5f * (inWorldSpacePosition1 + inWorldSpacePosition2);
  42. Vec3 r1 = p - inBody1.GetCenterOfMassPosition();
  43. Vec3 r2 = p - inBody2.GetCenterOfMassPosition();
  44. const MotionProperties *mp1 = inBody1.GetMotionPropertiesUnchecked();
  45. const MotionProperties *mp2 = inBody2.GetMotionPropertiesUnchecked();
  46. // Calculate velocity of collision points
  47. Vec3 relative_velocity;
  48. if constexpr (Type1 != EMotionType::Static && Type2 != EMotionType::Static)
  49. relative_velocity = mp2->GetPointVelocityCOM(r2) - mp1->GetPointVelocityCOM(r1);
  50. else if constexpr (Type1 != EMotionType::Static)
  51. relative_velocity = -mp1->GetPointVelocityCOM(r1);
  52. else if constexpr (Type2 != EMotionType::Static)
  53. relative_velocity = mp2->GetPointVelocityCOM(r2);
  54. else
  55. {
  56. JPH_ASSERT(false); // Static vs static makes no sense
  57. relative_velocity = Vec3::sZero();
  58. }
  59. float normal_velocity = relative_velocity.Dot(inWorldSpaceNormal);
  60. // How much the shapes are penetrating (> 0 if penetrating, < 0 if separated)
  61. float penetration = (inWorldSpacePosition1 - inWorldSpacePosition2).Dot(inWorldSpaceNormal);
  62. // If there is no penetration, this is a speculative contact and we will apply a bias to the contact constraint
  63. // so that the constraint becomes relative_velocity . contact normal > -penetration / delta_time
  64. // instead of relative_velocity . contact normal > 0
  65. // See: GDC 2013: "Physics for Game Programmers; Continuous Collision" - Erin Catto
  66. float speculative_contact_velocity_bias = max(0.0f, -penetration / inDeltaTime);
  67. // Determine if the velocity is big enough for restitution
  68. float normal_velocity_bias;
  69. if (inCombinedRestitution > 0.0f && normal_velocity < -inMinVelocityForRestitution)
  70. {
  71. // We have a velocity that is big enough for restitution. This is where speculative contacts don't work
  72. // great as we have to decide now if we're going to apply the restitution or not. If the relative
  73. // velocity is big enough for a hit, we apply the restitution (in the end, due to other constraints,
  74. // the objects may actually not collide and we will have applied restitution incorrectly). Another
  75. // artifact that occurs because of this approximation is that the object will bounce from its current
  76. // position rather than from a position where it is touching the other object. This causes the object
  77. // to appear to move faster for 1 frame (the opposite of time stealing).
  78. if (normal_velocity < -speculative_contact_velocity_bias)
  79. normal_velocity_bias = inCombinedRestitution * normal_velocity;
  80. else
  81. normal_velocity_bias = 0.0f;
  82. }
  83. else
  84. {
  85. // No restitution. We can safely apply our contact velocity bias.
  86. normal_velocity_bias = speculative_contact_velocity_bias;
  87. }
  88. mNonPenetrationConstraint.TemplatedCalculateConstraintProperties<Type1, Type2>(inDeltaTime, mp1, inInvI1, r1, mp2, inInvI2, r2, inWorldSpaceNormal, normal_velocity_bias);
  89. // Calculate friction part
  90. if (inCombinedFriction > 0.0f)
  91. {
  92. // Implement friction as 2 AxisContraintParts
  93. mFrictionConstraint1.TemplatedCalculateConstraintProperties<Type1, Type2>(inDeltaTime, mp1, inInvI1, r1, mp2, inInvI2, r2, inWorldSpaceTangent1);
  94. mFrictionConstraint2.TemplatedCalculateConstraintProperties<Type1, Type2>(inDeltaTime, mp1, inInvI1, r1, mp2, inInvI2, r2, inWorldSpaceTangent2);
  95. }
  96. else
  97. {
  98. // Turn off friction constraint
  99. mFrictionConstraint1.Deactivate();
  100. mFrictionConstraint2.Deactivate();
  101. }
  102. }
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. // ContactConstraintManager::ContactConstraint
  105. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  106. #ifdef JPH_DEBUG_RENDERER
  107. void ContactConstraintManager::ContactConstraint::Draw(DebugRenderer *inRenderer, ColorArg inManifoldColor) const
  108. {
  109. if (mContactPoints.empty())
  110. return;
  111. // Get body transforms
  112. Mat44 transform_body1 = mBody1->GetCenterOfMassTransform();
  113. Mat44 transform_body2 = mBody2->GetCenterOfMassTransform();
  114. Vec3 prev_point = transform_body1 * Vec3::sLoadFloat3Unsafe(mContactPoints.back().mContactPoint->mPosition1);
  115. for (const WorldContactPoint &wcp : mContactPoints)
  116. {
  117. // Test if any lambda from the previous frame was transferred
  118. float radius = wcp.mNonPenetrationConstraint.GetTotalLambda() == 0.0f
  119. && wcp.mFrictionConstraint1.GetTotalLambda() == 0.0f
  120. && wcp.mFrictionConstraint2.GetTotalLambda() == 0.0f? 0.1f : 0.2f;
  121. Vec3 next_point = transform_body1 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition1);
  122. inRenderer->DrawMarker(next_point, Color::sCyan, radius);
  123. inRenderer->DrawMarker(transform_body2 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition2), Color::sPurple, radius);
  124. // Draw edge
  125. inRenderer->DrawArrow(prev_point, next_point, inManifoldColor, 0.05f);
  126. prev_point = next_point;
  127. }
  128. // Draw normal
  129. Vec3 wp = transform_body1 * Vec3::sLoadFloat3Unsafe(mContactPoints[0].mContactPoint->mPosition1);
  130. inRenderer->DrawArrow(wp, wp + mWorldSpaceNormal, Color::sRed, 0.05f);
  131. // Get tangents
  132. Vec3 t1, t2;
  133. GetTangents(t1, t2);
  134. // Draw tangents
  135. inRenderer->DrawLine(wp, wp + t1, Color::sGreen);
  136. inRenderer->DrawLine(wp, wp + t2, Color::sBlue);
  137. }
  138. #endif // JPH_DEBUG_RENDERER
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. // ContactConstraintManager::CachedContactPoint
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. void ContactConstraintManager::CachedContactPoint::SaveState(StateRecorder &inStream) const
  143. {
  144. inStream.Write(mPosition1);
  145. inStream.Write(mPosition2);
  146. inStream.Write(mNonPenetrationLambda);
  147. inStream.Write(mFrictionLambda);
  148. }
  149. void ContactConstraintManager::CachedContactPoint::RestoreState(StateRecorder &inStream)
  150. {
  151. inStream.Read(mPosition1);
  152. inStream.Read(mPosition2);
  153. inStream.Read(mNonPenetrationLambda);
  154. inStream.Read(mFrictionLambda);
  155. }
  156. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. // ContactConstraintManager::CachedManifold
  158. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. void ContactConstraintManager::CachedManifold::SaveState(StateRecorder &inStream) const
  160. {
  161. inStream.Write(mContactNormal);
  162. }
  163. void ContactConstraintManager::CachedManifold::RestoreState(StateRecorder &inStream)
  164. {
  165. inStream.Read(mContactNormal);
  166. }
  167. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  168. // ContactConstraintManager::CachedBodyPair
  169. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  170. void ContactConstraintManager::CachedBodyPair::SaveState(StateRecorder &inStream) const
  171. {
  172. inStream.Write(mDeltaPosition);
  173. inStream.Write(mDeltaRotation);
  174. }
  175. void ContactConstraintManager::CachedBodyPair::RestoreState(StateRecorder &inStream)
  176. {
  177. inStream.Read(mDeltaPosition);
  178. inStream.Read(mDeltaRotation);
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  181. // ContactConstraintManager::ManifoldCache
  182. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  183. void ContactConstraintManager::ManifoldCache::Init(uint inMaxBodyPairs, uint inMaxContactConstraints, uint inCachedManifoldsSize)
  184. {
  185. mAllocator.Init(inMaxBodyPairs * sizeof(BodyPairMap::KeyValue) + inCachedManifoldsSize);
  186. mCachedManifolds.Init(GetNextPowerOf2(inMaxContactConstraints));
  187. mCachedBodyPairs.Init(GetNextPowerOf2(inMaxBodyPairs));
  188. }
  189. void ContactConstraintManager::ManifoldCache::Clear()
  190. {
  191. JPH_PROFILE_FUNCTION();
  192. mCachedManifolds.Clear();
  193. mCachedBodyPairs.Clear();
  194. mAllocator.Clear();
  195. #ifdef JPH_ENABLE_ASSERTS
  196. // Mark as incomplete
  197. mIsFinalized = false;
  198. #endif
  199. }
  200. void ContactConstraintManager::ManifoldCache::Prepare(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
  201. {
  202. // Minimum amount of buckets to use in the hash map
  203. constexpr uint32 cMinBuckets = 1024;
  204. // Use the next higher power of 2 of amount of objects in the cache from last frame to determine the amount of buckets in this frame
  205. mCachedManifolds.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inExpectedNumManifolds)), mCachedManifolds.GetMaxBuckets()));
  206. mCachedBodyPairs.SetNumBuckets(min(max(cMinBuckets, GetNextPowerOf2(inExpectedNumBodyPairs)), mCachedBodyPairs.GetMaxBuckets()));
  207. }
  208. const ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::Find(const SubShapeIDPair &inKey, uint64 inKeyHash) const
  209. {
  210. JPH_ASSERT(mIsFinalized);
  211. return mCachedManifolds.Find(inKey, inKeyHash);
  212. }
  213. ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::Create(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints)
  214. {
  215. JPH_ASSERT(!mIsFinalized);
  216. MKeyValue *kv = mCachedManifolds.Create(ioContactAllocator, inKey, inKeyHash, CachedManifold::sGetRequiredExtraSize(inNumContactPoints));
  217. if (kv == nullptr)
  218. {
  219. JPH_ASSERT(false, "Out of cache space for manifold cache");
  220. return nullptr;
  221. }
  222. kv->GetValue().mNumContactPoints = uint16(inNumContactPoints);
  223. ++ioContactAllocator.mNumManifolds;
  224. return kv;
  225. }
  226. ContactConstraintManager::MKVAndCreated ContactConstraintManager::ManifoldCache::FindOrCreate(ContactAllocator &ioContactAllocator, const SubShapeIDPair &inKey, uint64 inKeyHash, int inNumContactPoints)
  227. {
  228. MKeyValue *kv = const_cast<MKeyValue *>(mCachedManifolds.Find(inKey, inKeyHash));
  229. if (kv != nullptr)
  230. return { kv, false };
  231. return { Create(ioContactAllocator, inKey, inKeyHash, inNumContactPoints), true };
  232. }
  233. uint32 ContactConstraintManager::ManifoldCache::ToHandle(const MKeyValue *inKeyValue) const
  234. {
  235. JPH_ASSERT(!mIsFinalized);
  236. return mCachedManifolds.ToHandle(inKeyValue);
  237. }
  238. const ContactConstraintManager::MKeyValue *ContactConstraintManager::ManifoldCache::FromHandle(uint32 inHandle) const
  239. {
  240. JPH_ASSERT(mIsFinalized);
  241. return mCachedManifolds.FromHandle(inHandle);
  242. }
  243. const ContactConstraintManager::BPKeyValue *ContactConstraintManager::ManifoldCache::Find(const BodyPair &inKey, uint64 inKeyHash) const
  244. {
  245. JPH_ASSERT(mIsFinalized);
  246. return mCachedBodyPairs.Find(inKey, inKeyHash);
  247. }
  248. ContactConstraintManager::BPKeyValue *ContactConstraintManager::ManifoldCache::Create(ContactAllocator &ioContactAllocator, const BodyPair &inKey, uint64 inKeyHash)
  249. {
  250. JPH_ASSERT(!mIsFinalized);
  251. BPKeyValue *kv = mCachedBodyPairs.Create(ioContactAllocator, inKey, inKeyHash, 0);
  252. if (kv == nullptr)
  253. {
  254. JPH_ASSERT(false, "Out of cache space for body pair cache");
  255. return nullptr;
  256. }
  257. ++ioContactAllocator.mNumBodyPairs;
  258. return kv;
  259. }
  260. void ContactConstraintManager::ManifoldCache::GetAllBodyPairsSorted(Array<const BPKeyValue *> &outAll) const
  261. {
  262. JPH_ASSERT(mIsFinalized);
  263. mCachedBodyPairs.GetAllKeyValues(outAll);
  264. // Sort by key
  265. QuickSort(outAll.begin(), outAll.end(), [](const BPKeyValue *inLHS, const BPKeyValue *inRHS) {
  266. return inLHS->GetKey() < inRHS->GetKey();
  267. });
  268. }
  269. void ContactConstraintManager::ManifoldCache::GetAllManifoldsSorted(const CachedBodyPair &inBodyPair, Array<const MKeyValue *> &outAll) const
  270. {
  271. JPH_ASSERT(mIsFinalized);
  272. // Iterate through the attached manifolds
  273. for (uint32 handle = inBodyPair.mFirstCachedManifold; handle != ManifoldMap::cInvalidHandle; handle = FromHandle(handle)->GetValue().mNextWithSameBodyPair)
  274. {
  275. const MKeyValue *kv = mCachedManifolds.FromHandle(handle);
  276. outAll.push_back(kv);
  277. }
  278. // Sort by key
  279. QuickSort(outAll.begin(), outAll.end(), [](const MKeyValue *inLHS, const MKeyValue *inRHS) {
  280. return inLHS->GetKey() < inRHS->GetKey();
  281. });
  282. }
  283. void ContactConstraintManager::ManifoldCache::GetAllCCDManifoldsSorted(Array<const MKeyValue *> &outAll) const
  284. {
  285. mCachedManifolds.GetAllKeyValues(outAll);
  286. for (int i = (int)outAll.size() - 1; i >= 0; --i)
  287. if ((outAll[i]->GetValue().mFlags & (uint16)CachedManifold::EFlags::CCDContact) == 0)
  288. {
  289. outAll[i] = outAll.back();
  290. outAll.pop_back();
  291. }
  292. // Sort by key
  293. QuickSort(outAll.begin(), outAll.end(), [](const MKeyValue *inLHS, const MKeyValue *inRHS) {
  294. return inLHS->GetKey() < inRHS->GetKey();
  295. });
  296. }
  297. void ContactConstraintManager::ManifoldCache::ContactPointRemovedCallbacks(ContactListener *inListener)
  298. {
  299. for (MKeyValue &kv : mCachedManifolds)
  300. if ((kv.GetValue().mFlags & uint16(CachedManifold::EFlags::ContactPersisted)) == 0)
  301. inListener->OnContactRemoved(kv.GetKey());
  302. }
  303. #ifdef JPH_ENABLE_ASSERTS
  304. void ContactConstraintManager::ManifoldCache::Finalize()
  305. {
  306. mIsFinalized = true;
  307. #ifdef JPH_MANIFOLD_CACHE_DEBUG
  308. Trace("ManifoldMap:");
  309. mCachedManifolds.TraceStats();
  310. Trace("BodyPairMap:");
  311. mCachedBodyPairs.TraceStats();
  312. #endif // JPH_MANIFOLD_CACHE_DEBUG
  313. }
  314. #endif
  315. void ContactConstraintManager::ManifoldCache::SaveState(StateRecorder &inStream) const
  316. {
  317. JPH_ASSERT(mIsFinalized);
  318. // Get contents of cache
  319. Array<const BPKeyValue *> all_bp;
  320. GetAllBodyPairsSorted(all_bp);
  321. // Write amount of body pairs
  322. size_t num_body_pairs = all_bp.size();
  323. inStream.Write(num_body_pairs);
  324. // Write all body pairs
  325. for (const BPKeyValue *bp_kv : all_bp)
  326. {
  327. // Write body pair key
  328. inStream.Write(bp_kv->GetKey());
  329. // Write body pair
  330. const CachedBodyPair &bp = bp_kv->GetValue();
  331. bp.SaveState(inStream);
  332. // Get attached manifolds
  333. Array<const MKeyValue *> all_m;
  334. GetAllManifoldsSorted(bp, all_m);
  335. // Write num manifolds
  336. size_t num_manifolds = all_m.size();
  337. inStream.Write(num_manifolds);
  338. // Write all manifolds
  339. for (const MKeyValue *m_kv : all_m)
  340. {
  341. // Write key
  342. inStream.Write(m_kv->GetKey());
  343. const CachedManifold &cm = m_kv->GetValue();
  344. JPH_ASSERT((cm.mFlags & (uint16)CachedManifold::EFlags::CCDContact) == 0);
  345. // Write amount of contacts
  346. inStream.Write(cm.mNumContactPoints);
  347. // Write manifold
  348. cm.SaveState(inStream);
  349. // Write contact points
  350. for (uint32 i = 0; i < cm.mNumContactPoints; ++i)
  351. cm.mContactPoints[i].SaveState(inStream);
  352. }
  353. }
  354. // Get CCD manifolds
  355. Array<const MKeyValue *> all_m;
  356. GetAllCCDManifoldsSorted(all_m);
  357. // Write num CCD manifolds
  358. size_t num_manifolds = all_m.size();
  359. inStream.Write(num_manifolds);
  360. // Write all CCD manifold keys
  361. for (const MKeyValue *m_kv : all_m)
  362. inStream.Write(m_kv->GetKey());
  363. }
  364. bool ContactConstraintManager::ManifoldCache::RestoreState(const ManifoldCache &inReadCache, StateRecorder &inStream)
  365. {
  366. JPH_ASSERT(!mIsFinalized);
  367. bool success = true;
  368. // Create a contact allocator for restoring the contact cache
  369. ContactAllocator contact_allocator(GetContactAllocator());
  370. // When validating, get all existing body pairs
  371. Array<const BPKeyValue *> all_bp;
  372. if (inStream.IsValidating())
  373. inReadCache.GetAllBodyPairsSorted(all_bp);
  374. // Read amount of body pairs
  375. size_t num_body_pairs;
  376. if (inStream.IsValidating())
  377. num_body_pairs = all_bp.size();
  378. inStream.Read(num_body_pairs);
  379. // Read entire cache
  380. for (size_t i = 0; i < num_body_pairs; ++i)
  381. {
  382. // Read key
  383. BodyPair body_pair_key;
  384. if (inStream.IsValidating() && i < all_bp.size())
  385. body_pair_key = all_bp[i]->GetKey();
  386. inStream.Read(body_pair_key);
  387. // Create new entry for this body pair
  388. uint64 body_pair_hash = body_pair_key.GetHash();
  389. BPKeyValue *bp_kv = Create(contact_allocator, body_pair_key, body_pair_hash);
  390. if (bp_kv == nullptr)
  391. {
  392. // Out of cache space
  393. success = false;
  394. break;
  395. }
  396. CachedBodyPair &bp = bp_kv->GetValue();
  397. // Read body pair
  398. if (inStream.IsValidating() && i < all_bp.size())
  399. memcpy(&bp, &all_bp[i]->GetValue(), sizeof(CachedBodyPair));
  400. bp.RestoreState(inStream);
  401. // When validating, get all existing manifolds
  402. Array<const MKeyValue *> all_m;
  403. if (inStream.IsValidating())
  404. inReadCache.GetAllManifoldsSorted(all_bp[i]->GetValue(), all_m);
  405. // Read amount of manifolds
  406. size_t num_manifolds;
  407. if (inStream.IsValidating())
  408. num_manifolds = all_m.size();
  409. inStream.Read(num_manifolds);
  410. uint32 handle = ManifoldMap::cInvalidHandle;
  411. for (size_t j = 0; j < num_manifolds; ++j)
  412. {
  413. // Read key
  414. SubShapeIDPair sub_shape_key;
  415. if (inStream.IsValidating() && j < all_m.size())
  416. sub_shape_key = all_m[j]->GetKey();
  417. inStream.Read(sub_shape_key);
  418. uint64 sub_shape_key_hash = sub_shape_key.GetHash();
  419. // Read amount of contact points
  420. uint16 num_contact_points;
  421. if (inStream.IsValidating() && j < all_m.size())
  422. num_contact_points = all_m[j]->GetValue().mNumContactPoints;
  423. inStream.Read(num_contact_points);
  424. // Read manifold
  425. MKeyValue *m_kv = Create(contact_allocator, sub_shape_key, sub_shape_key_hash, num_contact_points);
  426. if (m_kv == nullptr)
  427. {
  428. // Out of cache space
  429. success = false;
  430. break;
  431. }
  432. CachedManifold &cm = m_kv->GetValue();
  433. if (inStream.IsValidating() && j < all_m.size())
  434. {
  435. memcpy(&cm, &all_m[j]->GetValue(), CachedManifold::sGetRequiredTotalSize(num_contact_points));
  436. cm.mNumContactPoints = uint16(num_contact_points); // Restore num contact points
  437. }
  438. cm.RestoreState(inStream);
  439. cm.mNextWithSameBodyPair = handle;
  440. handle = ToHandle(m_kv);
  441. // Read contact points
  442. for (uint32 k = 0; k < num_contact_points; ++k)
  443. cm.mContactPoints[k].RestoreState(inStream);
  444. }
  445. bp.mFirstCachedManifold = handle;
  446. }
  447. // When validating, get all existing CCD manifolds
  448. Array<const MKeyValue *> all_m;
  449. if (inStream.IsValidating())
  450. inReadCache.GetAllCCDManifoldsSorted(all_m);
  451. // Read amount of CCD manifolds
  452. size_t num_manifolds;
  453. if (inStream.IsValidating())
  454. num_manifolds = all_m.size();
  455. inStream.Read(num_manifolds);
  456. for (size_t j = 0; j < num_manifolds; ++j)
  457. {
  458. // Read key
  459. SubShapeIDPair sub_shape_key;
  460. if (inStream.IsValidating() && j < all_m.size())
  461. sub_shape_key = all_m[j]->GetKey();
  462. inStream.Read(sub_shape_key);
  463. uint64 sub_shape_key_hash = sub_shape_key.GetHash();
  464. // Create CCD manifold
  465. MKeyValue *m_kv = Create(contact_allocator, sub_shape_key, sub_shape_key_hash, 0);
  466. if (m_kv == nullptr)
  467. {
  468. // Out of cache space
  469. success = false;
  470. break;
  471. }
  472. CachedManifold &cm = m_kv->GetValue();
  473. cm.mFlags |= (uint16)CachedManifold::EFlags::CCDContact;
  474. }
  475. #ifdef JPH_ENABLE_ASSERTS
  476. mIsFinalized = true;
  477. #endif
  478. return success;
  479. }
  480. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  481. // ContactConstraintManager
  482. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  483. ContactConstraintManager::ContactConstraintManager(const PhysicsSettings &inPhysicsSettings) :
  484. mPhysicsSettings(inPhysicsSettings)
  485. {
  486. #ifdef JPH_ENABLE_ASSERTS
  487. // For the first frame mark this empty buffer as finalized
  488. mCache[mCacheWriteIdx ^ 1].Finalize();
  489. #endif
  490. }
  491. ContactConstraintManager::~ContactConstraintManager()
  492. {
  493. JPH_ASSERT(mConstraints == nullptr);
  494. }
  495. void ContactConstraintManager::Init(uint inMaxBodyPairs, uint inMaxContactConstraints)
  496. {
  497. mMaxConstraints = inMaxContactConstraints;
  498. // Calculate worst case cache usage
  499. uint cached_manifolds_size = inMaxContactConstraints * (sizeof(CachedManifold) + (MaxContactPoints - 1) * sizeof(CachedContactPoint));
  500. // Init the caches
  501. mCache[0].Init(inMaxBodyPairs, inMaxContactConstraints, cached_manifolds_size);
  502. mCache[1].Init(inMaxBodyPairs, inMaxContactConstraints, cached_manifolds_size);
  503. }
  504. void ContactConstraintManager::PrepareConstraintBuffer(PhysicsUpdateContext *inContext)
  505. {
  506. // Store context
  507. mUpdateContext = inContext;
  508. // Allocate temporary constraint buffer
  509. JPH_ASSERT(mConstraints == nullptr);
  510. mConstraints = (ContactConstraint *)inContext->mTempAllocator->Allocate(mMaxConstraints * sizeof(ContactConstraint));
  511. }
  512. template <EMotionType Type1, EMotionType Type2>
  513. JPH_INLINE void ContactConstraintManager::TemplatedCalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, float inDeltaTime, Mat44Arg inTransformBody1, Mat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2, Mat44Arg inInvI1, Mat44Arg inInvI2)
  514. {
  515. // Calculate tangents
  516. Vec3 t1, t2;
  517. ioConstraint.GetTangents(t1, t2);
  518. // Setup velocity constraint properties
  519. float min_velocity_for_restitution = mPhysicsSettings.mMinVelocityForRestitution;
  520. for (WorldContactPoint &wcp : ioConstraint.mContactPoints)
  521. {
  522. Vec3 p1 = inTransformBody1 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition1);
  523. Vec3 p2 = inTransformBody2 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition2);
  524. wcp.CalculateFrictionAndNonPenetrationConstraintProperties<Type1, Type2>(inDeltaTime, inBody1, inBody2, inInvI1, inInvI2, p1, p2, ioConstraint.mWorldSpaceNormal, t1, t2, ioConstraint.mCombinedRestitution, ioConstraint.mCombinedFriction, min_velocity_for_restitution);
  525. }
  526. }
  527. inline void ContactConstraintManager::CalculateFrictionAndNonPenetrationConstraintProperties(ContactConstraint &ioConstraint, float inDeltaTime, Mat44Arg inTransformBody1, Mat44Arg inTransformBody2, const Body &inBody1, const Body &inBody2)
  528. {
  529. // Dispatch to the correct templated form
  530. switch (inBody1.GetMotionType())
  531. {
  532. case EMotionType::Dynamic:
  533. {
  534. Mat44 invi1 = inBody1.GetInverseInertia();
  535. switch (inBody2.GetMotionType())
  536. {
  537. case EMotionType::Dynamic:
  538. TemplatedCalculateFrictionAndNonPenetrationConstraintProperties<EMotionType::Dynamic, EMotionType::Dynamic>(ioConstraint, inDeltaTime, inTransformBody1, inTransformBody2, inBody1, inBody2, invi1, inBody2.GetInverseInertia());
  539. break;
  540. case EMotionType::Kinematic:
  541. TemplatedCalculateFrictionAndNonPenetrationConstraintProperties<EMotionType::Dynamic, EMotionType::Kinematic>(ioConstraint, inDeltaTime, inTransformBody1, inTransformBody2, inBody1, inBody2, invi1, Mat44() /* Will not be used */);
  542. break;
  543. case EMotionType::Static:
  544. TemplatedCalculateFrictionAndNonPenetrationConstraintProperties<EMotionType::Dynamic, EMotionType::Static>(ioConstraint, inDeltaTime, inTransformBody1, inTransformBody2, inBody1, inBody2, invi1, Mat44() /* Will not be used */);
  545. break;
  546. default:
  547. JPH_ASSERT(false);
  548. break;
  549. }
  550. break;
  551. }
  552. case EMotionType::Kinematic:
  553. JPH_ASSERT(inBody2.IsDynamic());
  554. TemplatedCalculateFrictionAndNonPenetrationConstraintProperties<EMotionType::Kinematic, EMotionType::Dynamic>(ioConstraint, inDeltaTime, inTransformBody1, inTransformBody2, inBody1, inBody2, Mat44() /* Will not be used */, inBody2.GetInverseInertia());
  555. break;
  556. case EMotionType::Static:
  557. JPH_ASSERT(inBody2.IsDynamic());
  558. TemplatedCalculateFrictionAndNonPenetrationConstraintProperties<EMotionType::Static, EMotionType::Dynamic>(ioConstraint, inDeltaTime, inTransformBody1, inTransformBody2, inBody1, inBody2, Mat44() /* Will not be used */, inBody2.GetInverseInertia());
  559. break;
  560. default:
  561. JPH_ASSERT(false);
  562. break;
  563. }
  564. }
  565. void ContactConstraintManager::GetContactsFromCache(ContactAllocator &ioContactAllocator, Body &inBody1, Body &inBody2, bool &outPairHandled, bool &outConstraintCreated)
  566. {
  567. JPH_PROFILE_FUNCTION();
  568. // Start with nothing found and not handled
  569. outConstraintCreated = false;
  570. outPairHandled = false;
  571. // Swap bodies so that body 1 id < body 2 id
  572. Body *body1, *body2;
  573. if (inBody1.GetID() < inBody2.GetID())
  574. {
  575. body1 = &inBody1;
  576. body2 = &inBody2;
  577. }
  578. else
  579. {
  580. body1 = &inBody2;
  581. body2 = &inBody1;
  582. }
  583. // Find the cached body pair
  584. BodyPair body_pair_key(body1->GetID(), body2->GetID());
  585. uint64 body_pair_hash = body_pair_key.GetHash();
  586. const ManifoldCache &read_cache = mCache[mCacheWriteIdx ^ 1];
  587. const BPKeyValue *kv = read_cache.Find(body_pair_key, body_pair_hash);
  588. if (kv == nullptr)
  589. return;
  590. const CachedBodyPair &input_cbp = kv->GetValue();
  591. // Get relative translation
  592. Quat inv_r1 = body1->GetRotation().Conjugated();
  593. Vec3 delta_position = inv_r1 * (body2->GetCenterOfMassPosition() - body1->GetCenterOfMassPosition());
  594. // Get old position delta
  595. Vec3 old_delta_position = Vec3::sLoadFloat3Unsafe(input_cbp.mDeltaPosition);
  596. // Check if bodies are still roughly in the same relative position
  597. if ((delta_position - old_delta_position).LengthSq() > mPhysicsSettings.mBodyPairCacheMaxDeltaPositionSq)
  598. return;
  599. // Determine relative orientation
  600. Quat delta_rotation = inv_r1 * body2->GetRotation();
  601. // Reconstruct old quaternion delta
  602. Quat old_delta_rotation = Quat::sLoadFloat3Unsafe(input_cbp.mDeltaRotation);
  603. // Check if bodies are still roughly in the same relative orientation
  604. // The delta between 2 quaternions p and q is: p q^* = [rotation_axis * sin(angle / 2), cos(angle / 2)]
  605. // From the W component we can extract the angle: cos(angle / 2) = px * qx + py * qy + pz * qz + pw * qw = p . q
  606. // Since we want to abort if the rotation is smaller than -angle or bigger than angle, we can write the comparison as |p . q| < cos(angle / 2)
  607. if (abs(delta_rotation.Dot(old_delta_rotation)) < mPhysicsSettings.mBodyPairCacheCosMaxDeltaRotationDiv2)
  608. return;
  609. // The cache is valid, return that we've handled this body pair
  610. outPairHandled = true;
  611. // Copy the cached body pair to this frame
  612. ManifoldCache &write_cache = mCache[mCacheWriteIdx];
  613. BPKeyValue *output_bp_kv = write_cache.Create(ioContactAllocator, body_pair_key, body_pair_hash);
  614. if (output_bp_kv == nullptr)
  615. return; // Out of cache space
  616. CachedBodyPair *output_cbp = &output_bp_kv->GetValue();
  617. memcpy(output_cbp, &input_cbp, sizeof(CachedBodyPair));
  618. // If there were no contacts, we have handled the contact
  619. if (input_cbp.mFirstCachedManifold == ManifoldMap::cInvalidHandle)
  620. return;
  621. // Get body transforms
  622. Mat44 transform_body1 = body1->GetCenterOfMassTransform();
  623. Mat44 transform_body2 = body2->GetCenterOfMassTransform();
  624. // Get time step
  625. float delta_time = mUpdateContext->mSubStepDeltaTime;
  626. // Copy manifolds
  627. uint32 output_handle = ManifoldMap::cInvalidHandle;
  628. uint32 input_handle = input_cbp.mFirstCachedManifold;
  629. do
  630. {
  631. JPH_PROFILE("Add Constraint From Cached Manifold");
  632. // Find the existing manifold
  633. const MKeyValue *input_kv = read_cache.FromHandle(input_handle);
  634. const SubShapeIDPair &input_key = input_kv->GetKey();
  635. const CachedManifold &input_cm = input_kv->GetValue();
  636. JPH_ASSERT(input_cm.mNumContactPoints > 0); // There should be contact points in this manifold!
  637. // Create room for manifold in write buffer and copy data
  638. uint64 input_hash = input_key.GetHash();
  639. MKeyValue *output_kv = write_cache.Create(ioContactAllocator, input_key, input_hash, input_cm.mNumContactPoints);
  640. if (output_kv == nullptr)
  641. break; // Out of cache space
  642. CachedManifold *output_cm = &output_kv->GetValue();
  643. memcpy(output_cm, &input_cm, CachedManifold::sGetRequiredTotalSize(input_cm.mNumContactPoints));
  644. // Link the object under the body pairs
  645. output_cm->mNextWithSameBodyPair = output_handle;
  646. output_handle = write_cache.ToHandle(output_kv);
  647. // Calculate default contact settings
  648. ContactSettings settings;
  649. settings.mCombinedFriction = mCombineFriction(*body1, input_key.GetSubShapeID1(), *body2, input_key.GetSubShapeID2());
  650. settings.mCombinedRestitution = mCombineRestitution(*body1, input_key.GetSubShapeID1(), *body2, input_key.GetSubShapeID2());
  651. settings.mIsSensor = body1->IsSensor() || body2->IsSensor();
  652. // Calculate world space contact normal
  653. Vec3 world_space_normal = transform_body2.Multiply3x3(Vec3::sLoadFloat3Unsafe(output_cm->mContactNormal)).Normalized();
  654. // Call contact listener to update settings
  655. if (mContactListener != nullptr)
  656. {
  657. // Convert constraint to manifold structure for callback
  658. ContactManifold manifold;
  659. manifold.mWorldSpaceNormal = world_space_normal;
  660. manifold.mSubShapeID1 = input_key.GetSubShapeID1();
  661. manifold.mSubShapeID2 = input_key.GetSubShapeID2();
  662. manifold.mWorldSpaceContactPointsOn1.resize(output_cm->mNumContactPoints);
  663. manifold.mWorldSpaceContactPointsOn2.resize(output_cm->mNumContactPoints);
  664. float penetration_depth = -FLT_MAX;
  665. for (uint32 i = 0; i < output_cm->mNumContactPoints; ++i)
  666. {
  667. const CachedContactPoint &ccp = output_cm->mContactPoints[i];
  668. manifold.mWorldSpaceContactPointsOn1[i] = transform_body1 * Vec3::sLoadFloat3Unsafe(ccp.mPosition1);
  669. manifold.mWorldSpaceContactPointsOn2[i] = transform_body2 * Vec3::sLoadFloat3Unsafe(ccp.mPosition2);
  670. penetration_depth = max(penetration_depth, (manifold.mWorldSpaceContactPointsOn1[0] - manifold.mWorldSpaceContactPointsOn2[0]).Dot(world_space_normal));
  671. }
  672. manifold.mPenetrationDepth = penetration_depth; // We don't have the penetration depth anymore, estimate it
  673. // Notify callback
  674. mContactListener->OnContactPersisted(*body1, *body2, manifold, settings);
  675. }
  676. // If one of the bodies is a sensor, don't actually create the constraint
  677. JPH_ASSERT(settings.mIsSensor || !(body1->IsSensor() || body2->IsSensor()), "Sensors cannot be converted into regular bodies by a contact callback!");
  678. if (!settings.mIsSensor)
  679. {
  680. // Add contact constraint in world space for the solver
  681. uint32 constraint_idx = mNumConstraints++;
  682. if (constraint_idx >= mMaxConstraints)
  683. {
  684. JPH_ASSERT(false, "Out of contact constraints!");
  685. break;
  686. }
  687. // A constraint will be created
  688. outConstraintCreated = true;
  689. ContactConstraint &constraint = mConstraints[constraint_idx];
  690. new (&constraint) ContactConstraint();
  691. constraint.mBody1 = body1;
  692. constraint.mBody2 = body2;
  693. constraint.mSortKey = input_hash;
  694. constraint.mWorldSpaceNormal = world_space_normal;
  695. constraint.mCombinedFriction = settings.mCombinedFriction;
  696. constraint.mCombinedRestitution = settings.mCombinedRestitution;
  697. constraint.mContactPoints.resize(output_cm->mNumContactPoints);
  698. for (uint32 i = 0; i < output_cm->mNumContactPoints; ++i)
  699. {
  700. CachedContactPoint &ccp = output_cm->mContactPoints[i];
  701. WorldContactPoint &wcp = constraint.mContactPoints[i];
  702. wcp.mNonPenetrationConstraint.SetTotalLambda(ccp.mNonPenetrationLambda);
  703. wcp.mFrictionConstraint1.SetTotalLambda(ccp.mFrictionLambda[0]);
  704. wcp.mFrictionConstraint2.SetTotalLambda(ccp.mFrictionLambda[1]);
  705. wcp.mContactPoint = &ccp;
  706. }
  707. JPH_DET_LOG("GetContactsFromCache: id1: " << constraint.mBody1->GetID() << " id2: " << constraint.mBody2->GetID() << " key: " << constraint.mSortKey);
  708. // Calculate friction and non-penetration constraint properties for all contact points
  709. CalculateFrictionAndNonPenetrationConstraintProperties(constraint, delta_time, transform_body1, transform_body2, *body1, *body2);
  710. // Notify island builder
  711. mUpdateContext->mIslandBuilder->LinkContact(constraint_idx, body1->GetIndexInActiveBodiesInternal(), body2->GetIndexInActiveBodiesInternal());
  712. #ifdef JPH_DEBUG_RENDERER
  713. // Draw the manifold
  714. if (sDrawContactManifolds)
  715. constraint.Draw(DebugRenderer::sInstance, Color::sYellow);
  716. #endif // JPH_DEBUG_RENDERER
  717. }
  718. // Mark contact as persisted so that we won't fire OnContactRemoved callbacks
  719. input_cm.mFlags |= (uint16)CachedManifold::EFlags::ContactPersisted;
  720. // Fetch the next manifold
  721. input_handle = input_cm.mNextWithSameBodyPair;
  722. }
  723. while (input_handle != ManifoldMap::cInvalidHandle);
  724. output_cbp->mFirstCachedManifold = output_handle;
  725. }
  726. ContactConstraintManager::BodyPairHandle ContactConstraintManager::AddBodyPair(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2)
  727. {
  728. JPH_PROFILE_FUNCTION();
  729. // Swap bodies so that body 1 id < body 2 id
  730. const Body *body1, *body2;
  731. if (inBody1.GetID() < inBody2.GetID())
  732. {
  733. body1 = &inBody1;
  734. body2 = &inBody2;
  735. }
  736. else
  737. {
  738. body1 = &inBody2;
  739. body2 = &inBody1;
  740. }
  741. // Add an entry
  742. BodyPair body_pair_key(body1->GetID(), body2->GetID());
  743. uint64 body_pair_hash = body_pair_key.GetHash();
  744. BPKeyValue *body_pair_kv = mCache[mCacheWriteIdx].Create(ioContactAllocator, body_pair_key, body_pair_hash);
  745. if (body_pair_kv == nullptr)
  746. return nullptr; // Out of cache space
  747. CachedBodyPair *cbp = &body_pair_kv->GetValue();
  748. cbp->mFirstCachedManifold = ManifoldMap::cInvalidHandle;
  749. // Get relative translation
  750. Quat inv_r1 = body1->GetRotation().Conjugated();
  751. Vec3 delta_position = inv_r1 * (body2->GetCenterOfMassPosition() - body1->GetCenterOfMassPosition());
  752. // Store it
  753. delta_position.StoreFloat3(&cbp->mDeltaPosition);
  754. // Determine relative orientation
  755. Quat delta_rotation = inv_r1 * body2->GetRotation();
  756. // Store it
  757. delta_rotation.StoreFloat3(&cbp->mDeltaRotation);
  758. return cbp;
  759. }
  760. template <EMotionType Type1, EMotionType Type2>
  761. bool ContactConstraintManager::TemplatedAddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold, Mat44Arg inInvI1, Mat44Arg inInvI2)
  762. {
  763. // Calculate hash
  764. SubShapeIDPair key { inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2 };
  765. uint64 key_hash = key.GetHash();
  766. // Determine number of contact points
  767. int num_contact_points = (int)inManifold.mWorldSpaceContactPointsOn1.size();
  768. JPH_ASSERT(num_contact_points <= MaxContactPoints);
  769. JPH_ASSERT(num_contact_points == (int)inManifold.mWorldSpaceContactPointsOn2.size());
  770. // Reserve space for new contact cache entry
  771. // Note that for dynamic vs dynamic we always require the first body to have a lower body id to get a consistent key
  772. // under which to look up the contact
  773. ManifoldCache &write_cache = mCache[mCacheWriteIdx];
  774. MKeyValue *new_manifold_kv = write_cache.Create(ioContactAllocator, key, key_hash, num_contact_points);
  775. if (new_manifold_kv == nullptr)
  776. return false; // Out of cache space
  777. CachedManifold *new_manifold = &new_manifold_kv->GetValue();
  778. // Transform the world space normal to the space of body 2 (this is usually the static body)
  779. Mat44 inverse_transform_body2 = inBody2.GetInverseCenterOfMassTransform();
  780. inverse_transform_body2.Multiply3x3(inManifold.mWorldSpaceNormal).Normalized().StoreFloat3(&new_manifold->mContactNormal);
  781. // Settings object that gets passed to the callback
  782. ContactSettings settings;
  783. settings.mCombinedFriction = mCombineFriction(inBody1, inManifold.mSubShapeID1, inBody2, inManifold.mSubShapeID2);
  784. settings.mCombinedRestitution = mCombineRestitution(inBody1, inManifold.mSubShapeID1, inBody2, inManifold.mSubShapeID2);
  785. settings.mIsSensor = inBody1.IsSensor() || inBody2.IsSensor();
  786. // Get the contact points for the old cache entry
  787. const ManifoldCache &read_cache = mCache[mCacheWriteIdx ^ 1];
  788. const MKeyValue *old_manifold_kv = read_cache.Find(key, key_hash);
  789. const CachedContactPoint *ccp_start;
  790. const CachedContactPoint *ccp_end;
  791. if (old_manifold_kv != nullptr)
  792. {
  793. // Call point persisted listener
  794. if (mContactListener != nullptr)
  795. mContactListener->OnContactPersisted(inBody1, inBody2, inManifold, settings);
  796. // Fetch the contact points from the old manifold
  797. const CachedManifold *old_manifold = &old_manifold_kv->GetValue();
  798. ccp_start = old_manifold->mContactPoints;
  799. ccp_end = ccp_start + old_manifold->mNumContactPoints;
  800. // Mark contact as persisted so that we won't fire OnContactRemoved callbacks
  801. old_manifold->mFlags |= (uint16)CachedManifold::EFlags::ContactPersisted;
  802. }
  803. else
  804. {
  805. // Call point added listener
  806. if (mContactListener != nullptr)
  807. mContactListener->OnContactAdded(inBody1, inBody2, inManifold, settings);
  808. // No contact points available from old manifold
  809. ccp_start = nullptr;
  810. ccp_end = nullptr;
  811. }
  812. // Get inverse transform for body 1
  813. Mat44 inverse_transform_body1 = inBody1.GetInverseCenterOfMassTransform();
  814. bool contact_constraint_created;
  815. // If one of the bodies is a sensor, don't actually create the constraint
  816. JPH_ASSERT(settings.mIsSensor || !(inBody1.IsSensor() || inBody2.IsSensor()), "Sensors cannot be converted into regular bodies by a contact callback!");
  817. if (settings.mIsSensor)
  818. {
  819. // Store the contact manifold in the cache
  820. for (int i = 0; i < num_contact_points; ++i)
  821. {
  822. // Convert to local space to the body
  823. Vec3 p1 = inverse_transform_body1 * inManifold.mWorldSpaceContactPointsOn1[i];
  824. Vec3 p2 = inverse_transform_body2 * inManifold.mWorldSpaceContactPointsOn2[i];
  825. // Create new contact point
  826. CachedContactPoint &cp = new_manifold->mContactPoints[i];
  827. p1.StoreFloat3(&cp.mPosition1);
  828. p2.StoreFloat3(&cp.mPosition2);
  829. // We don't use this, but reset them anyway for determinism check
  830. cp.mNonPenetrationLambda = 0.0f;
  831. cp.mFrictionLambda[0] = 0.0f;
  832. cp.mFrictionLambda[1] = 0.0f;
  833. }
  834. // No constraint created
  835. contact_constraint_created = false;
  836. }
  837. else
  838. {
  839. // Add contact constraint
  840. uint32 constraint_idx = mNumConstraints++;
  841. if (constraint_idx >= mMaxConstraints)
  842. {
  843. JPH_ASSERT(false, "Out of contact constraints!");
  844. // Manifold has been created already, we're not filling it in, so we need to reset the contact number of points.
  845. // Note that we don't hook it up to the body pair cache so that it won't be used as a cache during the next simulation.
  846. new_manifold->mNumContactPoints = 0;
  847. return false;
  848. }
  849. // We will create a contact constraint
  850. contact_constraint_created = true;
  851. ContactConstraint &constraint = mConstraints[constraint_idx];
  852. new (&constraint) ContactConstraint();
  853. constraint.mWorldSpaceNormal = inManifold.mWorldSpaceNormal;
  854. constraint.mBody1 = &inBody1;
  855. constraint.mBody2 = &inBody2;
  856. constraint.mSortKey = key_hash;
  857. constraint.mCombinedFriction = settings.mCombinedFriction;
  858. constraint.mCombinedRestitution = settings.mCombinedRestitution;
  859. JPH_DET_LOG("TemplatedAddContactConstraint: id1: " << constraint.mBody1->GetID() << " id2: " << constraint.mBody2->GetID() << " key: " << constraint.mSortKey);
  860. // Notify island builder
  861. mUpdateContext->mIslandBuilder->LinkContact(constraint_idx, inBody1.GetIndexInActiveBodiesInternal(), inBody2.GetIndexInActiveBodiesInternal());
  862. // Get time step
  863. float delta_time = mUpdateContext->mSubStepDeltaTime;
  864. // Calculate tangents
  865. Vec3 t1, t2;
  866. constraint.GetTangents(t1, t2);
  867. constraint.mContactPoints.resize(num_contact_points);
  868. for (int i = 0; i < num_contact_points; ++i)
  869. {
  870. // Convert to world space and set positions
  871. WorldContactPoint &wcp = constraint.mContactPoints[i];
  872. Vec3 p1_ws = inManifold.mWorldSpaceContactPointsOn1[i];
  873. Vec3 p2_ws = inManifold.mWorldSpaceContactPointsOn2[i];
  874. // Convert to local space to the body
  875. Vec3 p1_ls = inverse_transform_body1 * p1_ws;
  876. Vec3 p2_ls = inverse_transform_body2 * p2_ws;
  877. // Check if we have a close contact point from last update
  878. bool lambda_set = false;
  879. for (const CachedContactPoint *ccp = ccp_start; ccp < ccp_end; ccp++)
  880. if (Vec3::sLoadFloat3Unsafe(ccp->mPosition1).IsClose(p1_ls, mPhysicsSettings.mContactPointPreserveLambdaMaxDistSq)
  881. && Vec3::sLoadFloat3Unsafe(ccp->mPosition2).IsClose(p2_ls, mPhysicsSettings.mContactPointPreserveLambdaMaxDistSq))
  882. {
  883. // Get lambdas from previous frame
  884. wcp.mNonPenetrationConstraint.SetTotalLambda(ccp->mNonPenetrationLambda);
  885. wcp.mFrictionConstraint1.SetTotalLambda(ccp->mFrictionLambda[0]);
  886. wcp.mFrictionConstraint2.SetTotalLambda(ccp->mFrictionLambda[1]);
  887. lambda_set = true;
  888. break;
  889. }
  890. if (!lambda_set)
  891. {
  892. wcp.mNonPenetrationConstraint.SetTotalLambda(0.0f);
  893. wcp.mFrictionConstraint1.SetTotalLambda(0.0f);
  894. wcp.mFrictionConstraint2.SetTotalLambda(0.0f);
  895. }
  896. // Create new contact point
  897. CachedContactPoint &cp = new_manifold->mContactPoints[i];
  898. p1_ls.StoreFloat3(&cp.mPosition1);
  899. p2_ls.StoreFloat3(&cp.mPosition2);
  900. wcp.mContactPoint = &cp;
  901. // Setup velocity constraint
  902. wcp.CalculateFrictionAndNonPenetrationConstraintProperties<Type1, Type2>(delta_time, inBody1, inBody2, inInvI1, inInvI2, p1_ws, p2_ws, inManifold.mWorldSpaceNormal, t1, t2, settings.mCombinedRestitution, settings.mCombinedFriction, mPhysicsSettings.mMinVelocityForRestitution);
  903. }
  904. #ifdef JPH_DEBUG_RENDERER
  905. // Draw the manifold
  906. if (sDrawContactManifolds)
  907. constraint.Draw(DebugRenderer::sInstance, Color::sOrange);
  908. #endif // JPH_DEBUG_RENDERER
  909. }
  910. // Store cached contact point in body pair cache
  911. CachedBodyPair *cbp = reinterpret_cast<CachedBodyPair *>(inBodyPairHandle);
  912. new_manifold->mNextWithSameBodyPair = cbp->mFirstCachedManifold;
  913. cbp->mFirstCachedManifold = write_cache.ToHandle(new_manifold_kv);
  914. // A contact constraint was added
  915. return contact_constraint_created;
  916. }
  917. bool ContactConstraintManager::AddContactConstraint(ContactAllocator &ioContactAllocator, BodyPairHandle inBodyPairHandle, Body &inBody1, Body &inBody2, const ContactManifold &inManifold)
  918. {
  919. JPH_PROFILE_FUNCTION();
  920. JPH_DET_LOG("AddContactConstraint: id1: " << inBody1.GetID() << " id2: " << inBody2.GetID()
  921. << " subshape1: " << inManifold.mSubShapeID1 << " subshape2: " << inManifold.mSubShapeID2
  922. << " normal: " << inManifold.mWorldSpaceNormal << " pendepth: " << inManifold.mPenetrationDepth);
  923. JPH_ASSERT(inManifold.mWorldSpaceNormal.IsNormalized());
  924. // Swap bodies so that body 1 id < body 2 id
  925. const ContactManifold *manifold;
  926. Body *body1, *body2;
  927. ContactManifold temp;
  928. if (inBody2.GetID() < inBody1.GetID())
  929. {
  930. body1 = &inBody2;
  931. body2 = &inBody1;
  932. temp = inManifold.SwapShapes();
  933. manifold = &temp;
  934. }
  935. else
  936. {
  937. body1 = &inBody1;
  938. body2 = &inBody2;
  939. manifold = &inManifold;
  940. }
  941. // Dispatch to the correct templated form
  942. // Note: Non-dynamic vs non-dynamic can happen in this case due to one body being a sensor, so we need to have an extended switch case here
  943. switch (body1->GetMotionType())
  944. {
  945. case EMotionType::Dynamic:
  946. {
  947. Mat44 invi1 = body1->GetInverseInertia();
  948. switch (body2->GetMotionType())
  949. {
  950. case EMotionType::Dynamic:
  951. return TemplatedAddContactConstraint<EMotionType::Dynamic, EMotionType::Dynamic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, invi1, body2->GetInverseInertia());
  952. case EMotionType::Kinematic:
  953. return TemplatedAddContactConstraint<EMotionType::Dynamic, EMotionType::Kinematic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, invi1, Mat44() /* Will not be used */);
  954. case EMotionType::Static:
  955. return TemplatedAddContactConstraint<EMotionType::Dynamic, EMotionType::Static>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, invi1, Mat44() /* Will not be used */);
  956. default:
  957. JPH_ASSERT(false);
  958. break;
  959. }
  960. break;
  961. }
  962. case EMotionType::Kinematic:
  963. switch (body2->GetMotionType())
  964. {
  965. case EMotionType::Dynamic:
  966. return TemplatedAddContactConstraint<EMotionType::Kinematic, EMotionType::Dynamic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, Mat44() /* Will not be used */, body2->GetInverseInertia());
  967. case EMotionType::Kinematic:
  968. return TemplatedAddContactConstraint<EMotionType::Kinematic, EMotionType::Kinematic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, Mat44() /* Will not be used */, Mat44() /* Will not be used */);
  969. case EMotionType::Static:
  970. return TemplatedAddContactConstraint<EMotionType::Kinematic, EMotionType::Static>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, Mat44() /* Will not be used */, Mat44() /* Will not be used */);
  971. default:
  972. JPH_ASSERT(false);
  973. break;
  974. }
  975. break;
  976. case EMotionType::Static:
  977. switch (body2->GetMotionType())
  978. {
  979. case EMotionType::Dynamic:
  980. return TemplatedAddContactConstraint<EMotionType::Static, EMotionType::Dynamic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, Mat44() /* Will not be used */, body2->GetInverseInertia());
  981. case EMotionType::Kinematic:
  982. return TemplatedAddContactConstraint<EMotionType::Static, EMotionType::Kinematic>(ioContactAllocator, inBodyPairHandle, *body1, *body2, *manifold, Mat44() /* Will not be used */, Mat44() /* Will not be used */);
  983. case EMotionType::Static: // Static vs static not possible
  984. default:
  985. JPH_ASSERT(false);
  986. break;
  987. }
  988. break;
  989. default:
  990. JPH_ASSERT(false);
  991. break;
  992. }
  993. return false;
  994. }
  995. void ContactConstraintManager::OnCCDContactAdded(ContactAllocator &ioContactAllocator, const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &outSettings)
  996. {
  997. JPH_ASSERT(inManifold.mWorldSpaceNormal.IsNormalized());
  998. // Calculate contact settings
  999. outSettings.mCombinedFriction = mCombineFriction(inBody1, inManifold.mSubShapeID1, inBody2, inManifold.mSubShapeID2);
  1000. outSettings.mCombinedRestitution = mCombineRestitution(inBody1, inManifold.mSubShapeID1, inBody2, inManifold.mSubShapeID2);
  1001. outSettings.mIsSensor = false; // For now, no sensors are supported during CCD
  1002. // The remainder of this function only deals with calling contact callbacks, if there's no contact callback we also don't need to do this work
  1003. if (mContactListener != nullptr)
  1004. {
  1005. // Swap bodies so that body 1 id < body 2 id
  1006. const ContactManifold *manifold;
  1007. const Body *body1, *body2;
  1008. ContactManifold temp;
  1009. if (inBody2.GetID() < inBody1.GetID())
  1010. {
  1011. body1 = &inBody2;
  1012. body2 = &inBody1;
  1013. temp = inManifold.SwapShapes();
  1014. manifold = &temp;
  1015. }
  1016. else
  1017. {
  1018. body1 = &inBody1;
  1019. body2 = &inBody2;
  1020. manifold = &inManifold;
  1021. }
  1022. // Calculate hash
  1023. SubShapeIDPair key { body1->GetID(), manifold->mSubShapeID1, body2->GetID(), manifold->mSubShapeID2 };
  1024. uint64 key_hash = key.GetHash();
  1025. // Check if we already created this contact this physics update
  1026. ManifoldCache &write_cache = mCache[mCacheWriteIdx];
  1027. MKVAndCreated new_manifold_kv = write_cache.FindOrCreate(ioContactAllocator, key, key_hash, 0);
  1028. if (new_manifold_kv.second)
  1029. {
  1030. // This contact is new for this physics update, check if previous update we already had this contact.
  1031. const ManifoldCache &read_cache = mCache[mCacheWriteIdx ^ 1];
  1032. const MKeyValue *old_manifold_kv = read_cache.Find(key, key_hash);
  1033. if (old_manifold_kv == nullptr)
  1034. {
  1035. // New contact
  1036. mContactListener->OnContactAdded(*body1, *body2, *manifold, outSettings);
  1037. }
  1038. else
  1039. {
  1040. // Existing contact
  1041. mContactListener->OnContactPersisted(*body1, *body2, *manifold, outSettings);
  1042. // Mark contact as persisted so that we won't fire OnContactRemoved callbacks
  1043. old_manifold_kv->GetValue().mFlags |= (uint16)CachedManifold::EFlags::ContactPersisted;
  1044. }
  1045. // Check if the cache is full
  1046. if (new_manifold_kv.first != nullptr)
  1047. {
  1048. // We don't store any contact points in this manifold as it is not for caching impulses, we only need to know that the contact was created
  1049. CachedManifold &new_manifold = new_manifold_kv.first->GetValue();
  1050. new_manifold.mContactNormal = { 0, 0, 0 };
  1051. new_manifold.mFlags |= (uint16)CachedManifold::EFlags::CCDContact;
  1052. }
  1053. }
  1054. else
  1055. {
  1056. // Already found this contact this physics update.
  1057. // Note that we can trigger OnContactPersisted multiple times per physics update, but otherwise we have no way of obtaining the settings
  1058. mContactListener->OnContactPersisted(*body1, *body2, *manifold, outSettings);
  1059. }
  1060. }
  1061. JPH_ASSERT(!outSettings.mIsSensor, "CCD bodies cannot currently act as sensors");
  1062. }
  1063. void ContactConstraintManager::SortContacts(uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd) const
  1064. {
  1065. JPH_PROFILE_FUNCTION();
  1066. QuickSort(inConstraintIdxBegin, inConstraintIdxEnd, [this](uint32 inLHS, uint32 inRHS) {
  1067. const ContactConstraint &lhs = mConstraints[inLHS];
  1068. const ContactConstraint &rhs = mConstraints[inRHS];
  1069. // Most of the time the sort key will be different so we sort on that
  1070. if (lhs.mSortKey != rhs.mSortKey)
  1071. return lhs.mSortKey < rhs.mSortKey;
  1072. // If they're equal we use the IDs of body 1 to order
  1073. if (lhs.mBody1 != rhs.mBody1)
  1074. return lhs.mBody1->GetID() < rhs.mBody1->GetID();
  1075. // If they're still equal we use the IDs of body 2 to order
  1076. if (lhs.mBody2 != rhs.mBody2)
  1077. return lhs.mBody2->GetID() < rhs.mBody2->GetID();
  1078. JPH_ASSERT(inLHS == inRHS, "Hash collision, ordering will be inconsistent");
  1079. return false;
  1080. });
  1081. }
  1082. void ContactConstraintManager::FinalizeContactCache(uint inExpectedNumBodyPairs, uint inExpectedNumManifolds)
  1083. {
  1084. JPH_PROFILE_FUNCTION();
  1085. #ifdef JPH_ENABLE_ASSERTS
  1086. // Mark cache as finalized
  1087. ManifoldCache &old_write_cache = mCache[mCacheWriteIdx];
  1088. old_write_cache.Finalize();
  1089. // Check that the count of body pairs and manifolds that we tracked outside of the cache (to avoid contention on an atomic) is correct
  1090. JPH_ASSERT(old_write_cache.GetNumBodyPairs() == inExpectedNumBodyPairs);
  1091. JPH_ASSERT(old_write_cache.GetNumManifolds() == inExpectedNumManifolds);
  1092. #endif
  1093. // Buffers are now complete, make write buffer the read buffer
  1094. mCacheWriteIdx ^= 1;
  1095. // Use the amount of contacts from the last iteration to determine the amount of buckets to use in the hash map for the next iteration
  1096. mCache[mCacheWriteIdx].Prepare(inExpectedNumBodyPairs, inExpectedNumManifolds);
  1097. }
  1098. void ContactConstraintManager::ContactPointRemovedCallbacks()
  1099. {
  1100. JPH_PROFILE_FUNCTION();
  1101. // Get the read cache
  1102. ManifoldCache &read_cache = mCache[mCacheWriteIdx ^ 1];
  1103. // Call the actual callbacks
  1104. if (mContactListener != nullptr)
  1105. read_cache.ContactPointRemovedCallbacks(mContactListener);
  1106. // We're done with the cache now
  1107. read_cache.Clear();
  1108. }
  1109. void ContactConstraintManager::SetupVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime)
  1110. {
  1111. JPH_PROFILE_FUNCTION();
  1112. for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
  1113. {
  1114. ContactConstraint &constraint = mConstraints[*constraint_idx];
  1115. // Fetch bodies
  1116. const Body &body1 = *constraint.mBody1;
  1117. const Body &body2 = *constraint.mBody2;
  1118. // Get body transforms
  1119. Mat44 transform_body1 = body1.GetCenterOfMassTransform();
  1120. Mat44 transform_body2 = body2.GetCenterOfMassTransform();
  1121. // Calculate friction and non-penetration constraint properties for all contact points
  1122. CalculateFrictionAndNonPenetrationConstraintProperties(constraint, inDeltaTime, transform_body1, transform_body2, body1, body2);
  1123. }
  1124. }
  1125. template <EMotionType Type1, EMotionType Type2>
  1126. JPH_INLINE void ContactConstraintManager::sWarmStartConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2, float inWarmStartImpulseRatio)
  1127. {
  1128. // Calculate tangents
  1129. Vec3 t1, t2;
  1130. ioConstraint.GetTangents(t1, t2);
  1131. for (WorldContactPoint &wcp : ioConstraint.mContactPoints)
  1132. {
  1133. // Warm starting: Apply impulse from last frame
  1134. if (wcp.mFrictionConstraint1.IsActive())
  1135. {
  1136. JPH_ASSERT(wcp.mFrictionConstraint2.IsActive());
  1137. wcp.mFrictionConstraint1.TemplatedWarmStart<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, t1, inWarmStartImpulseRatio);
  1138. wcp.mFrictionConstraint2.TemplatedWarmStart<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, t2, inWarmStartImpulseRatio);
  1139. }
  1140. wcp.mNonPenetrationConstraint.TemplatedWarmStart<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, ioConstraint.mWorldSpaceNormal, inWarmStartImpulseRatio);
  1141. }
  1142. }
  1143. void ContactConstraintManager::WarmStartVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio)
  1144. {
  1145. JPH_PROFILE_FUNCTION();
  1146. for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
  1147. {
  1148. ContactConstraint &constraint = mConstraints[*constraint_idx];
  1149. // Fetch bodies
  1150. Body &body1 = *constraint.mBody1;
  1151. EMotionType motion_type1 = body1.GetMotionType();
  1152. MotionProperties *motion_properties1 = body1.GetMotionPropertiesUnchecked();
  1153. Body &body2 = *constraint.mBody2;
  1154. EMotionType motion_type2 = body2.GetMotionType();
  1155. MotionProperties *motion_properties2 = body2.GetMotionPropertiesUnchecked();
  1156. // Dispatch to the correct templated form
  1157. // Note: Warm starting doesn't differentiate between kinematic/static bodies so we handle both as static bodies
  1158. if (motion_type1 == EMotionType::Dynamic)
  1159. {
  1160. if (motion_type2 == EMotionType::Dynamic)
  1161. sWarmStartConstraint<EMotionType::Dynamic, EMotionType::Dynamic>(constraint, motion_properties1, motion_properties2, inWarmStartImpulseRatio);
  1162. else
  1163. sWarmStartConstraint<EMotionType::Dynamic, EMotionType::Static>(constraint, motion_properties1, motion_properties2, inWarmStartImpulseRatio);
  1164. }
  1165. else
  1166. {
  1167. JPH_ASSERT(motion_type2 == EMotionType::Dynamic);
  1168. sWarmStartConstraint<EMotionType::Static, EMotionType::Dynamic>(constraint, motion_properties1, motion_properties2, inWarmStartImpulseRatio);
  1169. }
  1170. }
  1171. }
  1172. template <EMotionType Type1, EMotionType Type2>
  1173. JPH_INLINE bool ContactConstraintManager::sSolveVelocityConstraint(ContactConstraint &ioConstraint, MotionProperties *ioMotionProperties1, MotionProperties *ioMotionProperties2)
  1174. {
  1175. bool any_impulse_applied = false;
  1176. // Calculate tangents
  1177. Vec3 t1, t2;
  1178. ioConstraint.GetTangents(t1, t2);
  1179. // First apply all friction constraints (non-penetration is more important than friction)
  1180. for (WorldContactPoint &wcp : ioConstraint.mContactPoints)
  1181. {
  1182. // Check if friction is enabled
  1183. if (wcp.mFrictionConstraint1.IsActive())
  1184. {
  1185. JPH_ASSERT(wcp.mFrictionConstraint2.IsActive());
  1186. // Calculate max impulse that can be applied. Note that we're using the non-penetration impulse from the previous iteration here.
  1187. // We do this because non-penetration is more important so is solved last (the last things that are solved in an iterative solver
  1188. // contribute the most).
  1189. float max_lambda_f = ioConstraint.mCombinedFriction * wcp.mNonPenetrationConstraint.GetTotalLambda();
  1190. // Solve friction velocities
  1191. // Note that what we're doing is not fully correct since the max force we can apply is 2 * max_lambda_f instead of max_lambda_f since we're solving axis independently
  1192. if (wcp.mFrictionConstraint1.TemplatedSolveVelocityConstraint<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, t1, -max_lambda_f, max_lambda_f))
  1193. any_impulse_applied = true;
  1194. if (wcp.mFrictionConstraint2.TemplatedSolveVelocityConstraint<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, t2, -max_lambda_f, max_lambda_f))
  1195. any_impulse_applied = true;
  1196. }
  1197. }
  1198. // Then apply all non-penetration constraints
  1199. for (WorldContactPoint &wcp : ioConstraint.mContactPoints)
  1200. {
  1201. // Solve non penetration velocities
  1202. if (wcp.mNonPenetrationConstraint.TemplatedSolveVelocityConstraint<Type1, Type2>(ioMotionProperties1, ioMotionProperties2, ioConstraint.mWorldSpaceNormal, 0.0f, FLT_MAX))
  1203. any_impulse_applied = true;
  1204. }
  1205. return any_impulse_applied;
  1206. }
  1207. bool ContactConstraintManager::SolveVelocityConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
  1208. {
  1209. JPH_PROFILE_FUNCTION();
  1210. bool any_impulse_applied = false;
  1211. for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
  1212. {
  1213. ContactConstraint &constraint = mConstraints[*constraint_idx];
  1214. // Fetch bodies
  1215. Body &body1 = *constraint.mBody1;
  1216. EMotionType motion_type1 = body1.GetMotionType();
  1217. MotionProperties *motion_properties1 = body1.GetMotionPropertiesUnchecked();
  1218. Body &body2 = *constraint.mBody2;
  1219. EMotionType motion_type2 = body2.GetMotionType();
  1220. MotionProperties *motion_properties2 = body2.GetMotionPropertiesUnchecked();
  1221. // Dispatch to the correct templated form
  1222. switch (motion_type1)
  1223. {
  1224. case EMotionType::Dynamic:
  1225. switch (motion_type2)
  1226. {
  1227. case EMotionType::Dynamic:
  1228. any_impulse_applied |= sSolveVelocityConstraint<EMotionType::Dynamic, EMotionType::Dynamic>(constraint, motion_properties1, motion_properties2);
  1229. break;
  1230. case EMotionType::Kinematic:
  1231. any_impulse_applied |= sSolveVelocityConstraint<EMotionType::Dynamic, EMotionType::Kinematic>(constraint, motion_properties1, motion_properties2);
  1232. break;
  1233. case EMotionType::Static:
  1234. any_impulse_applied |= sSolveVelocityConstraint<EMotionType::Dynamic, EMotionType::Static>(constraint, motion_properties1, motion_properties2);
  1235. break;
  1236. default:
  1237. JPH_ASSERT(false);
  1238. break;
  1239. }
  1240. break;
  1241. case EMotionType::Kinematic:
  1242. JPH_ASSERT(motion_type2 == EMotionType::Dynamic);
  1243. any_impulse_applied |= sSolveVelocityConstraint<EMotionType::Kinematic, EMotionType::Dynamic>(constraint, motion_properties1, motion_properties2);
  1244. break;
  1245. case EMotionType::Static:
  1246. JPH_ASSERT(motion_type2 == EMotionType::Dynamic);
  1247. any_impulse_applied |= sSolveVelocityConstraint<EMotionType::Static, EMotionType::Dynamic>(constraint, motion_properties1, motion_properties2);
  1248. break;
  1249. default:
  1250. JPH_ASSERT(false);
  1251. break;
  1252. }
  1253. }
  1254. return any_impulse_applied;
  1255. }
  1256. void ContactConstraintManager::StoreAppliedImpulses(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd) const
  1257. {
  1258. // Copy back total applied impulse to cache for the next frame
  1259. for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
  1260. {
  1261. const ContactConstraint &constraint = mConstraints[*constraint_idx];
  1262. for (const WorldContactPoint &wcp : constraint.mContactPoints)
  1263. {
  1264. wcp.mContactPoint->mNonPenetrationLambda = wcp.mNonPenetrationConstraint.GetTotalLambda();
  1265. wcp.mContactPoint->mFrictionLambda[0] = wcp.mFrictionConstraint1.GetTotalLambda();
  1266. wcp.mContactPoint->mFrictionLambda[1] = wcp.mFrictionConstraint2.GetTotalLambda();
  1267. }
  1268. }
  1269. }
  1270. bool ContactConstraintManager::SolvePositionConstraints(const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd)
  1271. {
  1272. JPH_PROFILE_FUNCTION();
  1273. bool any_impulse_applied = false;
  1274. float delta_time = mUpdateContext->mSubStepDeltaTime;
  1275. for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
  1276. {
  1277. ContactConstraint &constraint = mConstraints[*constraint_idx];
  1278. // Fetch bodies
  1279. Body &body1 = *constraint.mBody1;
  1280. Body &body2 = *constraint.mBody2;
  1281. // Get transforms
  1282. Mat44 transform1 = body1.GetCenterOfMassTransform();
  1283. Mat44 transform2 = body2.GetCenterOfMassTransform();
  1284. for (WorldContactPoint &wcp : constraint.mContactPoints)
  1285. {
  1286. // Calculate new contact point positions in world space (the bodies may have moved)
  1287. Vec3 p1 = transform1 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition1);
  1288. Vec3 p2 = transform2 * Vec3::sLoadFloat3Unsafe(wcp.mContactPoint->mPosition2);
  1289. // Calculate separation along the normal (negative if interpenetrating)
  1290. // Allow a little penetration by default (PhysicsSettings::mPenetrationSlop) to avoid jittering between contact/no-contact which wipes out the contact cache and warm start impulses
  1291. // Clamp penetration to a max PhysicsSettings::mMaxPenetrationDistance so that we don't apply a huge impulse if we're penetrating a lot
  1292. float separation = max((p2 - p1).Dot(constraint.mWorldSpaceNormal) + mPhysicsSettings.mPenetrationSlop, -mPhysicsSettings.mMaxPenetrationDistance);
  1293. // Only enforce constraint when separation < 0 (otherwise we're apart)
  1294. if (separation < 0.0f)
  1295. {
  1296. // Update constraint properties (bodies may have moved)
  1297. wcp.CalculateNonPenetrationConstraintProperties(delta_time, body1, body2, p1, p2, constraint.mWorldSpaceNormal);
  1298. // Solve position errors
  1299. if (wcp.mNonPenetrationConstraint.SolvePositionConstraint(body1, body2, constraint.mWorldSpaceNormal, separation, mPhysicsSettings.mBaumgarte))
  1300. any_impulse_applied = true;
  1301. }
  1302. }
  1303. }
  1304. return any_impulse_applied;
  1305. }
  1306. void ContactConstraintManager::RecycleConstraintBuffer()
  1307. {
  1308. // Reset constraint array
  1309. mNumConstraints = 0;
  1310. }
  1311. void ContactConstraintManager::FinishConstraintBuffer()
  1312. {
  1313. // Free constraints buffer
  1314. mUpdateContext->mTempAllocator->Free(mConstraints, mMaxConstraints * sizeof(ContactConstraint));
  1315. mConstraints = nullptr;
  1316. mNumConstraints = 0;
  1317. // Reset update context
  1318. mUpdateContext = nullptr;
  1319. }
  1320. void ContactConstraintManager::SaveState(StateRecorder &inStream) const
  1321. {
  1322. mCache[mCacheWriteIdx ^ 1].SaveState(inStream);
  1323. }
  1324. bool ContactConstraintManager::RestoreState(StateRecorder &inStream)
  1325. {
  1326. bool success = mCache[mCacheWriteIdx].RestoreState(mCache[mCacheWriteIdx ^ 1], inStream);
  1327. mCacheWriteIdx ^= 1;
  1328. mCache[mCacheWriteIdx].Clear();
  1329. return success;
  1330. }
  1331. JPH_NAMESPACE_END