ContactConstraintManager.cpp 58 KB

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