ContactConstraintManager.cpp 67 KB

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