ContactConstraintManager.cpp 53 KB

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