ContactConstraintManager.cpp 62 KB

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