BodyManager.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt.h>
  4. #include <Physics/PhysicsSettings.h>
  5. #include <Physics/Body/BodyManager.h>
  6. #include <Physics/Body/BodyCreationSettings.h>
  7. #include <Physics/Body/BodyLock.h>
  8. #include <Physics/Body/BodyActivationListener.h>
  9. #include <Physics/StateRecorder.h>
  10. #include <Core/StringTools.h>
  11. #include <Core/StatCollector.h>
  12. #ifdef JPH_DEBUG_RENDERER
  13. #include <Renderer/DebugRenderer.h>
  14. #endif // JPH_DEBUG_RENDERER
  15. namespace JPH {
  16. #ifdef JPH_ENABLE_ASSERTS
  17. thread_local bool BodyManager::sOverrideAllowActivation = false;
  18. thread_local bool BodyManager::sOverrideAllowDeactivation = false;
  19. #endif
  20. BodyManager::~BodyManager()
  21. {
  22. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  23. // Destroy any bodies that are still alive
  24. for (Body *b : mBodies)
  25. if (sIsValidBodyPointer(b))
  26. delete b;
  27. delete [] mActiveBodies;
  28. }
  29. void BodyManager::Init(uint inMaxBodies)
  30. {
  31. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  32. // Allocate space for bodies
  33. mBodies.reserve(inMaxBodies);
  34. // Allocate space for active bodies
  35. JPH_ASSERT(mActiveBodies == nullptr);
  36. mActiveBodies = new BodyID [inMaxBodies];
  37. // Allocate space for sequence numbers
  38. mBodySequenceNumbers.resize(inMaxBodies);
  39. }
  40. uint BodyManager::GetNumBodies() const
  41. {
  42. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  43. return mNumBodies;
  44. }
  45. BodyManager::BodyStats BodyManager::GetBodyStats() const
  46. {
  47. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  48. BodyStats stats;
  49. stats.mNumBodies = mNumBodies;
  50. stats.mMaxBodies = uint(mBodies.capacity());
  51. for (const Body *body : mBodies)
  52. if (sIsValidBodyPointer(body))
  53. {
  54. switch (body->GetMotionType())
  55. {
  56. case EMotionType::Static:
  57. stats.mNumBodiesStatic++;
  58. break;
  59. case EMotionType::Dynamic:
  60. stats.mNumBodiesDynamic++;
  61. if (body->IsActive())
  62. stats.mNumActiveBodiesDynamic++;
  63. break;
  64. case EMotionType::Kinematic:
  65. stats.mNumBodiesKinematic++;
  66. if (body->IsActive())
  67. stats.mNumActiveBodiesKinematic++;
  68. break;
  69. }
  70. }
  71. return stats;
  72. }
  73. Body *BodyManager::CreateBody(const BodyCreationSettings &inBodyCreationSettings)
  74. {
  75. // Determine next free index
  76. uint32 idx;
  77. {
  78. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  79. if (mBodyIDFreeListStart != cBodyIDFreeListEnd)
  80. {
  81. // Pop an item from the freelist
  82. JPH_ASSERT(mBodyIDFreeListStart & cIsFreedBody);
  83. idx = uint32(mBodyIDFreeListStart >> cFreedBodyIndexShift);
  84. JPH_ASSERT(!sIsValidBodyPointer(mBodies[idx]));
  85. mBodyIDFreeListStart = uintptr_t(mBodies[idx]);
  86. }
  87. else
  88. {
  89. if (mBodies.size() < mBodies.capacity())
  90. {
  91. // Allocate a new entry, note that the array should not actually resize since we've reserved it at init time
  92. idx = uint32(mBodies.size());
  93. mBodies.push_back((Body *)cBodyIDFreeListEnd);
  94. }
  95. else
  96. {
  97. // Out of bodies
  98. return nullptr;
  99. }
  100. }
  101. // Update cached number of bodies
  102. mNumBodies++;
  103. }
  104. // Get next sequence number
  105. uint8 seq_no = GetNextSequenceNumber(idx);
  106. // Fill in basic properties
  107. Body *body = new Body();
  108. body->mID = BodyID(idx, seq_no);
  109. body->mShape = inBodyCreationSettings.GetShape();
  110. body->SetFriction(inBodyCreationSettings.mFriction);
  111. body->SetRestitution(inBodyCreationSettings.mRestitution);
  112. body->mMotionType = inBodyCreationSettings.mMotionType;
  113. if (inBodyCreationSettings.mIsSensor)
  114. body->mFlags |= uint8(Body::EFlags::IsSensor);
  115. body->mObjectLayer = inBodyCreationSettings.mObjectLayer;
  116. body->mCollisionGroup = inBodyCreationSettings.mCollisionGroup;
  117. if (inBodyCreationSettings.HasMassProperties())
  118. {
  119. MotionProperties *mp = new MotionProperties();
  120. mp->SetLinearDamping(inBodyCreationSettings.mLinearDamping);
  121. mp->SetAngularDamping(inBodyCreationSettings.mAngularDamping);
  122. mp->SetMaxLinearVelocity(inBodyCreationSettings.mMaxLinearVelocity);
  123. mp->SetMaxAngularVelocity(inBodyCreationSettings.mMaxAngularVelocity);
  124. mp->SetGravityFactor(inBodyCreationSettings.mGravityFactor);
  125. mp->SetMotionQuality(inBodyCreationSettings.mMotionQuality);
  126. mp->mAllowSleeping = inBodyCreationSettings.mAllowSleeping;
  127. mp->mIndexInActiveBodies = Body::cInactiveIndex;
  128. mp->mIslandIndex = Body::cInactiveIndex;
  129. JPH_IF_ENABLE_ASSERTS(mp->mCachedMotionType = body->mMotionType;)
  130. mp->SetMassProperties(inBodyCreationSettings.GetMassProperties());
  131. body->mMotionProperties = mp;
  132. }
  133. // Position body
  134. body->SetPositionAndRotationInternal(inBodyCreationSettings.mPosition, inBodyCreationSettings.mRotation);
  135. // Add body
  136. mBodies[idx] = body;
  137. return body;
  138. }
  139. void BodyManager::DestroyBodies(const BodyID *inBodyIDs, int inNumber)
  140. {
  141. // Don't take lock if no bodies are to be destroyed
  142. if (inNumber <= 0)
  143. return;
  144. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  145. // Update cached number of bodies
  146. JPH_ASSERT(mNumBodies >= (uint)inNumber);
  147. mNumBodies -= inNumber;
  148. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  149. {
  150. // Get body
  151. BodyID body_id = *b;
  152. uint32 idx = body_id.GetIndex();
  153. Body *body = mBodies[idx];
  154. // Validate that it can be removed
  155. JPH_ASSERT(body->GetID() == body_id);
  156. JPH_ASSERT(!body->IsActive());
  157. JPH_ASSERT(!body->IsInBroadPhase());
  158. // Push the id onto the freelist
  159. mBodies[idx] = (Body *)mBodyIDFreeListStart;
  160. mBodyIDFreeListStart = (uintptr_t(idx) << cFreedBodyIndexShift) | cIsFreedBody;
  161. // Free the body
  162. delete body;
  163. }
  164. #if defined(_DEBUG) && defined(JPH_ENABLE_ASSERTS)
  165. // Check that the freelist is correct
  166. size_t num_freed = 0;
  167. for (uintptr_t start = mBodyIDFreeListStart; start != cBodyIDFreeListEnd; start = uintptr_t(mBodies[start >> cFreedBodyIndexShift]))
  168. {
  169. JPH_ASSERT(start & cIsFreedBody);
  170. num_freed++;
  171. }
  172. JPH_ASSERT(mNumBodies == mBodies.size() - num_freed);
  173. #endif // defined(_DEBUG) && _defined(JPH_ENABLE_ASSERTS)
  174. }
  175. void BodyManager::ActivateBodies(const BodyID *inBodyIDs, int inNumber)
  176. {
  177. // Don't take lock if no bodies are to be activated
  178. if (inNumber <= 0)
  179. return;
  180. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  181. JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowActivation);
  182. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  183. {
  184. BodyID body_id = *b;
  185. Body &body = *mBodies[body_id.GetIndex()];
  186. JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
  187. JPH_ASSERT(body.GetID() == body_id);
  188. JPH_ASSERT(body.IsInBroadPhase());
  189. if (!body.IsStatic()
  190. && body.mMotionProperties->mIndexInActiveBodies == Body::cInactiveIndex)
  191. {
  192. body.mMotionProperties->mIndexInActiveBodies = mNumActiveBodies;
  193. body.ResetSleepTestSpheres();
  194. JPH_ASSERT(mNumActiveBodies < GetMaxBodies());
  195. mActiveBodies[mNumActiveBodies] = body_id;
  196. mNumActiveBodies++; // Increment atomic after setting the body ID so that PhysicsSystem::JobFindCollisions (which doesn't lock the mActiveBodiesMutex) will only read valid IDs
  197. // Count CCD bodies
  198. if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
  199. mNumActiveCCDBodies++;
  200. // Call activation listener
  201. if (mActivationListener != nullptr)
  202. mActivationListener->OnBodyActivated(body_id, body.GetUserData());
  203. }
  204. }
  205. }
  206. void BodyManager::DeactivateBodies(const BodyID *inBodyIDs, int inNumber)
  207. {
  208. // Don't take lock if no bodies are to be deactivated
  209. if (inNumber <= 0)
  210. return;
  211. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  212. JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowDeactivation);
  213. for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
  214. {
  215. BodyID body_id = *b;
  216. Body &body = *mBodies[body_id.GetIndex()];
  217. JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
  218. JPH_ASSERT(body.GetID() == body_id);
  219. JPH_ASSERT(body.IsInBroadPhase());
  220. if (body.mMotionProperties != nullptr
  221. && body.mMotionProperties->mIndexInActiveBodies != Body::cInactiveIndex)
  222. {
  223. uint32 last_body_index = mNumActiveBodies - 1;
  224. if (body.mMotionProperties->mIndexInActiveBodies != last_body_index)
  225. {
  226. // This is not the last body, use the last body to fill the hole
  227. BodyID last_body_id = mActiveBodies[last_body_index];
  228. mActiveBodies[body.mMotionProperties->mIndexInActiveBodies] = last_body_id;
  229. // Update that body's index in the active list
  230. Body &last_body = *mBodies[last_body_id.GetIndex()];
  231. JPH_ASSERT(last_body.mMotionProperties->mIndexInActiveBodies == last_body_index);
  232. last_body.mMotionProperties->mIndexInActiveBodies = body.mMotionProperties->mIndexInActiveBodies;
  233. }
  234. // Mark this body as no longer active
  235. body.mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
  236. body.mMotionProperties->mIslandIndex = Body::cInactiveIndex;
  237. // Reset velocity
  238. body.mMotionProperties->mLinearVelocity = Vec3::sZero();
  239. body.mMotionProperties->mAngularVelocity = Vec3::sZero();
  240. // Remove unused element from active bodies list
  241. --mNumActiveBodies;
  242. // Count CCD bodies
  243. if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
  244. mNumActiveCCDBodies--;
  245. // Call activation listener
  246. if (mActivationListener != nullptr)
  247. mActivationListener->OnBodyDeactivated(body_id, body.GetUserData());
  248. }
  249. }
  250. }
  251. void BodyManager::GetActiveBodies(BodyIDVector &outBodyIDs) const
  252. {
  253. JPH_PROFILE_FUNCTION();
  254. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  255. outBodyIDs.assign(mActiveBodies, mActiveBodies + mNumActiveBodies);
  256. }
  257. void BodyManager::GetBodyIDs(BodyIDVector &outBodies) const
  258. {
  259. JPH_PROFILE_FUNCTION();
  260. UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  261. // Reserve space for all bodies
  262. outBodies.clear();
  263. outBodies.reserve(mNumBodies);
  264. // Iterate the list and find the bodies that are not null
  265. for (const Body *b : mBodies)
  266. if (sIsValidBodyPointer(b))
  267. outBodies.push_back(b->GetID());
  268. // Validate that our reservation was correct
  269. JPH_ASSERT(outBodies.size() == mNumBodies);
  270. }
  271. void BodyManager::SetBodyActivationListener(BodyActivationListener *inListener)
  272. {
  273. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  274. mActivationListener = inListener;
  275. }
  276. BodyManager::MutexMask BodyManager::GetMutexMask(const BodyID *inBodies, int inNumber) const
  277. {
  278. static_assert(sizeof(MutexMask) * 8 == BodyMutexes::NumMutexes, "MutexMask must have the same amount of bits");
  279. if (inNumber >= BodyMutexes::NumMutexes)
  280. {
  281. // Just lock everything if there are too many bodies
  282. return ~MutexMask(0);
  283. }
  284. else
  285. {
  286. MutexMask mask = 0;
  287. for (const BodyID *b = inBodies, *b_end = inBodies + inNumber; b < b_end; ++b)
  288. if (!b->IsInvalid())
  289. {
  290. uint32 index = mBodyMutexes.GetMutexIndex(b->GetIndex());
  291. mask |= (MutexMask(1) << index);
  292. }
  293. return mask;
  294. }
  295. }
  296. void BodyManager::LockRead(MutexMask inMutexMask) const
  297. {
  298. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  299. int index = 0;
  300. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  301. if (mask & 1)
  302. mBodyMutexes.GetMutexByIndex(index).lock_shared();
  303. }
  304. void BodyManager::UnlockRead(MutexMask inMutexMask) const
  305. {
  306. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  307. int index = 0;
  308. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  309. if (mask & 1)
  310. mBodyMutexes.GetMutexByIndex(index).unlock_shared();
  311. }
  312. void BodyManager::LockWrite(MutexMask inMutexMask) const
  313. {
  314. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  315. int index = 0;
  316. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  317. if (mask & 1)
  318. mBodyMutexes.GetMutexByIndex(index).lock();
  319. }
  320. void BodyManager::UnlockWrite(MutexMask inMutexMask) const
  321. {
  322. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  323. int index = 0;
  324. for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
  325. if (mask & 1)
  326. mBodyMutexes.GetMutexByIndex(index).unlock();
  327. }
  328. void BodyManager::LockAllBodies() const
  329. {
  330. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
  331. mBodyMutexes.LockAll();
  332. PhysicsLock::sLock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  333. }
  334. void BodyManager::UnlockAllBodies() const
  335. {
  336. PhysicsLock::sUnlock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
  337. JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
  338. mBodyMutexes.UnlockAll();
  339. }
  340. void BodyManager::SaveState(StateRecorder &inStream) const
  341. {
  342. {
  343. LockAllBodies();
  344. // Count number of bodies
  345. size_t num_bodies = 0;
  346. for (const Body *b : mBodies)
  347. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  348. ++num_bodies;
  349. inStream.Write(num_bodies);
  350. // Write state of bodies
  351. for (const Body *b : mBodies)
  352. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  353. {
  354. inStream.Write(b->GetID());
  355. b->SaveState(inStream);
  356. }
  357. UnlockAllBodies();
  358. }
  359. {
  360. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  361. // Write active bodies, sort because activation can come from multiple threads, so order is not deterministic
  362. inStream.Write(mNumActiveBodies);
  363. BodyIDVector sorted_active_bodies(mActiveBodies, mActiveBodies + mNumActiveBodies);
  364. sort(sorted_active_bodies.begin(), sorted_active_bodies.end());
  365. for (const BodyID &id : sorted_active_bodies)
  366. inStream.Write(id);
  367. inStream.Write(mNumActiveCCDBodies);
  368. }
  369. }
  370. bool BodyManager::RestoreState(StateRecorder &inStream)
  371. {
  372. {
  373. LockAllBodies();
  374. // Read state of bodies, note this reads it in a way to be consistent with validation
  375. size_t old_num_bodies = 0;
  376. for (const Body *b : mBodies)
  377. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  378. ++old_num_bodies;
  379. size_t num_bodies = old_num_bodies; // Initialize to current value for validation
  380. inStream.Read(num_bodies);
  381. if (num_bodies != old_num_bodies)
  382. {
  383. JPH_ASSERT(false, "Cannot handle adding/removing bodies");
  384. UnlockAllBodies();
  385. return false;
  386. }
  387. for (Body *b : mBodies)
  388. if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
  389. {
  390. BodyID body_id = b->GetID(); // Initialize to current value for validation
  391. inStream.Read(body_id);
  392. if (body_id != b->GetID())
  393. {
  394. JPH_ASSERT(false, "Cannot handle adding/removing bodies");
  395. UnlockAllBodies();
  396. return false;
  397. }
  398. b->RestoreState(inStream);
  399. }
  400. UnlockAllBodies();
  401. }
  402. {
  403. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  404. // Mark current active bodies as deactivated
  405. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  406. mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
  407. sort(mActiveBodies, mActiveBodies + mNumActiveBodies); // Sort for validation
  408. // Read active bodies
  409. inStream.Read(mNumActiveBodies);
  410. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  411. {
  412. inStream.Read(*id);
  413. mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = uint32(id - mActiveBodies);
  414. }
  415. inStream.Read(mNumActiveCCDBodies);
  416. }
  417. return true;
  418. }
  419. #ifdef JPH_DEBUG_RENDERER
  420. void BodyManager::Draw(const DrawSettings &inDrawSettings, const PhysicsSettings &inPhysicsSettings, DebugRenderer *inRenderer)
  421. {
  422. JPH_PROFILE_FUNCTION();
  423. LockAllBodies();
  424. for (const Body *body : mBodies)
  425. if (sIsValidBodyPointer(body) && body->IsInBroadPhase())
  426. {
  427. JPH_ASSERT(mBodies[body->GetID().GetIndex()] == body);
  428. bool is_sensor = body->IsSensor();
  429. // Determine drawing mode
  430. Color color;
  431. if (is_sensor)
  432. color = Color::sYellow;
  433. else
  434. switch (inDrawSettings.mDrawShapeColor)
  435. {
  436. case EShapeColor::InstanceColor:
  437. // Each instance has own color
  438. color = Color::sGetDistinctColor(body->mID.GetIndex());
  439. break;
  440. case EShapeColor::ShapeTypeColor:
  441. // Each shape type has own color
  442. switch (body->GetShape()->GetType())
  443. {
  444. case EShapeType::Convex:
  445. color = Color::sGreen;
  446. break;
  447. case EShapeType::Scaled:
  448. color = Color::sYellow;
  449. break;
  450. case EShapeType::StaticCompound:
  451. color = Color::sOrange;
  452. break;
  453. case EShapeType::MutableCompound:
  454. color = Color::sDarkOrange;
  455. break;
  456. case EShapeType::Mesh:
  457. color = Color::sRed;
  458. break;
  459. case EShapeType::HeightField:
  460. color = Color::sPurple;
  461. break;
  462. case EShapeType::RotatedTranslated:
  463. color = Color::sBlue;
  464. break;
  465. case EShapeType::OffsetCenterOfMass:
  466. color = Color::sCyan;
  467. break;
  468. default:
  469. JPH_ASSERT(false);
  470. color = Color::sBlack;
  471. break;
  472. }
  473. break;
  474. case EShapeColor::MotionTypeColor:
  475. // Determine color based on motion type
  476. switch (body->mMotionType)
  477. {
  478. case EMotionType::Static:
  479. color = Color::sGrey;
  480. break;
  481. case EMotionType::Kinematic:
  482. color = Color::sGreen;
  483. break;
  484. case EMotionType::Dynamic:
  485. color = Color::sGetDistinctColor(body->mID.GetIndex());
  486. break;
  487. default:
  488. JPH_ASSERT(false);
  489. color = Color::sBlack;
  490. break;
  491. }
  492. break;
  493. case EShapeColor::SleepColor:
  494. // Determine color based on motion type
  495. switch (body->mMotionType)
  496. {
  497. case EMotionType::Static:
  498. color = Color::sGrey;
  499. break;
  500. case EMotionType::Kinematic:
  501. color = body->IsActive()? Color::sGreen : Color::sRed;
  502. break;
  503. case EMotionType::Dynamic:
  504. color = body->IsActive()? Color::sYellow : Color::sRed;
  505. break;
  506. default:
  507. JPH_ASSERT(false);
  508. color = Color::sBlack;
  509. break;
  510. }
  511. break;
  512. case EShapeColor::IslandColor:
  513. // Determine color based on motion type
  514. switch (body->mMotionType)
  515. {
  516. case EMotionType::Static:
  517. color = Color::sGrey;
  518. break;
  519. case EMotionType::Kinematic:
  520. case EMotionType::Dynamic:
  521. {
  522. uint32 idx = body->GetMotionProperties()->GetIslandIndexInternal();
  523. color = idx != Body::cInactiveIndex? Color::sGetDistinctColor(idx) : Color::sLightGrey;
  524. }
  525. break;
  526. default:
  527. JPH_ASSERT(false);
  528. color = Color::sBlack;
  529. break;
  530. }
  531. break;
  532. case EShapeColor::MaterialColor:
  533. color = Color::sWhite;
  534. break;
  535. default:
  536. JPH_ASSERT(false);
  537. color = Color::sBlack;
  538. break;
  539. }
  540. // Draw the results of GetSupportFunction
  541. if (inDrawSettings.mDrawGetSupportFunction)
  542. body->mShape->DrawGetSupportFunction(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawSupportDirection);
  543. // Draw the results of GetSupportingFace
  544. if (inDrawSettings.mDrawGetSupportingFace)
  545. body->mShape->DrawGetSupportingFace(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
  546. // Draw the shape
  547. if (inDrawSettings.mDrawShape)
  548. body->mShape->Draw(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawShapeColor == EShapeColor::MaterialColor, inDrawSettings.mDrawShapeWireframe || is_sensor);
  549. // Draw bounding box
  550. if (inDrawSettings.mDrawBoundingBox)
  551. inRenderer->DrawWireBox(body->mBounds, color);
  552. // Draw center of mass transform
  553. if (inDrawSettings.mDrawCenterOfMassTransform)
  554. inRenderer->DrawCoordinateSystem(body->GetCenterOfMassTransform(), 0.2f);
  555. // Draw world transform
  556. if (inDrawSettings.mDrawWorldTransform)
  557. inRenderer->DrawCoordinateSystem(body->GetWorldTransform(), 0.2f);
  558. // Draw world space linear and angular velocity
  559. if (inDrawSettings.mDrawVelocity)
  560. {
  561. Vec3 pos = body->GetCenterOfMassPosition();
  562. inRenderer->DrawArrow(pos, pos + body->GetLinearVelocity(), Color::sGreen, 0.1f);
  563. inRenderer->DrawArrow(pos, pos + body->GetAngularVelocity(), Color::sRed, 0.1f);
  564. }
  565. if (inDrawSettings.mDrawMassAndInertia && body->IsDynamic())
  566. {
  567. const MotionProperties *mp = body->GetMotionProperties();
  568. // Invert mass again
  569. float mass = 1.0f / mp->GetInverseMass();
  570. // Invert diagonal again
  571. Vec3 diagonal = mp->GetInverseInertiaDiagonal().Reciprocal();
  572. // Determine how big of a box has the equivalent inertia
  573. Vec3 box_size = MassProperties::sGetEquivalentSolidBoxSize(mass, diagonal);
  574. // Draw box with equivalent inertia
  575. inRenderer->DrawWireBox(body->GetCenterOfMassTransform() * Mat44::sRotation(mp->GetInertiaRotation()), AABox(-0.5f * box_size, 0.5f * box_size), Color::sOrange);
  576. // Draw mass
  577. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), StringFormat("%.2f", (double)mass), Color::sOrange, 0.2f);
  578. }
  579. if (inDrawSettings.mDrawSleepStats && body->IsDynamic() && body->IsActive())
  580. {
  581. // Draw stats to know which bodies could go to sleep
  582. string text = StringFormat("t: %.1f", (double)body->mMotionProperties->mSleepTestTimer);
  583. uint8 g = uint8(Clamp(255.0f * body->mMotionProperties->mSleepTestTimer / inPhysicsSettings.mTimeBeforeSleep, 0.0f, 255.0f));
  584. Color sleep_color = Color(0, 255 - g, g);
  585. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), text, sleep_color, 0.2f);
  586. for (int i = 0; i < 3; ++i)
  587. inRenderer->DrawWireSphere(body->mMotionProperties->mSleepTestSpheres[i].GetCenter(), body->mMotionProperties->mSleepTestSpheres[i].GetRadius(), sleep_color);
  588. }
  589. if (inDrawSettings.mDrawNames)
  590. inRenderer->DrawText3D(body->GetCenterOfMassPosition(), body->GetDebugName(), Color::sCyan, 0.2f);
  591. }
  592. UnlockAllBodies();
  593. }
  594. #endif // JPH_DEBUG_RENDERER
  595. void BodyManager::InvalidateContactCacheForBody(Body &ioBody)
  596. {
  597. lock_guard lock(mBodiesCacheInvalidMutex);
  598. if (!ioBody.IsCollisionCacheInvalid())
  599. {
  600. mBodiesCacheInvalid.push_back(ioBody.GetID());
  601. ioBody.InvalidateCollisionCacheInternal(true);
  602. }
  603. }
  604. void BodyManager::ValidateContactCacheForAllBodies()
  605. {
  606. lock_guard lock(mBodiesCacheInvalidMutex);
  607. for (const BodyID &b : mBodiesCacheInvalid)
  608. {
  609. // The body may have been removed between the call to InvalidateContactCacheForBody and this call, so check if it still exists
  610. Body *body = TryGetBody(b);
  611. if (body != nullptr)
  612. body->InvalidateCollisionCacheInternal(false);
  613. }
  614. mBodiesCacheInvalid.clear();
  615. }
  616. #ifdef JPH_STAT_COLLECTOR
  617. void BodyManager::CollectStats() const
  618. {
  619. JPH_PROFILE_FUNCTION();
  620. BodyLockInterfaceLocking lock_interface(const_cast<BodyManager &>(*this));
  621. BodyIDVector active_body_ids;
  622. GetActiveBodies(active_body_ids);
  623. for (const BodyID &id : active_body_ids)
  624. {
  625. BodyLockRead body_lock(lock_interface, id);
  626. if (body_lock.SucceededAndIsInBroadPhase())
  627. {
  628. const Body &body = body_lock.GetBody();
  629. string prefix = "Body." + body.GetDebugName();
  630. JPH_STAT_COLLECTOR_ADD(prefix + ".Position", body.GetPosition());
  631. JPH_STAT_COLLECTOR_ADD(prefix + ".Rotation", body.GetRotation());
  632. JPH_STAT_COLLECTOR_ADD(prefix + ".LinearVelocity", body.GetLinearVelocity());
  633. JPH_STAT_COLLECTOR_ADD(prefix + ".LinearVelocity.Length", body.GetLinearVelocity().Length());
  634. JPH_STAT_COLLECTOR_ADD(prefix + ".AngularVelocity", body.GetAngularVelocity());
  635. JPH_STAT_COLLECTOR_ADD(prefix + ".AngularVelocity.Length", body.GetAngularVelocity().Length());
  636. }
  637. }
  638. }
  639. #endif // JPH_STAT_COLLECTOR
  640. #ifdef _DEBUG
  641. void BodyManager::ValidateActiveBodyBounds()
  642. {
  643. UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
  644. for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
  645. {
  646. const Body *body = mBodies[id->GetIndex()];
  647. AABox cached = body->GetWorldSpaceBounds();
  648. AABox calculated = body->GetShape()->GetWorldSpaceBounds(body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
  649. JPH_ASSERT(cached == calculated);
  650. }
  651. }
  652. #endif // _DEBUG
  653. } // JPH