ContactConstraintManager.cpp 70 KB

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