ContactConstraintManager.cpp 71 KB

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