ContactConstraintManager.cpp 60 KB

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