ContactConstraintManager.cpp 65 KB

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