PhysicsSystem.cpp 103 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413
  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/PhysicsSystem.h>
  6. #include <Jolt/Physics/PhysicsSettings.h>
  7. #include <Jolt/Physics/PhysicsUpdateContext.h>
  8. #include <Jolt/Physics/PhysicsStepListener.h>
  9. #include <Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h>
  10. #include <Jolt/Physics/Collision/BroadPhase/BroadPhaseQuadTree.h>
  11. #include <Jolt/Physics/Collision/CollisionDispatch.h>
  12. #include <Jolt/Physics/Collision/AABoxCast.h>
  13. #include <Jolt/Physics/Collision/ShapeCast.h>
  14. #include <Jolt/Physics/Collision/CollideShape.h>
  15. #include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
  16. #include <Jolt/Physics/Collision/CastResult.h>
  17. #include <Jolt/Physics/Collision/CollideConvexVsTriangles.h>
  18. #include <Jolt/Physics/Collision/ManifoldBetweenTwoFaces.h>
  19. #include <Jolt/Physics/Collision/Shape/ConvexShape.h>
  20. #include <Jolt/Physics/Constraints/ConstraintPart/AxisConstraintPart.h>
  21. #include <Jolt/Physics/DeterminismLog.h>
  22. #include <Jolt/Physics/SoftBody/SoftBodyMotionProperties.h>
  23. #include <Jolt/Geometry/RayAABox.h>
  24. #include <Jolt/Core/JobSystem.h>
  25. #include <Jolt/Core/TempAllocator.h>
  26. #include <Jolt/Core/QuickSort.h>
  27. #ifdef JPH_DEBUG_RENDERER
  28. #include <Jolt/Renderer/DebugRenderer.h>
  29. #endif // JPH_DEBUG_RENDERER
  30. JPH_NAMESPACE_BEGIN
  31. #ifdef JPH_DEBUG_RENDERER
  32. bool PhysicsSystem::sDrawMotionQualityLinearCast = false;
  33. #endif // JPH_DEBUG_RENDERER
  34. //#define BROAD_PHASE BroadPhaseBruteForce
  35. #define BROAD_PHASE BroadPhaseQuadTree
  36. static const Color cColorUpdateBroadPhaseFinalize = Color::sGetDistinctColor(1);
  37. static const Color cColorUpdateBroadPhasePrepare = Color::sGetDistinctColor(2);
  38. static const Color cColorFindCollisions = Color::sGetDistinctColor(3);
  39. static const Color cColorApplyGravity = Color::sGetDistinctColor(4);
  40. static const Color cColorSetupVelocityConstraints = Color::sGetDistinctColor(5);
  41. static const Color cColorBuildIslandsFromConstraints = Color::sGetDistinctColor(6);
  42. static const Color cColorDetermineActiveConstraints = Color::sGetDistinctColor(7);
  43. static const Color cColorFinalizeIslands = Color::sGetDistinctColor(8);
  44. static const Color cColorContactRemovedCallbacks = Color::sGetDistinctColor(9);
  45. static const Color cColorBodySetIslandIndex = Color::sGetDistinctColor(10);
  46. static const Color cColorStartNextStep = Color::sGetDistinctColor(11);
  47. static const Color cColorSolveVelocityConstraints = Color::sGetDistinctColor(12);
  48. static const Color cColorPreIntegrateVelocity = Color::sGetDistinctColor(13);
  49. static const Color cColorIntegrateVelocity = Color::sGetDistinctColor(14);
  50. static const Color cColorPostIntegrateVelocity = Color::sGetDistinctColor(15);
  51. static const Color cColorResolveCCDContacts = Color::sGetDistinctColor(16);
  52. static const Color cColorSolvePositionConstraints = Color::sGetDistinctColor(17);
  53. static const Color cColorFindCCDContacts = Color::sGetDistinctColor(18);
  54. static const Color cColorStepListeners = Color::sGetDistinctColor(19);
  55. static const Color cColorUpdateSoftBodies = Color::sGetDistinctColor(20);
  56. PhysicsSystem::~PhysicsSystem()
  57. {
  58. // Remove broadphase
  59. delete mBroadPhase;
  60. }
  61. void PhysicsSystem::Init(uint inMaxBodies, uint inNumBodyMutexes, uint inMaxBodyPairs, uint inMaxContactConstraints, const BroadPhaseLayerInterface &inBroadPhaseLayerInterface, const ObjectVsBroadPhaseLayerFilter &inObjectVsBroadPhaseLayerFilter, const ObjectLayerPairFilter &inObjectLayerPairFilter)
  62. {
  63. mObjectVsBroadPhaseLayerFilter = &inObjectVsBroadPhaseLayerFilter;
  64. mObjectLayerPairFilter = &inObjectLayerPairFilter;
  65. // Initialize body manager
  66. mBodyManager.Init(inMaxBodies, inNumBodyMutexes, inBroadPhaseLayerInterface);
  67. // Create broadphase
  68. mBroadPhase = new BROAD_PHASE();
  69. mBroadPhase->Init(&mBodyManager, inBroadPhaseLayerInterface);
  70. // Init contact constraint manager
  71. mContactManager.Init(inMaxBodyPairs, inMaxContactConstraints);
  72. // Init islands builder
  73. mIslandBuilder.Init(inMaxBodies);
  74. // Initialize body interface
  75. mBodyInterfaceLocking.Init(mBodyLockInterfaceLocking, mBodyManager, *mBroadPhase);
  76. mBodyInterfaceNoLock.Init(mBodyLockInterfaceNoLock, mBodyManager, *mBroadPhase);
  77. // Initialize narrow phase query
  78. mNarrowPhaseQueryLocking.Init(mBodyLockInterfaceLocking, *mBroadPhase);
  79. mNarrowPhaseQueryNoLock.Init(mBodyLockInterfaceNoLock, *mBroadPhase);
  80. }
  81. void PhysicsSystem::OptimizeBroadPhase()
  82. {
  83. mBroadPhase->Optimize();
  84. }
  85. void PhysicsSystem::AddStepListener(PhysicsStepListener *inListener)
  86. {
  87. lock_guard lock(mStepListenersMutex);
  88. JPH_ASSERT(find(mStepListeners.begin(), mStepListeners.end(), inListener) == mStepListeners.end());
  89. mStepListeners.push_back(inListener);
  90. }
  91. void PhysicsSystem::RemoveStepListener(PhysicsStepListener *inListener)
  92. {
  93. lock_guard lock(mStepListenersMutex);
  94. StepListeners::iterator i = find(mStepListeners.begin(), mStepListeners.end(), inListener);
  95. JPH_ASSERT(i != mStepListeners.end());
  96. *i = mStepListeners.back();
  97. mStepListeners.pop_back();
  98. }
  99. EPhysicsUpdateError PhysicsSystem::Update(float inDeltaTime, int inCollisionSteps, TempAllocator *inTempAllocator, JobSystem *inJobSystem)
  100. {
  101. JPH_PROFILE_FUNCTION();
  102. JPH_DET_LOG("PhysicsSystem::Update: dt: " << inDeltaTime << " steps: " << inCollisionSteps);
  103. JPH_ASSERT(inCollisionSteps > 0);
  104. JPH_ASSERT(inDeltaTime >= 0.0f);
  105. // Sync point for the broadphase. This will allow it to do clean up operations without having any mutexes locked yet.
  106. mBroadPhase->FrameSync();
  107. // If there are no active bodies or there's no time delta
  108. uint32 num_active_rigid_bodies = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  109. uint32 num_active_soft_bodies = mBodyManager.GetNumActiveBodies(EBodyType::SoftBody);
  110. if ((num_active_rigid_bodies == 0 && num_active_soft_bodies == 0) || inDeltaTime <= 0.0f)
  111. {
  112. mBodyManager.LockAllBodies();
  113. // Update broadphase
  114. mBroadPhase->LockModifications();
  115. BroadPhase::UpdateState update_state = mBroadPhase->UpdatePrepare();
  116. mBroadPhase->UpdateFinalize(update_state);
  117. mBroadPhase->UnlockModifications();
  118. // Call contact removal callbacks from contacts that existed in the previous update
  119. mContactManager.FinalizeContactCacheAndCallContactPointRemovedCallbacks(0, 0);
  120. mBodyManager.UnlockAllBodies();
  121. return EPhysicsUpdateError::None;
  122. }
  123. // Calculate ratio between current and previous frame delta time to scale initial constraint forces
  124. float step_delta_time = inDeltaTime / inCollisionSteps;
  125. float warm_start_impulse_ratio = mPhysicsSettings.mConstraintWarmStart && mPreviousStepDeltaTime > 0.0f? step_delta_time / mPreviousStepDeltaTime : 0.0f;
  126. mPreviousStepDeltaTime = step_delta_time;
  127. // Create the context used for passing information between jobs
  128. PhysicsUpdateContext context(*inTempAllocator);
  129. context.mPhysicsSystem = this;
  130. context.mJobSystem = inJobSystem;
  131. context.mBarrier = inJobSystem->CreateBarrier();
  132. context.mIslandBuilder = &mIslandBuilder;
  133. context.mStepDeltaTime = step_delta_time;
  134. context.mWarmStartImpulseRatio = warm_start_impulse_ratio;
  135. context.mSteps.resize(inCollisionSteps);
  136. // Allocate space for body pairs
  137. JPH_ASSERT(context.mBodyPairs == nullptr);
  138. context.mBodyPairs = static_cast<BodyPair *>(inTempAllocator->Allocate(sizeof(BodyPair) * mPhysicsSettings.mMaxInFlightBodyPairs));
  139. // Lock all bodies for write so that we can freely touch them
  140. mStepListenersMutex.lock();
  141. mBodyManager.LockAllBodies();
  142. mBroadPhase->LockModifications();
  143. // Get max number of concurrent jobs
  144. int max_concurrency = context.GetMaxConcurrency();
  145. // Calculate how many step listener jobs we spawn
  146. int num_step_listener_jobs = mStepListeners.empty()? 0 : max(1, min((int)mStepListeners.size() / mPhysicsSettings.mStepListenersBatchSize / mPhysicsSettings.mStepListenerBatchesPerJob, max_concurrency));
  147. // Number of gravity jobs depends on the amount of active bodies.
  148. // Launch max 1 job per batch of active bodies
  149. // Leave 1 thread for update broadphase prepare and 1 for determine active constraints
  150. int num_apply_gravity_jobs = max(1, min(((int)num_active_rigid_bodies + cApplyGravityBatchSize - 1) / cApplyGravityBatchSize, max_concurrency - 2));
  151. // Number of determine active constraints jobs to run depends on number of constraints.
  152. // Leave 1 thread for update broadphase prepare and 1 for apply gravity
  153. int num_determine_active_constraints_jobs = max(1, min(((int)mConstraintManager.GetNumConstraints() + cDetermineActiveConstraintsBatchSize - 1) / cDetermineActiveConstraintsBatchSize, max_concurrency - 2));
  154. // Number of find collisions jobs to run depends on number of active bodies.
  155. // Note that when we have more than 1 thread, we always spawn at least 2 find collisions jobs so that the first job can wait for build islands from constraints
  156. // (which may activate additional bodies that need to be processed) while the second job can start processing collision work.
  157. int num_find_collisions_jobs = max(max_concurrency == 1? 1 : 2, min(((int)num_active_rigid_bodies + cActiveBodiesBatchSize - 1) / cActiveBodiesBatchSize, max_concurrency));
  158. // Number of integrate velocity jobs depends on number of active bodies.
  159. int num_integrate_velocity_jobs = max(1, min(((int)num_active_rigid_bodies + cIntegrateVelocityBatchSize - 1) / cIntegrateVelocityBatchSize, max_concurrency));
  160. {
  161. JPH_PROFILE("Build Jobs");
  162. // Iterate over collision steps
  163. for (int step_idx = 0; step_idx < inCollisionSteps; ++step_idx)
  164. {
  165. bool is_first_step = step_idx == 0;
  166. bool is_last_step = step_idx == inCollisionSteps - 1;
  167. PhysicsUpdateContext::Step &step = context.mSteps[step_idx];
  168. step.mContext = &context;
  169. step.mIsFirst = is_first_step;
  170. step.mIsLast = is_last_step;
  171. // Create job to do broadphase finalization
  172. // This job must finish before integrating velocities. Until then the positions will not be updated neither will bodies be added / removed.
  173. step.mUpdateBroadphaseFinalize = inJobSystem->CreateJob("UpdateBroadPhaseFinalize", cColorUpdateBroadPhaseFinalize, [&context, &step]()
  174. {
  175. // Validate that all find collision jobs have stopped
  176. JPH_ASSERT(step.mActiveFindCollisionJobs == 0);
  177. // Finalize the broadphase update
  178. context.mPhysicsSystem->mBroadPhase->UpdateFinalize(step.mBroadPhaseUpdateState);
  179. // Signal that it is done
  180. step.mPreIntegrateVelocity.RemoveDependency();
  181. }, num_find_collisions_jobs + 2); // depends on: find collisions, broadphase prepare update, finish building jobs
  182. // The immediate jobs below are only immediate for the first step, the all finished job will kick them for the next step
  183. int previous_step_dependency_count = is_first_step? 0 : 1;
  184. // Start job immediately: Start the prepare broadphase
  185. // Must be done under body lock protection since the order is body locks then broadphase mutex
  186. // If this is turned around the RemoveBody call will hang since it locks in that order
  187. step.mBroadPhasePrepare = inJobSystem->CreateJob("UpdateBroadPhasePrepare", cColorUpdateBroadPhasePrepare, [&context, &step]()
  188. {
  189. // Prepare the broadphase update
  190. step.mBroadPhaseUpdateState = context.mPhysicsSystem->mBroadPhase->UpdatePrepare();
  191. // Now the finalize can run (if other dependencies are met too)
  192. step.mUpdateBroadphaseFinalize.RemoveDependency();
  193. }, previous_step_dependency_count);
  194. // This job will find all collisions
  195. step.mBodyPairQueues.resize(max_concurrency);
  196. step.mMaxBodyPairsPerQueue = mPhysicsSettings.mMaxInFlightBodyPairs / max_concurrency;
  197. step.mActiveFindCollisionJobs = ~PhysicsUpdateContext::JobMask(0) >> (sizeof(PhysicsUpdateContext::JobMask) * 8 - num_find_collisions_jobs);
  198. step.mFindCollisions.resize(num_find_collisions_jobs);
  199. for (int i = 0; i < num_find_collisions_jobs; ++i)
  200. {
  201. // Build islands from constraints may activate additional bodies, so the first job will wait for this to finish in order to not miss any active bodies
  202. int num_dep_build_islands_from_constraints = i == 0? 1 : 0;
  203. step.mFindCollisions[i] = inJobSystem->CreateJob("FindCollisions", cColorFindCollisions, [&step, i]()
  204. {
  205. step.mContext->mPhysicsSystem->JobFindCollisions(&step, i);
  206. }, num_apply_gravity_jobs + num_determine_active_constraints_jobs + 1 + num_dep_build_islands_from_constraints); // depends on: apply gravity, determine active constraints, finish building jobs, build islands from constraints
  207. }
  208. if (is_first_step)
  209. {
  210. #ifdef JPH_ENABLE_ASSERTS
  211. // Don't allow write operations to the active bodies list
  212. mBodyManager.SetActiveBodiesLocked(true);
  213. #endif
  214. // Store the number of active bodies at the start of the step
  215. step.mNumActiveBodiesAtStepStart = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  216. // Lock all constraints
  217. mConstraintManager.LockAllConstraints();
  218. // Allocate memory for storing the active constraints
  219. JPH_ASSERT(context.mActiveConstraints == nullptr);
  220. context.mActiveConstraints = static_cast<Constraint **>(inTempAllocator->Allocate(mConstraintManager.GetNumConstraints() * sizeof(Constraint *)));
  221. // Prepare contact buffer
  222. mContactManager.PrepareConstraintBuffer(&context);
  223. // Setup island builder
  224. mIslandBuilder.PrepareContactConstraints(mContactManager.GetMaxConstraints(), context.mTempAllocator);
  225. }
  226. // This job applies gravity to all active bodies
  227. step.mApplyGravity.resize(num_apply_gravity_jobs);
  228. for (int i = 0; i < num_apply_gravity_jobs; ++i)
  229. step.mApplyGravity[i] = inJobSystem->CreateJob("ApplyGravity", cColorApplyGravity, [&context, &step]()
  230. {
  231. context.mPhysicsSystem->JobApplyGravity(&context, &step);
  232. JobHandle::sRemoveDependencies(step.mFindCollisions);
  233. }, num_step_listener_jobs > 0? num_step_listener_jobs : previous_step_dependency_count); // depends on: step listeners (or previous step if no step listeners)
  234. // This job will setup velocity constraints for non-collision constraints
  235. step.mSetupVelocityConstraints = inJobSystem->CreateJob("SetupVelocityConstraints", cColorSetupVelocityConstraints, [&context, &step]()
  236. {
  237. context.mPhysicsSystem->JobSetupVelocityConstraints(context.mStepDeltaTime, &step);
  238. JobHandle::sRemoveDependencies(step.mSolveVelocityConstraints);
  239. }, num_determine_active_constraints_jobs + 1); // depends on: determine active constraints, finish building jobs
  240. // This job will build islands from constraints
  241. step.mBuildIslandsFromConstraints = inJobSystem->CreateJob("BuildIslandsFromConstraints", cColorBuildIslandsFromConstraints, [&context, &step]()
  242. {
  243. context.mPhysicsSystem->JobBuildIslandsFromConstraints(&context, &step);
  244. step.mFindCollisions[0].RemoveDependency(); // The first collisions job cannot start running until we've finished building islands and activated all bodies
  245. step.mFinalizeIslands.RemoveDependency();
  246. }, num_determine_active_constraints_jobs + 1); // depends on: determine active constraints, finish building jobs
  247. // This job determines active constraints
  248. step.mDetermineActiveConstraints.resize(num_determine_active_constraints_jobs);
  249. for (int i = 0; i < num_determine_active_constraints_jobs; ++i)
  250. step.mDetermineActiveConstraints[i] = inJobSystem->CreateJob("DetermineActiveConstraints", cColorDetermineActiveConstraints, [&context, &step]()
  251. {
  252. context.mPhysicsSystem->JobDetermineActiveConstraints(&step);
  253. step.mSetupVelocityConstraints.RemoveDependency();
  254. step.mBuildIslandsFromConstraints.RemoveDependency();
  255. // Kick find collisions last as they will use up all CPU cores leaving no space for the previous 2 jobs
  256. JobHandle::sRemoveDependencies(step.mFindCollisions);
  257. }, num_step_listener_jobs > 0? num_step_listener_jobs : previous_step_dependency_count); // depends on: step listeners (or previous step if no step listeners)
  258. // This job calls the step listeners
  259. step.mStepListeners.resize(num_step_listener_jobs);
  260. for (int i = 0; i < num_step_listener_jobs; ++i)
  261. step.mStepListeners[i] = inJobSystem->CreateJob("StepListeners", cColorStepListeners, [&context, &step]()
  262. {
  263. // Call the step listeners
  264. context.mPhysicsSystem->JobStepListeners(&step);
  265. // Kick apply gravity and determine active constraint jobs
  266. JobHandle::sRemoveDependencies(step.mApplyGravity);
  267. JobHandle::sRemoveDependencies(step.mDetermineActiveConstraints);
  268. }, previous_step_dependency_count);
  269. // Unblock the previous step
  270. if (!is_first_step)
  271. context.mSteps[step_idx - 1].mStartNextStep.RemoveDependency();
  272. // This job will finalize the simulation islands
  273. step.mFinalizeIslands = inJobSystem->CreateJob("FinalizeIslands", cColorFinalizeIslands, [&context, &step]()
  274. {
  275. // Validate that all find collision jobs have stopped
  276. JPH_ASSERT(step.mActiveFindCollisionJobs == 0);
  277. context.mPhysicsSystem->JobFinalizeIslands(&context);
  278. JobHandle::sRemoveDependencies(step.mSolveVelocityConstraints);
  279. step.mBodySetIslandIndex.RemoveDependency();
  280. }, num_find_collisions_jobs + 2); // depends on: find collisions, build islands from constraints, finish building jobs
  281. // Unblock previous job
  282. // Note: technically we could release find collisions here but we don't want to because that could make them run before 'setup velocity constraints' which means that job won't have a thread left
  283. step.mBuildIslandsFromConstraints.RemoveDependency();
  284. // This job will call the contact removed callbacks
  285. step.mContactRemovedCallbacks = inJobSystem->CreateJob("ContactRemovedCallbacks", cColorContactRemovedCallbacks, [&context, &step]()
  286. {
  287. context.mPhysicsSystem->JobContactRemovedCallbacks(&step);
  288. if (step.mStartNextStep.IsValid())
  289. step.mStartNextStep.RemoveDependency();
  290. }, 1); // depends on the find ccd contacts
  291. // This job will set the island index on each body (only used for debug drawing purposes)
  292. // It will also delete any bodies that have been destroyed in the last frame
  293. step.mBodySetIslandIndex = inJobSystem->CreateJob("BodySetIslandIndex", cColorBodySetIslandIndex, [&context, &step]()
  294. {
  295. context.mPhysicsSystem->JobBodySetIslandIndex();
  296. if (step.mStartNextStep.IsValid())
  297. step.mStartNextStep.RemoveDependency();
  298. }, 1); // depends on: finalize islands
  299. // Job to start the next collision step
  300. if (!is_last_step)
  301. {
  302. PhysicsUpdateContext::Step *next_step = &context.mSteps[step_idx + 1];
  303. step.mStartNextStep = inJobSystem->CreateJob("StartNextStep", cColorStartNextStep, [this, next_step]()
  304. {
  305. #ifdef _DEBUG
  306. // Validate that the cached bounds are correct
  307. mBodyManager.ValidateActiveBodyBounds();
  308. #endif // _DEBUG
  309. // Store the number of active bodies at the start of the step
  310. next_step->mNumActiveBodiesAtStepStart = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  311. // Clear the large island splitter
  312. TempAllocator *temp_allocator = next_step->mContext->mTempAllocator;
  313. mLargeIslandSplitter.Reset(temp_allocator);
  314. // Clear the island builder
  315. mIslandBuilder.ResetIslands(temp_allocator);
  316. // Setup island builder
  317. mIslandBuilder.PrepareContactConstraints(mContactManager.GetMaxConstraints(), temp_allocator);
  318. // Restart the contact manager
  319. mContactManager.RecycleConstraintBuffer();
  320. // Kick the jobs of the next step (in the same order as the first step)
  321. next_step->mBroadPhasePrepare.RemoveDependency();
  322. if (next_step->mStepListeners.empty())
  323. {
  324. // Kick the gravity and active constraints jobs immediately
  325. JobHandle::sRemoveDependencies(next_step->mApplyGravity);
  326. JobHandle::sRemoveDependencies(next_step->mDetermineActiveConstraints);
  327. }
  328. else
  329. {
  330. // Kick the step listeners job first
  331. JobHandle::sRemoveDependencies(next_step->mStepListeners);
  332. }
  333. }, 4); // depends on: update soft bodies, body set island index, contact removed callbacks, finish building the previous step
  334. }
  335. // This job will solve the velocity constraints
  336. step.mSolveVelocityConstraints.resize(max_concurrency);
  337. for (int i = 0; i < max_concurrency; ++i)
  338. step.mSolveVelocityConstraints[i] = inJobSystem->CreateJob("SolveVelocityConstraints", cColorSolveVelocityConstraints, [&context, &step]()
  339. {
  340. context.mPhysicsSystem->JobSolveVelocityConstraints(&context, &step);
  341. step.mPreIntegrateVelocity.RemoveDependency();
  342. }, 3); // depends on: finalize islands, setup velocity constraints, finish building jobs.
  343. // Kick find collisions after setup velocity constraints because the former job will use up all CPU cores
  344. step.mSetupVelocityConstraints.RemoveDependency();
  345. JobHandle::sRemoveDependencies(step.mFindCollisions);
  346. // Finalize islands is a dependency on find collisions so it can go last
  347. step.mFinalizeIslands.RemoveDependency();
  348. // This job will prepare the position update of all active bodies
  349. step.mPreIntegrateVelocity = inJobSystem->CreateJob("PreIntegrateVelocity", cColorPreIntegrateVelocity, [&context, &step]()
  350. {
  351. context.mPhysicsSystem->JobPreIntegrateVelocity(&context, &step);
  352. JobHandle::sRemoveDependencies(step.mIntegrateVelocity);
  353. }, 2 + max_concurrency); // depends on: broadphase update finalize, solve velocity constraints, finish building jobs.
  354. // Unblock previous jobs
  355. step.mUpdateBroadphaseFinalize.RemoveDependency();
  356. JobHandle::sRemoveDependencies(step.mSolveVelocityConstraints);
  357. // This job will update the positions of all active bodies
  358. step.mIntegrateVelocity.resize(num_integrate_velocity_jobs);
  359. for (int i = 0; i < num_integrate_velocity_jobs; ++i)
  360. step.mIntegrateVelocity[i] = inJobSystem->CreateJob("IntegrateVelocity", cColorIntegrateVelocity, [&context, &step]()
  361. {
  362. context.mPhysicsSystem->JobIntegrateVelocity(&context, &step);
  363. step.mPostIntegrateVelocity.RemoveDependency();
  364. }, 2); // depends on: pre integrate velocity, finish building jobs.
  365. // Unblock previous job
  366. step.mPreIntegrateVelocity.RemoveDependency();
  367. // This job will finish the position update of all active bodies
  368. step.mPostIntegrateVelocity = inJobSystem->CreateJob("PostIntegrateVelocity", cColorPostIntegrateVelocity, [&context, &step]()
  369. {
  370. context.mPhysicsSystem->JobPostIntegrateVelocity(&context, &step);
  371. step.mResolveCCDContacts.RemoveDependency();
  372. }, num_integrate_velocity_jobs + 1); // depends on: integrate velocity, finish building jobs
  373. // Unblock previous jobs
  374. JobHandle::sRemoveDependencies(step.mIntegrateVelocity);
  375. // This job will update the positions and velocities for all bodies that need continuous collision detection
  376. step.mResolveCCDContacts = inJobSystem->CreateJob("ResolveCCDContacts", cColorResolveCCDContacts, [&context, &step]()
  377. {
  378. context.mPhysicsSystem->JobResolveCCDContacts(&context, &step);
  379. JobHandle::sRemoveDependencies(step.mSolvePositionConstraints);
  380. }, 2); // depends on: integrate velocities, detect ccd contacts (added dynamically), finish building jobs.
  381. // Unblock previous job
  382. step.mPostIntegrateVelocity.RemoveDependency();
  383. // Fixes up drift in positions and updates the broadphase with new body positions
  384. step.mSolvePositionConstraints.resize(max_concurrency);
  385. for (int i = 0; i < max_concurrency; ++i)
  386. step.mSolvePositionConstraints[i] = inJobSystem->CreateJob("SolvePositionConstraints", cColorSolvePositionConstraints, [&context, &step]()
  387. {
  388. context.mPhysicsSystem->JobSolvePositionConstraints(&context, &step);
  389. // Kick the next step
  390. if (step.mUpdateSoftBodies.IsValid())
  391. step.mUpdateSoftBodies.RemoveDependency();
  392. }, 2); // depends on: resolve ccd contacts, finish building jobs.
  393. // Unblock previous job.
  394. step.mResolveCCDContacts.RemoveDependency();
  395. step.mUpdateSoftBodies = inJobSystem->CreateJob("UpdateSoftBodies", cColorUpdateSoftBodies, [&context, &step]()
  396. {
  397. context.mPhysicsSystem->JobUpdateSoftBodies(&context);
  398. // Kick the next step
  399. if (step.mStartNextStep.IsValid())
  400. step.mStartNextStep.RemoveDependency();
  401. }, max_concurrency); // depends on: solve position constraints.
  402. // Unblock previous jobs
  403. JobHandle::sRemoveDependencies(step.mSolvePositionConstraints);
  404. }
  405. }
  406. // Build the list of jobs to wait for
  407. JobSystem::Barrier *barrier = context.mBarrier;
  408. {
  409. JPH_PROFILE("Build job barrier");
  410. StaticArray<JobHandle, cMaxPhysicsJobs> handles;
  411. for (const PhysicsUpdateContext::Step &step : context.mSteps)
  412. {
  413. if (step.mBroadPhasePrepare.IsValid())
  414. handles.push_back(step.mBroadPhasePrepare);
  415. for (const JobHandle &h : step.mStepListeners)
  416. handles.push_back(h);
  417. for (const JobHandle &h : step.mDetermineActiveConstraints)
  418. handles.push_back(h);
  419. for (const JobHandle &h : step.mApplyGravity)
  420. handles.push_back(h);
  421. for (const JobHandle &h : step.mFindCollisions)
  422. handles.push_back(h);
  423. if (step.mUpdateBroadphaseFinalize.IsValid())
  424. handles.push_back(step.mUpdateBroadphaseFinalize);
  425. handles.push_back(step.mSetupVelocityConstraints);
  426. handles.push_back(step.mBuildIslandsFromConstraints);
  427. handles.push_back(step.mFinalizeIslands);
  428. handles.push_back(step.mBodySetIslandIndex);
  429. for (const JobHandle &h : step.mSolveVelocityConstraints)
  430. handles.push_back(h);
  431. handles.push_back(step.mPreIntegrateVelocity);
  432. for (const JobHandle &h : step.mIntegrateVelocity)
  433. handles.push_back(h);
  434. handles.push_back(step.mPostIntegrateVelocity);
  435. handles.push_back(step.mResolveCCDContacts);
  436. for (const JobHandle &h : step.mSolvePositionConstraints)
  437. handles.push_back(h);
  438. handles.push_back(step.mContactRemovedCallbacks);
  439. if (step.mUpdateSoftBodies.IsValid())
  440. handles.push_back(step.mUpdateSoftBodies);
  441. if (step.mStartNextStep.IsValid())
  442. handles.push_back(step.mStartNextStep);
  443. }
  444. barrier->AddJobs(handles.data(), handles.size());
  445. }
  446. // Wait until all jobs finish
  447. // Note we don't just wait for the last job. If we would and another job
  448. // would be scheduled in between there is the possibility of a deadlock.
  449. // The other job could try to e.g. add/remove a body which would try to
  450. // lock a body mutex while this thread has already locked the mutex
  451. inJobSystem->WaitForJobs(barrier);
  452. // We're done with the barrier for this update
  453. inJobSystem->DestroyBarrier(barrier);
  454. #ifdef _DEBUG
  455. // Validate that the cached bounds are correct
  456. mBodyManager.ValidateActiveBodyBounds();
  457. #endif // _DEBUG
  458. // Clear the large island splitter
  459. mLargeIslandSplitter.Reset(inTempAllocator);
  460. // Clear the island builder
  461. mIslandBuilder.ResetIslands(inTempAllocator);
  462. // Clear the contact manager
  463. mContactManager.FinishConstraintBuffer();
  464. // Free active constraints
  465. inTempAllocator->Free(context.mActiveConstraints, mConstraintManager.GetNumConstraints() * sizeof(Constraint *));
  466. context.mActiveConstraints = nullptr;
  467. // Free body pairs
  468. inTempAllocator->Free(context.mBodyPairs, sizeof(BodyPair) * mPhysicsSettings.mMaxInFlightBodyPairs);
  469. context.mBodyPairs = nullptr;
  470. // Unlock the broadphase
  471. mBroadPhase->UnlockModifications();
  472. // Unlock all constraints
  473. mConstraintManager.UnlockAllConstraints();
  474. #ifdef JPH_ENABLE_ASSERTS
  475. // Allow write operations to the active bodies list
  476. mBodyManager.SetActiveBodiesLocked(false);
  477. #endif
  478. // Unlock all bodies
  479. mBodyManager.UnlockAllBodies();
  480. // Unlock step listeners
  481. mStepListenersMutex.unlock();
  482. // Return any errors
  483. EPhysicsUpdateError errors = static_cast<EPhysicsUpdateError>(context.mErrors.load(memory_order_acquire));
  484. JPH_ASSERT(errors == EPhysicsUpdateError::None, "An error occured during the physics update, see EPhysicsUpdateError for more information");
  485. return errors;
  486. }
  487. void PhysicsSystem::JobStepListeners(PhysicsUpdateContext::Step *ioStep)
  488. {
  489. #ifdef JPH_ENABLE_ASSERTS
  490. // Read positions (broadphase updates concurrently so we can't write), read/write velocities
  491. BodyAccess::Grant grant(BodyAccess::EAccess::ReadWrite, BodyAccess::EAccess::Read);
  492. // Can activate bodies only (we cache the amount of active bodies at the beginning of the step in mNumActiveBodiesAtStepStart so we cannot deactivate here)
  493. BodyManager::GrantActiveBodiesAccess grant_active(true, false);
  494. #endif
  495. float step_time = ioStep->mContext->mStepDeltaTime;
  496. uint32 batch_size = mPhysicsSettings.mStepListenersBatchSize;
  497. for (;;)
  498. {
  499. // Get the start of a new batch
  500. uint32 batch = ioStep->mStepListenerReadIdx.fetch_add(batch_size);
  501. if (batch >= mStepListeners.size())
  502. break;
  503. // Call the listeners
  504. for (uint32 i = batch, i_end = min((uint32)mStepListeners.size(), batch + batch_size); i < i_end; ++i)
  505. mStepListeners[i]->OnStep(step_time, *this);
  506. }
  507. }
  508. void PhysicsSystem::JobDetermineActiveConstraints(PhysicsUpdateContext::Step *ioStep) const
  509. {
  510. #ifdef JPH_ENABLE_ASSERTS
  511. // No body access
  512. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::None);
  513. #endif
  514. uint32 num_constraints = mConstraintManager.GetNumConstraints();
  515. uint32 num_active_constraints;
  516. Constraint **active_constraints = (Constraint **)JPH_STACK_ALLOC(cDetermineActiveConstraintsBatchSize * sizeof(Constraint *));
  517. for (;;)
  518. {
  519. // Atomically fetch a batch of constraints
  520. uint32 constraint_idx = ioStep->mConstraintReadIdx.fetch_add(cDetermineActiveConstraintsBatchSize);
  521. if (constraint_idx >= num_constraints)
  522. break;
  523. // Calculate the end of the batch
  524. uint32 constraint_idx_end = min(num_constraints, constraint_idx + cDetermineActiveConstraintsBatchSize);
  525. // Store the active constraints at the start of the step (bodies get activated during the step which in turn may activate constraints leading to an inconsistent shapshot)
  526. mConstraintManager.GetActiveConstraints(constraint_idx, constraint_idx_end, active_constraints, num_active_constraints);
  527. // Copy the block of active constraints to the global list of active constraints
  528. if (num_active_constraints > 0)
  529. {
  530. uint32 active_constraint_idx = ioStep->mNumActiveConstraints.fetch_add(num_active_constraints);
  531. memcpy(ioStep->mContext->mActiveConstraints + active_constraint_idx, active_constraints, num_active_constraints * sizeof(Constraint *));
  532. }
  533. }
  534. }
  535. void PhysicsSystem::JobApplyGravity(const PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  536. {
  537. #ifdef JPH_ENABLE_ASSERTS
  538. // We update velocities and need the rotation to do so
  539. BodyAccess::Grant grant(BodyAccess::EAccess::ReadWrite, BodyAccess::EAccess::Read);
  540. #endif
  541. // Get list of active bodies that we had at the start of the physics update.
  542. // Any body that is activated as part of the simulation step does not receive gravity this frame.
  543. // Note that bodies may be activated during this job but not deactivated, this means that only elements
  544. // will be added to the array. Since the array is made to not reallocate, this is a safe operation.
  545. const BodyID *active_bodies = mBodyManager.GetActiveBodiesUnsafe(EBodyType::RigidBody);
  546. uint32 num_active_bodies_at_step_start = ioStep->mNumActiveBodiesAtStepStart;
  547. // Fetch delta time once outside the loop
  548. float delta_time = ioContext->mStepDeltaTime;
  549. // Update velocities from forces
  550. for (;;)
  551. {
  552. // Atomically fetch a batch of bodies
  553. uint32 active_body_idx = ioStep->mApplyGravityReadIdx.fetch_add(cApplyGravityBatchSize);
  554. if (active_body_idx >= num_active_bodies_at_step_start)
  555. break;
  556. // Calculate the end of the batch
  557. uint32 active_body_idx_end = min(num_active_bodies_at_step_start, active_body_idx + cApplyGravityBatchSize);
  558. // Process the batch
  559. while (active_body_idx < active_body_idx_end)
  560. {
  561. Body &body = mBodyManager.GetBody(active_bodies[active_body_idx]);
  562. if (body.IsDynamic())
  563. body.GetMotionProperties()->ApplyForceTorqueAndDragInternal(body.GetRotation(), mGravity, delta_time);
  564. active_body_idx++;
  565. }
  566. }
  567. }
  568. void PhysicsSystem::JobSetupVelocityConstraints(float inDeltaTime, PhysicsUpdateContext::Step *ioStep) const
  569. {
  570. #ifdef JPH_ENABLE_ASSERTS
  571. // We only read positions
  572. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::Read);
  573. #endif
  574. ConstraintManager::sSetupVelocityConstraints(ioStep->mContext->mActiveConstraints, ioStep->mNumActiveConstraints, inDeltaTime);
  575. }
  576. void PhysicsSystem::JobBuildIslandsFromConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  577. {
  578. #ifdef JPH_ENABLE_ASSERTS
  579. // We read constraints and positions
  580. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::Read);
  581. // Can only activate bodies
  582. BodyManager::GrantActiveBodiesAccess grant_active(true, false);
  583. #endif
  584. // Prepare the island builder
  585. mIslandBuilder.PrepareNonContactConstraints(ioStep->mNumActiveConstraints, ioContext->mTempAllocator);
  586. // Build the islands
  587. ConstraintManager::sBuildIslands(ioStep->mContext->mActiveConstraints, ioStep->mNumActiveConstraints, mIslandBuilder, mBodyManager);
  588. }
  589. void PhysicsSystem::TrySpawnJobFindCollisions(PhysicsUpdateContext::Step *ioStep) const
  590. {
  591. // Get how many jobs we can spawn and check if we can spawn more
  592. uint max_jobs = ioStep->mBodyPairQueues.size();
  593. if (CountBits(ioStep->mActiveFindCollisionJobs) >= max_jobs)
  594. return;
  595. // Count how many body pairs we have waiting
  596. uint32 num_body_pairs = 0;
  597. for (const PhysicsUpdateContext::BodyPairQueue &queue : ioStep->mBodyPairQueues)
  598. num_body_pairs += queue.mWriteIdx - queue.mReadIdx;
  599. // Count how many active bodies we have waiting
  600. uint32 num_active_bodies = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody) - ioStep->mActiveBodyReadIdx;
  601. // Calculate how many jobs we would like
  602. uint desired_num_jobs = min((num_body_pairs + cNarrowPhaseBatchSize - 1) / cNarrowPhaseBatchSize + (num_active_bodies + cActiveBodiesBatchSize - 1) / cActiveBodiesBatchSize, max_jobs);
  603. for (;;)
  604. {
  605. // Get the bit mask of active jobs and see if we can spawn more
  606. PhysicsUpdateContext::JobMask current_active_jobs = ioStep->mActiveFindCollisionJobs;
  607. if (CountBits(current_active_jobs) >= desired_num_jobs)
  608. break;
  609. // Loop through all possible job indices
  610. for (uint job_index = 0; job_index < max_jobs; ++job_index)
  611. {
  612. // Test if it has been started
  613. PhysicsUpdateContext::JobMask job_mask = PhysicsUpdateContext::JobMask(1) << job_index;
  614. if ((current_active_jobs & job_mask) == 0)
  615. {
  616. // Try to claim the job index
  617. PhysicsUpdateContext::JobMask prev_value = ioStep->mActiveFindCollisionJobs.fetch_or(job_mask);
  618. if ((prev_value & job_mask) == 0)
  619. {
  620. // Add dependencies from the find collisions job to the next jobs
  621. ioStep->mUpdateBroadphaseFinalize.AddDependency();
  622. ioStep->mFinalizeIslands.AddDependency();
  623. // Start the job
  624. JobHandle job = ioStep->mContext->mJobSystem->CreateJob("FindCollisions", cColorFindCollisions, [step = ioStep, job_index]()
  625. {
  626. step->mContext->mPhysicsSystem->JobFindCollisions(step, job_index);
  627. });
  628. // Add the job to the job barrier so the main updating thread can execute the job too
  629. ioStep->mContext->mBarrier->AddJob(job);
  630. // Spawn only 1 extra job at a time
  631. return;
  632. }
  633. }
  634. }
  635. }
  636. }
  637. static void sFinalizeContactAllocator(PhysicsUpdateContext::Step &ioStep, const ContactConstraintManager::ContactAllocator &inAllocator)
  638. {
  639. // Atomically accumulate the number of found manifolds and body pairs
  640. ioStep.mNumBodyPairs.fetch_add(inAllocator.mNumBodyPairs, memory_order_relaxed);
  641. ioStep.mNumManifolds.fetch_add(inAllocator.mNumManifolds, memory_order_relaxed);
  642. // Combine update errors
  643. ioStep.mContext->mErrors.fetch_or((uint32)inAllocator.mErrors, memory_order_relaxed);
  644. }
  645. void PhysicsSystem::JobFindCollisions(PhysicsUpdateContext::Step *ioStep, int inJobIndex)
  646. {
  647. #ifdef JPH_ENABLE_ASSERTS
  648. // We read positions and read velocities (for elastic collisions)
  649. BodyAccess::Grant grant(BodyAccess::EAccess::Read, BodyAccess::EAccess::Read);
  650. // Can only activate bodies
  651. BodyManager::GrantActiveBodiesAccess grant_active(true, false);
  652. #endif
  653. // Allocation context for allocating new contact points
  654. ContactAllocator contact_allocator(mContactManager.GetContactAllocator());
  655. // Determine initial queue to read pairs from if no broadphase work can be done
  656. // (always start looking at results from the next job)
  657. int read_queue_idx = (inJobIndex + 1) % ioStep->mBodyPairQueues.size();
  658. for (;;)
  659. {
  660. // Check if there are active bodies to be processed
  661. uint32 active_bodies_read_idx = ioStep->mActiveBodyReadIdx;
  662. uint32 num_active_bodies = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  663. if (active_bodies_read_idx < num_active_bodies)
  664. {
  665. // Take a batch of active bodies
  666. uint32 active_bodies_read_idx_end = min(num_active_bodies, active_bodies_read_idx + cActiveBodiesBatchSize);
  667. if (ioStep->mActiveBodyReadIdx.compare_exchange_strong(active_bodies_read_idx, active_bodies_read_idx_end))
  668. {
  669. // Callback when a new body pair is found
  670. class MyBodyPairCallback : public BodyPairCollector
  671. {
  672. public:
  673. // Constructor
  674. MyBodyPairCallback(PhysicsUpdateContext::Step *inStep, ContactAllocator &ioContactAllocator, int inJobIndex) :
  675. mStep(inStep),
  676. mContactAllocator(ioContactAllocator),
  677. mJobIndex(inJobIndex)
  678. {
  679. }
  680. // Callback function when a body pair is found
  681. virtual void AddHit(const BodyPair &inPair) override
  682. {
  683. // Check if we have space in our write queue
  684. PhysicsUpdateContext::BodyPairQueue &queue = mStep->mBodyPairQueues[mJobIndex];
  685. uint32 body_pairs_in_queue = queue.mWriteIdx - queue.mReadIdx;
  686. if (body_pairs_in_queue >= mStep->mMaxBodyPairsPerQueue)
  687. {
  688. // Buffer full, process the pair now
  689. mStep->mContext->mPhysicsSystem->ProcessBodyPair(mContactAllocator, inPair);
  690. }
  691. else
  692. {
  693. // Store the pair in our own queue
  694. mStep->mContext->mBodyPairs[mJobIndex * mStep->mMaxBodyPairsPerQueue + queue.mWriteIdx % mStep->mMaxBodyPairsPerQueue] = inPair;
  695. ++queue.mWriteIdx;
  696. }
  697. }
  698. private:
  699. PhysicsUpdateContext::Step * mStep;
  700. ContactAllocator & mContactAllocator;
  701. int mJobIndex;
  702. };
  703. MyBodyPairCallback add_pair(ioStep, contact_allocator, inJobIndex);
  704. // Copy active bodies to temporary array, broadphase will reorder them
  705. uint32 batch_size = active_bodies_read_idx_end - active_bodies_read_idx;
  706. BodyID *active_bodies = (BodyID *)JPH_STACK_ALLOC(batch_size * sizeof(BodyID));
  707. memcpy(active_bodies, mBodyManager.GetActiveBodiesUnsafe(EBodyType::RigidBody) + active_bodies_read_idx, batch_size * sizeof(BodyID));
  708. // Find pairs in the broadphase
  709. mBroadPhase->FindCollidingPairs(active_bodies, batch_size, mPhysicsSettings.mSpeculativeContactDistance, *mObjectVsBroadPhaseLayerFilter, *mObjectLayerPairFilter, add_pair);
  710. // Check if we have enough pairs in the buffer to start a new job
  711. const PhysicsUpdateContext::BodyPairQueue &queue = ioStep->mBodyPairQueues[inJobIndex];
  712. uint32 body_pairs_in_queue = queue.mWriteIdx - queue.mReadIdx;
  713. if (body_pairs_in_queue >= cNarrowPhaseBatchSize)
  714. TrySpawnJobFindCollisions(ioStep);
  715. }
  716. }
  717. else
  718. {
  719. // Lockless loop to get the next body pair from the pairs buffer
  720. const PhysicsUpdateContext *context = ioStep->mContext;
  721. int first_read_queue_idx = read_queue_idx;
  722. for (;;)
  723. {
  724. PhysicsUpdateContext::BodyPairQueue &queue = ioStep->mBodyPairQueues[read_queue_idx];
  725. // Get the next pair to process
  726. uint32 pair_idx = queue.mReadIdx;
  727. // If the pair hasn't been written yet
  728. if (pair_idx >= queue.mWriteIdx)
  729. {
  730. // Go to the next queue
  731. read_queue_idx = (read_queue_idx + 1) % ioStep->mBodyPairQueues.size();
  732. // If we're back at the first queue, we've looked at all of them and found nothing
  733. if (read_queue_idx == first_read_queue_idx)
  734. {
  735. // Collect information from the contact allocator and accumulate it in the step.
  736. sFinalizeContactAllocator(*ioStep, contact_allocator);
  737. // Mark this job as inactive
  738. ioStep->mActiveFindCollisionJobs.fetch_and(~PhysicsUpdateContext::JobMask(1 << inJobIndex));
  739. // Trigger the next jobs
  740. ioStep->mUpdateBroadphaseFinalize.RemoveDependency();
  741. ioStep->mFinalizeIslands.RemoveDependency();
  742. return;
  743. }
  744. // Try again reading from the next queue
  745. continue;
  746. }
  747. // Copy the body pair out of the buffer
  748. const BodyPair bp = context->mBodyPairs[read_queue_idx * ioStep->mMaxBodyPairsPerQueue + pair_idx % ioStep->mMaxBodyPairsPerQueue];
  749. // Mark this pair as taken
  750. if (queue.mReadIdx.compare_exchange_strong(pair_idx, pair_idx + 1))
  751. {
  752. // Process the actual body pair
  753. ProcessBodyPair(contact_allocator, bp);
  754. break;
  755. }
  756. }
  757. }
  758. }
  759. }
  760. void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const BodyPair &inBodyPair)
  761. {
  762. JPH_PROFILE_FUNCTION();
  763. // Fetch body pair
  764. Body *body1 = &mBodyManager.GetBody(inBodyPair.mBodyA);
  765. Body *body2 = &mBodyManager.GetBody(inBodyPair.mBodyB);
  766. JPH_ASSERT(body1->IsActive());
  767. JPH_DET_LOG("ProcessBodyPair: id1: " << inBodyPair.mBodyA << " id2: " << inBodyPair.mBodyB << " p1: " << body1->GetCenterOfMassPosition() << " p2: " << body2->GetCenterOfMassPosition() << " r1: " << body1->GetRotation() << " r2: " << body2->GetRotation());
  768. // Ensure that body1 is dynamic, this ensures that we do the collision detection in the space of a moving body, which avoids accuracy problems when testing a very large static object against a small dynamic object
  769. // Ensure that body1 id < body2 id for dynamic vs dynamic
  770. // Keep body order unchanged when colliding with a sensor
  771. if ((!body1->IsDynamic() || (body2->IsDynamic() && inBodyPair.mBodyB < inBodyPair.mBodyA))
  772. && !body2->IsSensor())
  773. swap(body1, body2);
  774. JPH_ASSERT(body1->IsDynamic() || body2->IsSensor());
  775. // Check if the contact points from the previous frame are reusable and if so copy them
  776. bool pair_handled = false, constraint_created = false;
  777. if (mPhysicsSettings.mUseBodyPairContactCache && !(body1->IsCollisionCacheInvalid() || body2->IsCollisionCacheInvalid()))
  778. mContactManager.GetContactsFromCache(ioContactAllocator, *body1, *body2, pair_handled, constraint_created);
  779. // If the cache hasn't handled this body pair do actual collision detection
  780. if (!pair_handled)
  781. {
  782. // Create entry in the cache for this body pair
  783. // Needs to happen irrespective if we found a collision or not (we want to remember that no collision was found too)
  784. ContactConstraintManager::BodyPairHandle body_pair_handle = mContactManager.AddBodyPair(ioContactAllocator, *body1, *body2);
  785. if (body_pair_handle == nullptr)
  786. return; // Out of cache space
  787. // Create the query settings
  788. CollideShapeSettings settings;
  789. settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
  790. settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
  791. settings.mMaxSeparationDistance = mPhysicsSettings.mSpeculativeContactDistance;
  792. settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity();
  793. // Get transforms relative to body1
  794. RVec3 offset = body1->GetCenterOfMassPosition();
  795. Mat44 transform1 = Mat44::sRotation(body1->GetRotation());
  796. Mat44 transform2 = body2->GetCenterOfMassTransform().PostTranslated(-offset).ToMat44();
  797. if (mPhysicsSettings.mUseManifoldReduction // Check global flag
  798. && body1->GetUseManifoldReductionWithBody(*body2)) // Check body flag
  799. {
  800. // Version WITH contact manifold reduction
  801. class MyManifold : public ContactManifold
  802. {
  803. public:
  804. Vec3 mFirstWorldSpaceNormal;
  805. };
  806. // A temporary structure that allows us to keep track of the all manifolds between this body pair
  807. using Manifolds = StaticArray<MyManifold, 32>;
  808. // Create collector
  809. class ReductionCollideShapeCollector : public CollideShapeCollector
  810. {
  811. public:
  812. ReductionCollideShapeCollector(PhysicsSystem *inSystem, const Body *inBody1, const Body *inBody2) :
  813. mSystem(inSystem),
  814. mBody1(inBody1),
  815. mBody2(inBody2)
  816. {
  817. }
  818. virtual void AddHit(const CollideShapeResult &inResult) override
  819. {
  820. // One of the following should be true:
  821. // - Body 1 is dynamic and body 2 may be dynamic, static or kinematic
  822. // - Body 1 is not dynamic in which case body 2 should be a sensor
  823. JPH_ASSERT(mBody1->IsDynamic() || mBody2->IsSensor());
  824. JPH_ASSERT(!ShouldEarlyOut());
  825. // Test if we want to accept this hit
  826. if (mValidateBodyPair)
  827. {
  828. switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, mBody1->GetCenterOfMassPosition(), inResult))
  829. {
  830. case ValidateResult::AcceptContact:
  831. // We're just accepting this one, nothing to do
  832. break;
  833. case ValidateResult::AcceptAllContactsForThisBodyPair:
  834. // Accept and stop calling the validate callback
  835. mValidateBodyPair = false;
  836. break;
  837. case ValidateResult::RejectContact:
  838. // Skip this contact
  839. return;
  840. case ValidateResult::RejectAllContactsForThisBodyPair:
  841. // Skip this and early out
  842. ForceEarlyOut();
  843. return;
  844. }
  845. }
  846. // Calculate normal
  847. Vec3 world_space_normal = inResult.mPenetrationAxis.Normalized();
  848. // Check if we can add it to an existing manifold
  849. Manifolds::iterator manifold;
  850. float contact_normal_cos_max_delta_rot = mSystem->mPhysicsSettings.mContactNormalCosMaxDeltaRotation;
  851. for (manifold = mManifolds.begin(); manifold != mManifolds.end(); ++manifold)
  852. if (world_space_normal.Dot(manifold->mFirstWorldSpaceNormal) >= contact_normal_cos_max_delta_rot)
  853. {
  854. // Update average normal
  855. manifold->mWorldSpaceNormal += world_space_normal;
  856. manifold->mPenetrationDepth = max(manifold->mPenetrationDepth, inResult.mPenetrationDepth);
  857. break;
  858. }
  859. if (manifold == mManifolds.end())
  860. {
  861. // Check if array is full
  862. if (mManifolds.size() == mManifolds.capacity())
  863. {
  864. // Full, find manifold with least amount of penetration
  865. manifold = mManifolds.begin();
  866. for (Manifolds::iterator m = mManifolds.begin() + 1; m < mManifolds.end(); ++m)
  867. if (m->mPenetrationDepth < manifold->mPenetrationDepth)
  868. manifold = m;
  869. // If this contacts penetration is smaller than the smallest manifold, we skip this contact
  870. if (inResult.mPenetrationDepth < manifold->mPenetrationDepth)
  871. return;
  872. // Replace the manifold
  873. *manifold = { { mBody1->GetCenterOfMassPosition(), world_space_normal, inResult.mPenetrationDepth, inResult.mSubShapeID1, inResult.mSubShapeID2, { }, { } }, world_space_normal };
  874. }
  875. else
  876. {
  877. // Not full, create new manifold
  878. mManifolds.push_back({ { mBody1->GetCenterOfMassPosition(), world_space_normal, inResult.mPenetrationDepth, inResult.mSubShapeID1, inResult.mSubShapeID2, { }, { } }, world_space_normal });
  879. manifold = mManifolds.end() - 1;
  880. }
  881. }
  882. // Determine contact points
  883. const PhysicsSettings &settings = mSystem->mPhysicsSettings;
  884. ManifoldBetweenTwoFaces(inResult.mContactPointOn1, inResult.mContactPointOn2, inResult.mPenetrationAxis, Square(settings.mSpeculativeContactDistance) + settings.mManifoldToleranceSq, inResult.mShape1Face, inResult.mShape2Face, manifold->mRelativeContactPointsOn1, manifold->mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, mBody1->GetCenterOfMassPosition()));
  885. // Prune if we have more than 32 points (this means we could run out of space in the next iteration)
  886. if (manifold->mRelativeContactPointsOn1.size() > 32)
  887. PruneContactPoints(manifold->mFirstWorldSpaceNormal, manifold->mRelativeContactPointsOn1, manifold->mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, manifold->mBaseOffset));
  888. }
  889. PhysicsSystem * mSystem;
  890. const Body * mBody1;
  891. const Body * mBody2;
  892. bool mValidateBodyPair = true;
  893. Manifolds mManifolds;
  894. };
  895. ReductionCollideShapeCollector collector(this, body1, body2);
  896. // Perform collision detection between the two shapes
  897. SubShapeIDCreator part1, part2;
  898. CollisionDispatch::sCollideShapeVsShape(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector);
  899. // Add the contacts
  900. for (ContactManifold &manifold : collector.mManifolds)
  901. {
  902. // Normalize the normal (is a sum of all normals from merged manifolds)
  903. manifold.mWorldSpaceNormal = manifold.mWorldSpaceNormal.Normalized();
  904. // If we still have too many points, prune them now
  905. if (manifold.mRelativeContactPointsOn1.size() > 4)
  906. PruneContactPoints(manifold.mWorldSpaceNormal, manifold.mRelativeContactPointsOn1, manifold.mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, manifold.mBaseOffset));
  907. // Actually add the contact points to the manager
  908. constraint_created |= mContactManager.AddContactConstraint(ioContactAllocator, body_pair_handle, *body1, *body2, manifold);
  909. }
  910. }
  911. else
  912. {
  913. // Version WITHOUT contact manifold reduction
  914. // Create collector
  915. class NonReductionCollideShapeCollector : public CollideShapeCollector
  916. {
  917. public:
  918. NonReductionCollideShapeCollector(PhysicsSystem *inSystem, ContactAllocator &ioContactAllocator, Body *inBody1, Body *inBody2, const ContactConstraintManager::BodyPairHandle &inPairHandle) :
  919. mSystem(inSystem),
  920. mContactAllocator(ioContactAllocator),
  921. mBody1(inBody1),
  922. mBody2(inBody2),
  923. mBodyPairHandle(inPairHandle)
  924. {
  925. }
  926. virtual void AddHit(const CollideShapeResult &inResult) override
  927. {
  928. // One of the following should be true:
  929. // - Body 1 is dynamic and body 2 may be dynamic, static or kinematic
  930. // - Body 1 is not dynamic in which case body 2 should be a sensor
  931. JPH_ASSERT(mBody1->IsDynamic() || mBody2->IsSensor());
  932. JPH_ASSERT(!ShouldEarlyOut());
  933. // Test if we want to accept this hit
  934. if (mValidateBodyPair)
  935. {
  936. switch (mSystem->mContactManager.ValidateContactPoint(*mBody1, *mBody2, mBody1->GetCenterOfMassPosition(), inResult))
  937. {
  938. case ValidateResult::AcceptContact:
  939. // We're just accepting this one, nothing to do
  940. break;
  941. case ValidateResult::AcceptAllContactsForThisBodyPair:
  942. // Accept and stop calling the validate callback
  943. mValidateBodyPair = false;
  944. break;
  945. case ValidateResult::RejectContact:
  946. // Skip this contact
  947. return;
  948. case ValidateResult::RejectAllContactsForThisBodyPair:
  949. // Skip this and early out
  950. ForceEarlyOut();
  951. return;
  952. }
  953. }
  954. // Determine contact points
  955. ContactManifold manifold;
  956. manifold.mBaseOffset = mBody1->GetCenterOfMassPosition();
  957. const PhysicsSettings &settings = mSystem->mPhysicsSettings;
  958. ManifoldBetweenTwoFaces(inResult.mContactPointOn1, inResult.mContactPointOn2, inResult.mPenetrationAxis, Square(settings.mSpeculativeContactDistance) + settings.mManifoldToleranceSq, inResult.mShape1Face, inResult.mShape2Face, manifold.mRelativeContactPointsOn1, manifold.mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, manifold.mBaseOffset));
  959. // Calculate normal
  960. manifold.mWorldSpaceNormal = inResult.mPenetrationAxis.Normalized();
  961. // Store penetration depth
  962. manifold.mPenetrationDepth = inResult.mPenetrationDepth;
  963. // Prune if we have more than 4 points
  964. if (manifold.mRelativeContactPointsOn1.size() > 4)
  965. PruneContactPoints(manifold.mWorldSpaceNormal, manifold.mRelativeContactPointsOn1, manifold.mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, manifold.mBaseOffset));
  966. // Set other properties
  967. manifold.mSubShapeID1 = inResult.mSubShapeID1;
  968. manifold.mSubShapeID2 = inResult.mSubShapeID2;
  969. // Actually add the contact points to the manager
  970. mConstraintCreated |= mSystem->mContactManager.AddContactConstraint(mContactAllocator, mBodyPairHandle, *mBody1, *mBody2, manifold);
  971. }
  972. PhysicsSystem * mSystem;
  973. ContactAllocator & mContactAllocator;
  974. Body * mBody1;
  975. Body * mBody2;
  976. ContactConstraintManager::BodyPairHandle mBodyPairHandle;
  977. bool mValidateBodyPair = true;
  978. bool mConstraintCreated = false;
  979. };
  980. NonReductionCollideShapeCollector collector(this, ioContactAllocator, body1, body2, body_pair_handle);
  981. // Perform collision detection between the two shapes
  982. SubShapeIDCreator part1, part2;
  983. CollisionDispatch::sCollideShapeVsShape(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector);
  984. constraint_created = collector.mConstraintCreated;
  985. }
  986. }
  987. // If a contact constraint was created, we need to do some extra work
  988. if (constraint_created)
  989. {
  990. // Wake up sleeping bodies
  991. BodyID body_ids[2];
  992. int num_bodies = 0;
  993. if (body1->IsDynamic() && !body1->IsActive())
  994. body_ids[num_bodies++] = body1->GetID();
  995. if (body2->IsDynamic() && !body2->IsActive())
  996. body_ids[num_bodies++] = body2->GetID();
  997. if (num_bodies > 0)
  998. mBodyManager.ActivateBodies(body_ids, num_bodies);
  999. // Link the two bodies
  1000. mIslandBuilder.LinkBodies(body1->GetIndexInActiveBodiesInternal(), body2->GetIndexInActiveBodiesInternal());
  1001. }
  1002. }
  1003. void PhysicsSystem::JobFinalizeIslands(PhysicsUpdateContext *ioContext)
  1004. {
  1005. #ifdef JPH_ENABLE_ASSERTS
  1006. // We only touch island data
  1007. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::None);
  1008. #endif
  1009. // Finish collecting the islands, at this point the active body list doesn't change so it's safe to access
  1010. mIslandBuilder.Finalize(mBodyManager.GetActiveBodiesUnsafe(EBodyType::RigidBody), mBodyManager.GetNumActiveBodies(EBodyType::RigidBody), mContactManager.GetNumConstraints(), ioContext->mTempAllocator);
  1011. // Prepare the large island splitter
  1012. if (mPhysicsSettings.mUseLargeIslandSplitter)
  1013. mLargeIslandSplitter.Prepare(mIslandBuilder, mBodyManager.GetNumActiveBodies(EBodyType::RigidBody), ioContext->mTempAllocator);
  1014. }
  1015. void PhysicsSystem::JobBodySetIslandIndex()
  1016. {
  1017. #ifdef JPH_ENABLE_ASSERTS
  1018. // We only touch island data
  1019. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::None);
  1020. #endif
  1021. // Loop through the result and tag all bodies with an island index
  1022. for (uint32 island_idx = 0, n = mIslandBuilder.GetNumIslands(); island_idx < n; ++island_idx)
  1023. {
  1024. BodyID *body_start, *body_end;
  1025. mIslandBuilder.GetBodiesInIsland(island_idx, body_start, body_end);
  1026. for (const BodyID *body = body_start; body < body_end; ++body)
  1027. mBodyManager.GetBody(*body).GetMotionProperties()->SetIslandIndexInternal(island_idx);
  1028. }
  1029. }
  1030. void PhysicsSystem::JobSolveVelocityConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1031. {
  1032. #ifdef JPH_ENABLE_ASSERTS
  1033. // We update velocities and need to read positions to do so
  1034. BodyAccess::Grant grant(BodyAccess::EAccess::ReadWrite, BodyAccess::EAccess::Read);
  1035. #endif
  1036. float delta_time = ioContext->mStepDeltaTime;
  1037. Constraint **active_constraints = ioContext->mActiveConstraints;
  1038. // Only the first step to correct for the delta time difference in the previous update
  1039. float warm_start_impulse_ratio = ioStep->mIsFirst? ioContext->mWarmStartImpulseRatio : 1.0f;
  1040. bool check_islands = true, check_split_islands = mPhysicsSettings.mUseLargeIslandSplitter;
  1041. do
  1042. {
  1043. // First try to get work from large islands
  1044. if (check_split_islands)
  1045. {
  1046. bool first_iteration;
  1047. uint split_island_index;
  1048. uint32 *constraints_begin, *constraints_end, *contacts_begin, *contacts_end;
  1049. switch (mLargeIslandSplitter.FetchNextBatch(split_island_index, constraints_begin, constraints_end, contacts_begin, contacts_end, first_iteration))
  1050. {
  1051. case LargeIslandSplitter::EStatus::BatchRetrieved:
  1052. {
  1053. if (first_iteration)
  1054. {
  1055. // Iteration 0 is used to warm start the batch (we added 1 to the number of iterations in LargeIslandSplitter::SplitIsland)
  1056. ConstraintManager::sWarmStartVelocityConstraints(active_constraints, constraints_begin, constraints_end, warm_start_impulse_ratio);
  1057. mContactManager.WarmStartVelocityConstraints(contacts_begin, contacts_end, warm_start_impulse_ratio);
  1058. }
  1059. else
  1060. {
  1061. // Solve velocity constraints
  1062. ConstraintManager::sSolveVelocityConstraints(active_constraints, constraints_begin, constraints_end, delta_time);
  1063. mContactManager.SolveVelocityConstraints(contacts_begin, contacts_end);
  1064. }
  1065. // Mark the batch as processed
  1066. bool last_iteration, final_batch;
  1067. mLargeIslandSplitter.MarkBatchProcessed(split_island_index, constraints_begin, constraints_end, contacts_begin, contacts_end, last_iteration, final_batch);
  1068. // Save back the lambdas in the contact cache for the warm start of the next physics update
  1069. if (last_iteration)
  1070. mContactManager.StoreAppliedImpulses(contacts_begin, contacts_end);
  1071. // We processed work, loop again
  1072. continue;
  1073. }
  1074. case LargeIslandSplitter::EStatus::WaitingForBatch:
  1075. break;
  1076. case LargeIslandSplitter::EStatus::AllBatchesDone:
  1077. check_split_islands = false;
  1078. break;
  1079. }
  1080. }
  1081. // If that didn't succeed try to process an island
  1082. if (check_islands)
  1083. {
  1084. // Next island
  1085. uint32 island_idx = ioStep->mSolveVelocityConstraintsNextIsland++;
  1086. if (island_idx >= mIslandBuilder.GetNumIslands())
  1087. {
  1088. // We processed all islands, stop checking islands
  1089. check_islands = false;
  1090. continue;
  1091. }
  1092. JPH_PROFILE("Island");
  1093. // Get iterators for this island
  1094. uint32 *constraints_begin, *constraints_end, *contacts_begin, *contacts_end;
  1095. bool has_constraints = mIslandBuilder.GetConstraintsInIsland(island_idx, constraints_begin, constraints_end);
  1096. bool has_contacts = mIslandBuilder.GetContactsInIsland(island_idx, contacts_begin, contacts_end);
  1097. // If we don't have any contacts or constraints, we know that none of the following islands have any contacts or constraints
  1098. // (because they're sorted by most constraints first). This means we're done.
  1099. if (!has_contacts && !has_constraints)
  1100. {
  1101. #ifdef JPH_ENABLE_ASSERTS
  1102. // Validate our assumption that the next islands don't have any constraints or contacts
  1103. for (; island_idx < mIslandBuilder.GetNumIslands(); ++island_idx)
  1104. {
  1105. JPH_ASSERT(!mIslandBuilder.GetConstraintsInIsland(island_idx, constraints_begin, constraints_end));
  1106. JPH_ASSERT(!mIslandBuilder.GetContactsInIsland(island_idx, contacts_begin, contacts_end));
  1107. }
  1108. #endif // JPH_ENABLE_ASSERTS
  1109. check_islands = false;
  1110. continue;
  1111. }
  1112. // Sorting is costly but needed for a deterministic simulation, allow the user to turn this off
  1113. if (mPhysicsSettings.mDeterministicSimulation)
  1114. {
  1115. // Sort constraints to give a deterministic simulation
  1116. ConstraintManager::sSortConstraints(active_constraints, constraints_begin, constraints_end);
  1117. // Sort contacts to give a deterministic simulation
  1118. mContactManager.SortContacts(contacts_begin, contacts_end);
  1119. }
  1120. // Split up large islands
  1121. int num_velocity_steps = mPhysicsSettings.mNumVelocitySteps;
  1122. if (mPhysicsSettings.mUseLargeIslandSplitter
  1123. && mLargeIslandSplitter.SplitIsland(island_idx, mIslandBuilder, mBodyManager, mContactManager, active_constraints, num_velocity_steps, mPhysicsSettings.mNumPositionSteps))
  1124. continue; // Loop again to try to fetch the newly split island
  1125. // We didn't create a split, just run the solver now for this entire island. Begin by warm starting.
  1126. ConstraintManager::sWarmStartVelocityConstraints(active_constraints, constraints_begin, constraints_end, warm_start_impulse_ratio, num_velocity_steps);
  1127. mContactManager.WarmStartVelocityConstraints(contacts_begin, contacts_end, warm_start_impulse_ratio);
  1128. // Solve velocity constraints
  1129. for (int velocity_step = 0; velocity_step < num_velocity_steps; ++velocity_step)
  1130. {
  1131. bool applied_impulse = ConstraintManager::sSolveVelocityConstraints(active_constraints, constraints_begin, constraints_end, delta_time);
  1132. applied_impulse |= mContactManager.SolveVelocityConstraints(contacts_begin, contacts_end);
  1133. if (!applied_impulse)
  1134. break;
  1135. }
  1136. // Save back the lambdas in the contact cache for the warm start of the next physics update
  1137. mContactManager.StoreAppliedImpulses(contacts_begin, contacts_end);
  1138. // We processed work, loop again
  1139. continue;
  1140. }
  1141. // If we didn't find any work, give up a time slice
  1142. std::this_thread::yield();
  1143. }
  1144. while (check_islands || check_split_islands);
  1145. }
  1146. void PhysicsSystem::JobPreIntegrateVelocity(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1147. {
  1148. // Reserve enough space for all bodies that may need a cast
  1149. TempAllocator *temp_allocator = ioContext->mTempAllocator;
  1150. JPH_ASSERT(ioStep->mCCDBodies == nullptr);
  1151. ioStep->mCCDBodiesCapacity = mBodyManager.GetNumActiveCCDBodies();
  1152. ioStep->mCCDBodies = (CCDBody *)temp_allocator->Allocate(ioStep->mCCDBodiesCapacity * sizeof(CCDBody));
  1153. // Initialize the mapping table between active body and CCD body
  1154. JPH_ASSERT(ioStep->mActiveBodyToCCDBody == nullptr);
  1155. ioStep->mNumActiveBodyToCCDBody = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  1156. ioStep->mActiveBodyToCCDBody = (int *)temp_allocator->Allocate(ioStep->mNumActiveBodyToCCDBody * sizeof(int));
  1157. // Prepare the split island builder for solving the position constraints
  1158. mLargeIslandSplitter.PrepareForSolvePositions();
  1159. }
  1160. void PhysicsSystem::JobIntegrateVelocity(const PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1161. {
  1162. #ifdef JPH_ENABLE_ASSERTS
  1163. // We update positions and need velocity to do so, we also clamp velocities so need to write to them
  1164. BodyAccess::Grant grant(BodyAccess::EAccess::ReadWrite, BodyAccess::EAccess::ReadWrite);
  1165. #endif
  1166. float delta_time = ioContext->mStepDeltaTime;
  1167. const BodyID *active_bodies = mBodyManager.GetActiveBodiesUnsafe(EBodyType::RigidBody);
  1168. uint32 num_active_bodies = mBodyManager.GetNumActiveBodies(EBodyType::RigidBody);
  1169. uint32 num_active_bodies_after_find_collisions = ioStep->mActiveBodyReadIdx;
  1170. // We can move bodies that are not part of an island. In this case we need to notify the broadphase of the movement.
  1171. static constexpr int cBodiesBatch = 64;
  1172. BodyID *bodies_to_update_bounds = (BodyID *)JPH_STACK_ALLOC(cBodiesBatch * sizeof(BodyID));
  1173. int num_bodies_to_update_bounds = 0;
  1174. for (;;)
  1175. {
  1176. // Atomically fetch a batch of bodies
  1177. uint32 active_body_idx = ioStep->mIntegrateVelocityReadIdx.fetch_add(cIntegrateVelocityBatchSize);
  1178. if (active_body_idx >= num_active_bodies)
  1179. break;
  1180. // Calculate the end of the batch
  1181. uint32 active_body_idx_end = min(num_active_bodies, active_body_idx + cIntegrateVelocityBatchSize);
  1182. // Process the batch
  1183. while (active_body_idx < active_body_idx_end)
  1184. {
  1185. // Update the positions using an Symplectic Euler step (which integrates using the updated velocity v1' rather
  1186. // than the original velocity v1):
  1187. // x1' = x1 + h * v1'
  1188. // At this point the active bodies list does not change, so it is safe to access the array.
  1189. BodyID body_id = active_bodies[active_body_idx];
  1190. Body &body = mBodyManager.GetBody(body_id);
  1191. MotionProperties *mp = body.GetMotionProperties();
  1192. JPH_DET_LOG("JobIntegrateVelocity: id: " << body_id << " v: " << body.GetLinearVelocity() << " w: " << body.GetAngularVelocity());
  1193. // Clamp velocities (not for kinematic bodies)
  1194. if (body.IsDynamic())
  1195. {
  1196. mp->ClampLinearVelocity();
  1197. mp->ClampAngularVelocity();
  1198. }
  1199. // Update the rotation of the body according to the angular velocity
  1200. // For motion type discrete we need to do this anyway, for motion type linear cast we have multiple choices
  1201. // 1. Rotate the body first and then sweep
  1202. // 2. First sweep and then rotate the body at the end
  1203. // 3. Pick some inbetween rotation (e.g. half way), then sweep and finally rotate the remainder
  1204. // (1) has some clear advantages as when a long thin body hits a surface away from the center of mass, this will result in a large angular velocity and a limited reduction in linear velocity.
  1205. // When simulation the rotation first before doing the translation, the body will be able to rotate away from the contact point allowing the center of mass to approach the surface. When using
  1206. // approach (2) in this case what will happen is that we will immediately detect the same collision again (the body has not rotated and the body was already colliding at the end of the previous
  1207. // time step) resulting in a lot of stolen time and the body appearing to be frozen in an unnatural pose (like it is glued at an angle to the surface). (2) obviously has some negative side effects
  1208. // too as simulating the rotation first may cause it to tunnel through a small object that the linear cast might have otherwise dectected. In any case a linear cast is not good for detecting
  1209. // tunneling due to angular rotation, so we don't care about that too much (you'd need a full cast to take angular effects into account).
  1210. body.AddRotationStep(body.GetAngularVelocity() * delta_time);
  1211. // Get delta position
  1212. Vec3 delta_pos = body.GetLinearVelocity() * delta_time;
  1213. // If the position should be updated (or if it is delayed because of CCD)
  1214. bool update_position = true;
  1215. switch (mp->GetMotionQuality())
  1216. {
  1217. case EMotionQuality::Discrete:
  1218. // No additional collision checking to be done
  1219. break;
  1220. case EMotionQuality::LinearCast:
  1221. if (body.IsDynamic() // Kinematic bodies cannot be stopped
  1222. && !body.IsSensor()) // We don't support CCD sensors
  1223. {
  1224. // Determine inner radius (the smallest sphere that fits into the shape)
  1225. float inner_radius = body.GetShape()->GetInnerRadius();
  1226. JPH_ASSERT(inner_radius > 0.0f, "The shape has no inner radius, this makes the shape unsuitable for the linear cast motion quality as we cannot move it without risking tunneling.");
  1227. // Measure translation in this step and check if it above the treshold to perform a linear cast
  1228. float linear_cast_threshold_sq = Square(mPhysicsSettings.mLinearCastThreshold * inner_radius);
  1229. if (delta_pos.LengthSq() > linear_cast_threshold_sq)
  1230. {
  1231. // This body needs a cast
  1232. uint32 ccd_body_idx = ioStep->mNumCCDBodies++;
  1233. ioStep->mActiveBodyToCCDBody[active_body_idx] = ccd_body_idx;
  1234. new (&ioStep->mCCDBodies[ccd_body_idx]) CCDBody(body_id, delta_pos, linear_cast_threshold_sq, min(mPhysicsSettings.mPenetrationSlop, mPhysicsSettings.mLinearCastMaxPenetration * inner_radius));
  1235. update_position = false;
  1236. }
  1237. }
  1238. break;
  1239. }
  1240. if (update_position)
  1241. {
  1242. // Move the body now
  1243. body.AddPositionStep(delta_pos);
  1244. // If the body was activated due to an earlier CCD step it will have an index in the active
  1245. // body list that it higher than the highest one we processed during FindCollisions
  1246. // which means it hasn't been assigned an island and will not be updated by an island
  1247. // this means that we need to update its bounds manually
  1248. if (mp->GetIndexInActiveBodiesInternal() >= num_active_bodies_after_find_collisions)
  1249. {
  1250. body.CalculateWorldSpaceBoundsInternal();
  1251. bodies_to_update_bounds[num_bodies_to_update_bounds++] = body.GetID();
  1252. if (num_bodies_to_update_bounds == cBodiesBatch)
  1253. {
  1254. // Buffer full, flush now
  1255. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1256. num_bodies_to_update_bounds = 0;
  1257. }
  1258. }
  1259. // We did not create a CCD body
  1260. ioStep->mActiveBodyToCCDBody[active_body_idx] = -1;
  1261. }
  1262. active_body_idx++;
  1263. }
  1264. }
  1265. // Notify change bounds on requested bodies
  1266. if (num_bodies_to_update_bounds > 0)
  1267. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1268. }
  1269. void PhysicsSystem::JobPostIntegrateVelocity(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep) const
  1270. {
  1271. // Validate that our reservations were correct
  1272. JPH_ASSERT(ioStep->mNumCCDBodies <= mBodyManager.GetNumActiveCCDBodies());
  1273. if (ioStep->mNumCCDBodies == 0)
  1274. {
  1275. // No continous collision detection jobs -> kick the next job ourselves
  1276. ioStep->mContactRemovedCallbacks.RemoveDependency();
  1277. }
  1278. else
  1279. {
  1280. // Run the continous collision detection jobs
  1281. int num_continuous_collision_jobs = min(int(ioStep->mNumCCDBodies + cNumCCDBodiesPerJob - 1) / cNumCCDBodiesPerJob, ioContext->GetMaxConcurrency());
  1282. ioStep->mResolveCCDContacts.AddDependency(num_continuous_collision_jobs);
  1283. ioStep->mContactRemovedCallbacks.AddDependency(num_continuous_collision_jobs - 1); // Already had 1 dependency
  1284. for (int i = 0; i < num_continuous_collision_jobs; ++i)
  1285. {
  1286. JobHandle job = ioContext->mJobSystem->CreateJob("FindCCDContacts", cColorFindCCDContacts, [ioContext, ioStep]()
  1287. {
  1288. ioContext->mPhysicsSystem->JobFindCCDContacts(ioContext, ioStep);
  1289. ioStep->mResolveCCDContacts.RemoveDependency();
  1290. ioStep->mContactRemovedCallbacks.RemoveDependency();
  1291. });
  1292. ioContext->mBarrier->AddJob(job);
  1293. }
  1294. }
  1295. }
  1296. // Helper function to calculate the motion of a body during this CCD step
  1297. inline static Vec3 sCalculateBodyMotion(const Body &inBody, float inDeltaTime)
  1298. {
  1299. // If the body is linear casting, the body has not yet moved so we need to calculate its motion
  1300. if (inBody.IsDynamic() && inBody.GetMotionProperties()->GetMotionQuality() == EMotionQuality::LinearCast)
  1301. return inDeltaTime * inBody.GetLinearVelocity();
  1302. // Body has already moved, so we don't need to correct for anything
  1303. return Vec3::sZero();
  1304. }
  1305. // Helper function that finds the CCD body corresponding to a body (if it exists)
  1306. inline static PhysicsUpdateContext::Step::CCDBody *sGetCCDBody(const Body &inBody, PhysicsUpdateContext::Step *inStep)
  1307. {
  1308. // If the body has no motion properties it cannot have a CCD body
  1309. const MotionProperties *motion_properties = inBody.GetMotionPropertiesUnchecked();
  1310. if (motion_properties == nullptr)
  1311. return nullptr;
  1312. // If it is not active it cannot have a CCD body
  1313. uint32 active_index = motion_properties->GetIndexInActiveBodiesInternal();
  1314. if (active_index == Body::cInactiveIndex)
  1315. return nullptr;
  1316. // Check if the active body has a corresponding CCD body
  1317. JPH_ASSERT(active_index < inStep->mNumActiveBodyToCCDBody); // Ensure that the body has a mapping to CCD body
  1318. int ccd_index = inStep->mActiveBodyToCCDBody[active_index];
  1319. if (ccd_index < 0)
  1320. return nullptr;
  1321. PhysicsUpdateContext::Step::CCDBody *ccd_body = &inStep->mCCDBodies[ccd_index];
  1322. JPH_ASSERT(ccd_body->mBodyID1 == inBody.GetID(), "We found the wrong CCD body!");
  1323. return ccd_body;
  1324. }
  1325. void PhysicsSystem::JobFindCCDContacts(const PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1326. {
  1327. #ifdef JPH_ENABLE_ASSERTS
  1328. // We only read positions, but the validate callback may read body positions and velocities
  1329. BodyAccess::Grant grant(BodyAccess::EAccess::Read, BodyAccess::EAccess::Read);
  1330. #endif
  1331. // Allocation context for allocating new contact points
  1332. ContactAllocator contact_allocator(mContactManager.GetContactAllocator());
  1333. // Settings
  1334. ShapeCastSettings settings;
  1335. settings.mUseShrunkenShapeAndConvexRadius = true;
  1336. settings.mBackFaceModeTriangles = EBackFaceMode::IgnoreBackFaces;
  1337. settings.mBackFaceModeConvex = EBackFaceMode::IgnoreBackFaces;
  1338. settings.mReturnDeepestPoint = true;
  1339. settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
  1340. settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
  1341. for (;;)
  1342. {
  1343. // Fetch the next body to cast
  1344. uint32 idx = ioStep->mNextCCDBody++;
  1345. if (idx >= ioStep->mNumCCDBodies)
  1346. break;
  1347. CCDBody &ccd_body = ioStep->mCCDBodies[idx];
  1348. const Body &body = mBodyManager.GetBody(ccd_body.mBodyID1);
  1349. // Filter out layers
  1350. DefaultBroadPhaseLayerFilter broadphase_layer_filter = GetDefaultBroadPhaseLayerFilter(body.GetObjectLayer());
  1351. DefaultObjectLayerFilter object_layer_filter = GetDefaultLayerFilter(body.GetObjectLayer());
  1352. #ifdef JPH_DEBUG_RENDERER
  1353. // Draw start and end shape of cast
  1354. if (sDrawMotionQualityLinearCast)
  1355. {
  1356. RMat44 com = body.GetCenterOfMassTransform();
  1357. body.GetShape()->Draw(DebugRenderer::sInstance, com, Vec3::sReplicate(1.0f), Color::sGreen, false, true);
  1358. DebugRenderer::sInstance->DrawArrow(com.GetTranslation(), com.GetTranslation() + ccd_body.mDeltaPosition, Color::sGreen, 0.1f);
  1359. body.GetShape()->Draw(DebugRenderer::sInstance, com.PostTranslated(ccd_body.mDeltaPosition), Vec3::sReplicate(1.0f), Color::sRed, false, true);
  1360. }
  1361. #endif // JPH_DEBUG_RENDERER
  1362. // Create a collector that will find the maximum distance allowed to travel while not penetrating more than 'max penetration'
  1363. class CCDNarrowPhaseCollector : public CastShapeCollector
  1364. {
  1365. public:
  1366. CCDNarrowPhaseCollector(const BodyManager &inBodyManager, ContactConstraintManager &inContactConstraintManager, CCDBody &inCCDBody, ShapeCastResult &inResult, float inDeltaTime) :
  1367. mBodyManager(inBodyManager),
  1368. mContactConstraintManager(inContactConstraintManager),
  1369. mCCDBody(inCCDBody),
  1370. mResult(inResult),
  1371. mDeltaTime(inDeltaTime)
  1372. {
  1373. }
  1374. virtual void AddHit(const ShapeCastResult &inResult) override
  1375. {
  1376. JPH_PROFILE_FUNCTION();
  1377. // Check if this is a possible earlier hit than the one before
  1378. float fraction = inResult.mFraction;
  1379. if (fraction < mCCDBody.mFractionPlusSlop)
  1380. {
  1381. // Normalize normal
  1382. Vec3 normal = inResult.mPenetrationAxis.Normalized();
  1383. // Calculate how much we can add to the fraction to penetrate the collision point by mMaxPenetration.
  1384. // Note that the normal is pointing towards body 2!
  1385. // Let the extra distance that we can travel along delta_pos be 'dist': mMaxPenetration / dist = cos(angle between normal and delta_pos) = normal . delta_pos / |delta_pos|
  1386. // <=> dist = mMaxPenetration * |delta_pos| / normal . delta_pos
  1387. // Converting to a faction: delta_fraction = dist / |delta_pos| = mLinearCastTreshold / normal . delta_pos
  1388. float denominator = normal.Dot(mCCDBody.mDeltaPosition);
  1389. if (denominator > mCCDBody.mMaxPenetration) // Avoid dividing by zero, if extra hit fraction > 1 there's also no point in continuing
  1390. {
  1391. float fraction_plus_slop = fraction + mCCDBody.mMaxPenetration / denominator;
  1392. if (fraction_plus_slop < mCCDBody.mFractionPlusSlop)
  1393. {
  1394. const Body &body2 = mBodyManager.GetBody(inResult.mBodyID2);
  1395. // Check if we've already accepted all hits from this body
  1396. if (mValidateBodyPair)
  1397. {
  1398. // Validate the contact result
  1399. const Body &body1 = mBodyManager.GetBody(mCCDBody.mBodyID1);
  1400. ValidateResult validate_result = mContactConstraintManager.ValidateContactPoint(body1, body2, body1.GetCenterOfMassPosition(), inResult); // Note that the center of mass of body 1 is the start of the sweep and is used as base offset below
  1401. switch (validate_result)
  1402. {
  1403. case ValidateResult::AcceptContact:
  1404. // Just continue
  1405. break;
  1406. case ValidateResult::AcceptAllContactsForThisBodyPair:
  1407. // Accept this and all following contacts from this body
  1408. mValidateBodyPair = false;
  1409. break;
  1410. case ValidateResult::RejectContact:
  1411. return;
  1412. case ValidateResult::RejectAllContactsForThisBodyPair:
  1413. // Reject this and all following contacts from this body
  1414. mRejectAll = true;
  1415. ForceEarlyOut();
  1416. return;
  1417. }
  1418. }
  1419. // This is the earliest hit so far, store it
  1420. mCCDBody.mContactNormal = normal;
  1421. mCCDBody.mBodyID2 = inResult.mBodyID2;
  1422. mCCDBody.mFraction = fraction;
  1423. mCCDBody.mFractionPlusSlop = fraction_plus_slop;
  1424. mResult = inResult;
  1425. // Result was assuming body 2 is not moving, but it is, so we need to correct for it
  1426. Vec3 movement2 = fraction * sCalculateBodyMotion(body2, mDeltaTime);
  1427. if (!movement2.IsNearZero())
  1428. {
  1429. mResult.mContactPointOn1 += movement2;
  1430. mResult.mContactPointOn2 += movement2;
  1431. for (Vec3 &v : mResult.mShape1Face)
  1432. v += movement2;
  1433. for (Vec3 &v : mResult.mShape2Face)
  1434. v += movement2;
  1435. }
  1436. // Update early out fraction
  1437. UpdateEarlyOutFraction(fraction_plus_slop);
  1438. }
  1439. }
  1440. }
  1441. }
  1442. bool mValidateBodyPair; ///< If we still have to call the ValidateContactPoint for this body pair
  1443. bool mRejectAll; ///< Reject all further contacts between this body pair
  1444. private:
  1445. const BodyManager & mBodyManager;
  1446. ContactConstraintManager & mContactConstraintManager;
  1447. CCDBody & mCCDBody;
  1448. ShapeCastResult & mResult;
  1449. float mDeltaTime;
  1450. BodyID mAcceptedBodyID;
  1451. };
  1452. // Narrowphase collector
  1453. ShapeCastResult cast_shape_result;
  1454. CCDNarrowPhaseCollector np_collector(mBodyManager, mContactManager, ccd_body, cast_shape_result, ioContext->mStepDeltaTime);
  1455. // This collector wraps the narrowphase collector and collects the closest hit
  1456. class CCDBroadPhaseCollector : public CastShapeBodyCollector
  1457. {
  1458. public:
  1459. CCDBroadPhaseCollector(const CCDBody &inCCDBody, const Body &inBody1, const RShapeCast &inShapeCast, ShapeCastSettings &inShapeCastSettings, CCDNarrowPhaseCollector &ioCollector, const BodyManager &inBodyManager, PhysicsUpdateContext::Step *inStep, float inDeltaTime) :
  1460. mCCDBody(inCCDBody),
  1461. mBody1(inBody1),
  1462. mBody1Extent(inShapeCast.mShapeWorldBounds.GetExtent()),
  1463. mShapeCast(inShapeCast),
  1464. mShapeCastSettings(inShapeCastSettings),
  1465. mCollector(ioCollector),
  1466. mBodyManager(inBodyManager),
  1467. mStep(inStep),
  1468. mDeltaTime(inDeltaTime)
  1469. {
  1470. }
  1471. virtual void AddHit(const BroadPhaseCastResult &inResult) override
  1472. {
  1473. JPH_PROFILE_FUNCTION();
  1474. JPH_ASSERT(inResult.mFraction <= GetEarlyOutFraction(), "This hit should not have been passed on to the collector");
  1475. // Test if we're colliding with ourselves
  1476. if (mBody1.GetID() == inResult.mBodyID)
  1477. return;
  1478. // Avoid treating duplicates, if both bodies are doing CCD then only consider collision if body ID < other body ID
  1479. const Body &body2 = mBodyManager.GetBody(inResult.mBodyID);
  1480. const CCDBody *ccd_body2 = sGetCCDBody(body2, mStep);
  1481. if (ccd_body2 != nullptr && mCCDBody.mBodyID1 > ccd_body2->mBodyID1)
  1482. return;
  1483. // Test group filter
  1484. if (!mBody1.GetCollisionGroup().CanCollide(body2.GetCollisionGroup()))
  1485. return;
  1486. // TODO: For now we ignore sensors
  1487. if (body2.IsSensor())
  1488. return;
  1489. // Get relative movement of these two bodies
  1490. Vec3 direction = mShapeCast.mDirection - sCalculateBodyMotion(body2, mDeltaTime);
  1491. // Test if the remaining movement is less than our movement threshold
  1492. if (direction.LengthSq() < mCCDBody.mLinearCastThresholdSq)
  1493. return;
  1494. // Get the bounds of 2, widen it by the extent of 1 and test a ray to see if it hits earlier than the current early out fraction
  1495. AABox bounds = body2.GetWorldSpaceBounds();
  1496. bounds.mMin -= mBody1Extent;
  1497. bounds.mMax += mBody1Extent;
  1498. float hit_fraction = RayAABox(Vec3(mShapeCast.mCenterOfMassStart.GetTranslation()), RayInvDirection(direction), bounds.mMin, bounds.mMax);
  1499. if (hit_fraction > GetPositiveEarlyOutFraction()) // If early out fraction <= 0, we have the possibility of finding a deeper hit so we need to clamp the early out fraction
  1500. return;
  1501. // Reset collector (this is a new body pair)
  1502. mCollector.ResetEarlyOutFraction(GetEarlyOutFraction());
  1503. mCollector.mValidateBodyPair = true;
  1504. mCollector.mRejectAll = false;
  1505. // Provide direction as hint for the active edges algorithm
  1506. mShapeCastSettings.mActiveEdgeMovementDirection = direction;
  1507. // Do narrow phase collision check
  1508. RShapeCast relative_cast(mShapeCast.mShape, mShapeCast.mScale, mShapeCast.mCenterOfMassStart, direction, mShapeCast.mShapeWorldBounds);
  1509. body2.GetTransformedShape().CastShape(relative_cast, mShapeCastSettings, mShapeCast.mCenterOfMassStart.GetTranslation(), mCollector);
  1510. // Update early out fraction based on narrow phase collector
  1511. if (!mCollector.mRejectAll)
  1512. UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
  1513. }
  1514. const CCDBody & mCCDBody;
  1515. const Body & mBody1;
  1516. Vec3 mBody1Extent;
  1517. RShapeCast mShapeCast;
  1518. ShapeCastSettings & mShapeCastSettings;
  1519. CCDNarrowPhaseCollector & mCollector;
  1520. const BodyManager & mBodyManager;
  1521. PhysicsUpdateContext::Step *mStep;
  1522. float mDeltaTime;
  1523. };
  1524. // Check if we collide with any other body. Note that we use the non-locking interface as we know the broadphase cannot be modified at this point.
  1525. RShapeCast shape_cast(body.GetShape(), Vec3::sReplicate(1.0f), body.GetCenterOfMassTransform(), ccd_body.mDeltaPosition);
  1526. CCDBroadPhaseCollector bp_collector(ccd_body, body, shape_cast, settings, np_collector, mBodyManager, ioStep, ioContext->mStepDeltaTime);
  1527. mBroadPhase->CastAABoxNoLock({ shape_cast.mShapeWorldBounds, shape_cast.mDirection }, bp_collector, broadphase_layer_filter, object_layer_filter);
  1528. // Check if there was a hit
  1529. if (ccd_body.mFractionPlusSlop < 1.0f)
  1530. {
  1531. const Body &body2 = mBodyManager.GetBody(ccd_body.mBodyID2);
  1532. // Determine contact manifold
  1533. ContactManifold manifold;
  1534. manifold.mBaseOffset = shape_cast.mCenterOfMassStart.GetTranslation();
  1535. ManifoldBetweenTwoFaces(cast_shape_result.mContactPointOn1, cast_shape_result.mContactPointOn2, cast_shape_result.mPenetrationAxis, mPhysicsSettings.mManifoldToleranceSq, cast_shape_result.mShape1Face, cast_shape_result.mShape2Face, manifold.mRelativeContactPointsOn1, manifold.mRelativeContactPointsOn2 JPH_IF_DEBUG_RENDERER(, manifold.mBaseOffset));
  1536. manifold.mSubShapeID1 = cast_shape_result.mSubShapeID1;
  1537. manifold.mSubShapeID2 = cast_shape_result.mSubShapeID2;
  1538. manifold.mPenetrationDepth = cast_shape_result.mPenetrationDepth;
  1539. manifold.mWorldSpaceNormal = ccd_body.mContactNormal;
  1540. // Call contact point callbacks
  1541. mContactManager.OnCCDContactAdded(contact_allocator, body, body2, manifold, ccd_body.mContactSettings);
  1542. if (ccd_body.mContactSettings.mIsSensor)
  1543. {
  1544. // If this is a sensor, we don't want to solve the contact
  1545. ccd_body.mFractionPlusSlop = 1.0f;
  1546. ccd_body.mBodyID2 = BodyID();
  1547. }
  1548. else
  1549. {
  1550. // Calculate the average position from the manifold (this will result in the same impulse applied as when we apply impulses to all contact points)
  1551. if (manifold.mRelativeContactPointsOn2.size() > 1)
  1552. {
  1553. Vec3 average_contact_point = Vec3::sZero();
  1554. for (const Vec3 &v : manifold.mRelativeContactPointsOn2)
  1555. average_contact_point += v;
  1556. average_contact_point /= (float)manifold.mRelativeContactPointsOn2.size();
  1557. ccd_body.mContactPointOn2 = manifold.mBaseOffset + average_contact_point;
  1558. }
  1559. else
  1560. ccd_body.mContactPointOn2 = manifold.mBaseOffset + cast_shape_result.mContactPointOn2;
  1561. }
  1562. }
  1563. }
  1564. // Collect information from the contact allocator and accumulate it in the step.
  1565. sFinalizeContactAllocator(*ioStep, contact_allocator);
  1566. }
  1567. void PhysicsSystem::JobResolveCCDContacts(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1568. {
  1569. #ifdef JPH_ENABLE_ASSERTS
  1570. // Read/write body access
  1571. BodyAccess::Grant grant(BodyAccess::EAccess::ReadWrite, BodyAccess::EAccess::ReadWrite);
  1572. // We activate bodies that we collide with
  1573. BodyManager::GrantActiveBodiesAccess grant_active(true, false);
  1574. #endif
  1575. uint32 num_active_bodies_after_find_collisions = ioStep->mActiveBodyReadIdx;
  1576. TempAllocator *temp_allocator = ioContext->mTempAllocator;
  1577. // Check if there's anything to do
  1578. uint num_ccd_bodies = ioStep->mNumCCDBodies;
  1579. if (num_ccd_bodies > 0)
  1580. {
  1581. // Sort on fraction so that we process earliest collisions first
  1582. // This is needed to make the simulation deterministic and also to be able to stop contact processing
  1583. // between body pairs if an earlier hit was found involving the body by another CCD body
  1584. // (if it's body ID < this CCD body's body ID - see filtering logic in CCDBroadPhaseCollector)
  1585. CCDBody **sorted_ccd_bodies = (CCDBody **)temp_allocator->Allocate(num_ccd_bodies * sizeof(CCDBody *));
  1586. {
  1587. JPH_PROFILE("Sort");
  1588. // We don't want to copy the entire struct (it's quite big), so we create a pointer array first
  1589. CCDBody *src_ccd_bodies = ioStep->mCCDBodies;
  1590. CCDBody **dst_ccd_bodies = sorted_ccd_bodies;
  1591. CCDBody **dst_ccd_bodies_end = dst_ccd_bodies + num_ccd_bodies;
  1592. while (dst_ccd_bodies < dst_ccd_bodies_end)
  1593. *(dst_ccd_bodies++) = src_ccd_bodies++;
  1594. // Which we then sort
  1595. QuickSort(sorted_ccd_bodies, sorted_ccd_bodies + num_ccd_bodies, [](const CCDBody *inBody1, const CCDBody *inBody2)
  1596. {
  1597. if (inBody1->mFractionPlusSlop != inBody2->mFractionPlusSlop)
  1598. return inBody1->mFractionPlusSlop < inBody2->mFractionPlusSlop;
  1599. return inBody1->mBodyID1 < inBody2->mBodyID1;
  1600. });
  1601. }
  1602. // We can collide with bodies that are not active, we track them here so we can activate them in one go at the end.
  1603. // This is also needed because we can't modify the active body array while we iterate it.
  1604. static constexpr int cBodiesBatch = 64;
  1605. BodyID *bodies_to_activate = (BodyID *)JPH_STACK_ALLOC(cBodiesBatch * sizeof(BodyID));
  1606. int num_bodies_to_activate = 0;
  1607. // We can move bodies that are not part of an island. In this case we need to notify the broadphase of the movement.
  1608. BodyID *bodies_to_update_bounds = (BodyID *)JPH_STACK_ALLOC(cBodiesBatch * sizeof(BodyID));
  1609. int num_bodies_to_update_bounds = 0;
  1610. for (uint i = 0; i < num_ccd_bodies; ++i)
  1611. {
  1612. const CCDBody *ccd_body = sorted_ccd_bodies[i];
  1613. Body &body1 = mBodyManager.GetBody(ccd_body->mBodyID1);
  1614. MotionProperties *body_mp = body1.GetMotionProperties();
  1615. // If there was a hit
  1616. if (!ccd_body->mBodyID2.IsInvalid())
  1617. {
  1618. Body &body2 = mBodyManager.GetBody(ccd_body->mBodyID2);
  1619. // Determine if the other body has a CCD body
  1620. CCDBody *ccd_body2 = sGetCCDBody(body2, ioStep);
  1621. if (ccd_body2 != nullptr)
  1622. {
  1623. JPH_ASSERT(ccd_body2->mBodyID2 != ccd_body->mBodyID1, "If we collided with another body, that other body should have ignored collisions with us!");
  1624. // Check if the other body found a hit that is further away
  1625. if (ccd_body2->mFraction > ccd_body->mFraction)
  1626. {
  1627. // Reset the colliding body of the other CCD body. The other body will shorten its distance travelled and will not do any collision response (we'll do that).
  1628. // This means that at this point we have triggered a contact point add/persist for our further hit by accident for the other body.
  1629. // We accept this as calling the contact point callbacks here would require persisting the manifolds up to this point and doing the callbacks single threaded.
  1630. ccd_body2->mBodyID2 = BodyID();
  1631. ccd_body2->mFractionPlusSlop = ccd_body->mFraction;
  1632. }
  1633. }
  1634. // If the other body moved less than us before hitting something, we're not colliding with it so we again have triggered contact point add/persist callbacks by accident.
  1635. // We'll just move to the collision position anyway (as that's the last position we know is good), but we won't do any collision response.
  1636. if (ccd_body2 == nullptr || ccd_body2->mFraction >= ccd_body->mFraction)
  1637. {
  1638. // Calculate contact points relative to center of mass of both bodies
  1639. Vec3 r1_plus_u = Vec3(ccd_body->mContactPointOn2 - (body1.GetCenterOfMassPosition() + ccd_body->mFraction * ccd_body->mDeltaPosition));
  1640. Vec3 r2 = Vec3(ccd_body->mContactPointOn2 - body2.GetCenterOfMassPosition());
  1641. // Calculate velocity of collision points
  1642. Vec3 v1 = body1.GetPointVelocityCOM(r1_plus_u);
  1643. Vec3 v2 = body2.GetPointVelocityCOM(r2);
  1644. Vec3 relative_velocity = v2 - v1;
  1645. float normal_velocity = relative_velocity.Dot(ccd_body->mContactNormal);
  1646. // Calculate velocity bias due to restitution
  1647. float normal_velocity_bias;
  1648. if (ccd_body->mContactSettings.mCombinedRestitution > 0.0f && normal_velocity < -mPhysicsSettings.mMinVelocityForRestitution)
  1649. normal_velocity_bias = ccd_body->mContactSettings.mCombinedRestitution * normal_velocity;
  1650. else
  1651. normal_velocity_bias = 0.0f;
  1652. // Solve contact constraint
  1653. AxisConstraintPart contact_constraint;
  1654. contact_constraint.CalculateConstraintProperties(body1, r1_plus_u, body2, r2, ccd_body->mContactNormal, normal_velocity_bias);
  1655. contact_constraint.SolveVelocityConstraint(body1, body2, ccd_body->mContactNormal, -FLT_MAX, FLT_MAX);
  1656. // Apply friction
  1657. if (ccd_body->mContactSettings.mCombinedFriction > 0.0f)
  1658. {
  1659. // Calculate friction direction by removing normal velocity from the relative velocity
  1660. Vec3 friction_direction = relative_velocity - normal_velocity * ccd_body->mContactNormal;
  1661. float friction_direction_len_sq = friction_direction.LengthSq();
  1662. if (friction_direction_len_sq > 1.0e-12f)
  1663. {
  1664. // Normalize friction direction
  1665. friction_direction /= sqrt(friction_direction_len_sq);
  1666. // Calculate max friction impulse
  1667. float max_lambda_f = ccd_body->mContactSettings.mCombinedFriction * contact_constraint.GetTotalLambda();
  1668. AxisConstraintPart friction;
  1669. friction.CalculateConstraintProperties(body1, r1_plus_u, body2, r2, friction_direction);
  1670. friction.SolveVelocityConstraint(body1, body2, friction_direction, -max_lambda_f, max_lambda_f);
  1671. }
  1672. }
  1673. // Clamp velocities
  1674. body_mp->ClampLinearVelocity();
  1675. body_mp->ClampAngularVelocity();
  1676. if (body2.IsDynamic())
  1677. {
  1678. MotionProperties *body2_mp = body2.GetMotionProperties();
  1679. body2_mp->ClampLinearVelocity();
  1680. body2_mp->ClampAngularVelocity();
  1681. // Activate the body if it is not already active
  1682. if (!body2.IsActive())
  1683. {
  1684. bodies_to_activate[num_bodies_to_activate++] = ccd_body->mBodyID2;
  1685. if (num_bodies_to_activate == cBodiesBatch)
  1686. {
  1687. // Batch is full, activate now
  1688. mBodyManager.ActivateBodies(bodies_to_activate, num_bodies_to_activate);
  1689. num_bodies_to_activate = 0;
  1690. }
  1691. }
  1692. }
  1693. #ifdef JPH_DEBUG_RENDERER
  1694. if (sDrawMotionQualityLinearCast)
  1695. {
  1696. // Draw the collision location
  1697. RMat44 collision_transform = body1.GetCenterOfMassTransform().PostTranslated(ccd_body->mFraction * ccd_body->mDeltaPosition);
  1698. body1.GetShape()->Draw(DebugRenderer::sInstance, collision_transform, Vec3::sReplicate(1.0f), Color::sYellow, false, true);
  1699. // Draw the collision location + slop
  1700. RMat44 collision_transform_plus_slop = body1.GetCenterOfMassTransform().PostTranslated(ccd_body->mFractionPlusSlop * ccd_body->mDeltaPosition);
  1701. body1.GetShape()->Draw(DebugRenderer::sInstance, collision_transform_plus_slop, Vec3::sReplicate(1.0f), Color::sOrange, false, true);
  1702. // Draw contact normal
  1703. DebugRenderer::sInstance->DrawArrow(ccd_body->mContactPointOn2, ccd_body->mContactPointOn2 - ccd_body->mContactNormal, Color::sYellow, 0.1f);
  1704. // Draw post contact velocity
  1705. DebugRenderer::sInstance->DrawArrow(collision_transform.GetTranslation(), collision_transform.GetTranslation() + body1.GetLinearVelocity(), Color::sOrange, 0.1f);
  1706. DebugRenderer::sInstance->DrawArrow(collision_transform.GetTranslation(), collision_transform.GetTranslation() + body1.GetAngularVelocity(), Color::sPurple, 0.1f);
  1707. }
  1708. #endif // JPH_DEBUG_RENDERER
  1709. }
  1710. }
  1711. // Update body position
  1712. body1.AddPositionStep(ccd_body->mDeltaPosition * ccd_body->mFractionPlusSlop);
  1713. // If the body was activated due to an earlier CCD step it will have an index in the active
  1714. // body list that it higher than the highest one we processed during FindCollisions
  1715. // which means it hasn't been assigned an island and will not be updated by an island
  1716. // this means that we need to update its bounds manually
  1717. if (body_mp->GetIndexInActiveBodiesInternal() >= num_active_bodies_after_find_collisions)
  1718. {
  1719. body1.CalculateWorldSpaceBoundsInternal();
  1720. bodies_to_update_bounds[num_bodies_to_update_bounds++] = body1.GetID();
  1721. if (num_bodies_to_update_bounds == cBodiesBatch)
  1722. {
  1723. // Buffer full, flush now
  1724. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1725. num_bodies_to_update_bounds = 0;
  1726. }
  1727. }
  1728. }
  1729. // Activate the requested bodies
  1730. if (num_bodies_to_activate > 0)
  1731. mBodyManager.ActivateBodies(bodies_to_activate, num_bodies_to_activate);
  1732. // Notify change bounds on requested bodies
  1733. if (num_bodies_to_update_bounds > 0)
  1734. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1735. // Free the sorted ccd bodies
  1736. temp_allocator->Free(sorted_ccd_bodies, num_ccd_bodies * sizeof(CCDBody *));
  1737. }
  1738. // Ensure we free the CCD bodies array now, will not call the destructor!
  1739. temp_allocator->Free(ioStep->mActiveBodyToCCDBody, ioStep->mNumActiveBodyToCCDBody * sizeof(int));
  1740. ioStep->mActiveBodyToCCDBody = nullptr;
  1741. ioStep->mNumActiveBodyToCCDBody = 0;
  1742. temp_allocator->Free(ioStep->mCCDBodies, ioStep->mCCDBodiesCapacity * sizeof(CCDBody));
  1743. ioStep->mCCDBodies = nullptr;
  1744. ioStep->mCCDBodiesCapacity = 0;
  1745. }
  1746. void PhysicsSystem::JobContactRemovedCallbacks(const PhysicsUpdateContext::Step *ioStep)
  1747. {
  1748. #ifdef JPH_ENABLE_ASSERTS
  1749. // We don't touch any bodies
  1750. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::None);
  1751. #endif
  1752. // Reset the Body::EFlags::InvalidateContactCache flag for all bodies
  1753. mBodyManager.ValidateContactCacheForAllBodies();
  1754. // Finalize the contact cache (this swaps the read and write versions of the contact cache)
  1755. // Trigger all contact removed callbacks by looking at last step contact points that have not been flagged as reused
  1756. mContactManager.FinalizeContactCacheAndCallContactPointRemovedCallbacks(ioStep->mNumBodyPairs, ioStep->mNumManifolds);
  1757. }
  1758. class PhysicsSystem::BodiesToSleep : public NonCopyable
  1759. {
  1760. public:
  1761. static constexpr int cBodiesToSleepSize = 512;
  1762. static constexpr int cMaxBodiesToPutInBuffer = 128;
  1763. inline BodiesToSleep(BodyManager &inBodyManager, BodyID *inBodiesToSleepBuffer) : mBodyManager(inBodyManager), mBodiesToSleepBuffer(inBodiesToSleepBuffer), mBodiesToSleepCur(inBodiesToSleepBuffer) { }
  1764. inline ~BodiesToSleep()
  1765. {
  1766. // Flush the bodies to sleep buffer
  1767. int num_bodies_in_buffer = int(mBodiesToSleepCur - mBodiesToSleepBuffer);
  1768. if (num_bodies_in_buffer > 0)
  1769. mBodyManager.DeactivateBodies(mBodiesToSleepBuffer, num_bodies_in_buffer);
  1770. }
  1771. inline void PutToSleep(const BodyID *inBegin, const BodyID *inEnd)
  1772. {
  1773. int num_bodies_to_sleep = int(inEnd - inBegin);
  1774. if (num_bodies_to_sleep > cMaxBodiesToPutInBuffer)
  1775. {
  1776. // Too many bodies, deactivate immediately
  1777. mBodyManager.DeactivateBodies(inBegin, num_bodies_to_sleep);
  1778. }
  1779. else
  1780. {
  1781. // Check if there's enough space in the bodies to sleep buffer
  1782. int num_bodies_in_buffer = int(mBodiesToSleepCur - mBodiesToSleepBuffer);
  1783. if (num_bodies_in_buffer + num_bodies_to_sleep > cBodiesToSleepSize)
  1784. {
  1785. // Flush the bodies to sleep buffer
  1786. mBodyManager.DeactivateBodies(mBodiesToSleepBuffer, num_bodies_in_buffer);
  1787. mBodiesToSleepCur = mBodiesToSleepBuffer;
  1788. }
  1789. // Copy the bodies in the buffer
  1790. memcpy(mBodiesToSleepCur, inBegin, num_bodies_to_sleep * sizeof(BodyID));
  1791. mBodiesToSleepCur += num_bodies_to_sleep;
  1792. }
  1793. }
  1794. private:
  1795. BodyManager & mBodyManager;
  1796. BodyID * mBodiesToSleepBuffer;
  1797. BodyID * mBodiesToSleepCur;
  1798. };
  1799. void PhysicsSystem::CheckSleepAndUpdateBounds(uint32 inIslandIndex, const PhysicsUpdateContext *ioContext, const PhysicsUpdateContext::Step *ioStep, BodiesToSleep &ioBodiesToSleep)
  1800. {
  1801. // Get the bodies that belong to this island
  1802. BodyID *bodies_begin, *bodies_end;
  1803. mIslandBuilder.GetBodiesInIsland(inIslandIndex, bodies_begin, bodies_end);
  1804. // Only check sleeping in the last step
  1805. // Also resets force and torque used during the apply gravity phase
  1806. if (ioStep->mIsLast)
  1807. {
  1808. JPH_PROFILE("Check Sleeping");
  1809. static_assert(int(Body::ECanSleep::CannotSleep) == 0 && int(Body::ECanSleep::CanSleep) == 1, "Loop below makes this assumption");
  1810. int all_can_sleep = mPhysicsSettings.mAllowSleeping? int(Body::ECanSleep::CanSleep) : int(Body::ECanSleep::CannotSleep);
  1811. float time_before_sleep = mPhysicsSettings.mTimeBeforeSleep;
  1812. float max_movement = mPhysicsSettings.mPointVelocitySleepThreshold * time_before_sleep;
  1813. for (const BodyID *body_id = bodies_begin; body_id < bodies_end; ++body_id)
  1814. {
  1815. Body &body = mBodyManager.GetBody(*body_id);
  1816. // Update bounding box
  1817. body.CalculateWorldSpaceBoundsInternal();
  1818. // Update sleeping
  1819. all_can_sleep &= int(body.UpdateSleepStateInternal(ioContext->mStepDeltaTime, max_movement, time_before_sleep));
  1820. // Reset force and torque
  1821. MotionProperties *mp = body.GetMotionProperties();
  1822. mp->ResetForce();
  1823. mp->ResetTorque();
  1824. }
  1825. // If all bodies indicate they can sleep we can deactivate them
  1826. if (all_can_sleep == int(Body::ECanSleep::CanSleep))
  1827. ioBodiesToSleep.PutToSleep(bodies_begin, bodies_end);
  1828. }
  1829. else
  1830. {
  1831. JPH_PROFILE("Update Bounds");
  1832. // Update bounding box only for all other steps
  1833. for (const BodyID *body_id = bodies_begin; body_id < bodies_end; ++body_id)
  1834. {
  1835. Body &body = mBodyManager.GetBody(*body_id);
  1836. body.CalculateWorldSpaceBoundsInternal();
  1837. }
  1838. }
  1839. // Notify broadphase of changed objects (find ccd contacts can do linear casts in the next step, so we need to do this every step)
  1840. // Note: Shuffles the BodyID's around!!!
  1841. mBroadPhase->NotifyBodiesAABBChanged(bodies_begin, int(bodies_end - bodies_begin), false);
  1842. }
  1843. void PhysicsSystem::JobSolvePositionConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep)
  1844. {
  1845. #ifdef JPH_ENABLE_ASSERTS
  1846. // We fix up position errors
  1847. BodyAccess::Grant grant(BodyAccess::EAccess::None, BodyAccess::EAccess::ReadWrite);
  1848. // Can only deactivate bodies
  1849. BodyManager::GrantActiveBodiesAccess grant_active(false, true);
  1850. #endif
  1851. float delta_time = ioContext->mStepDeltaTime;
  1852. float baumgarte = mPhysicsSettings.mBaumgarte;
  1853. Constraint **active_constraints = ioContext->mActiveConstraints;
  1854. // Keep a buffer of bodies that need to go to sleep in order to not constantly lock the active bodies mutex and create contention between all solving threads
  1855. BodiesToSleep bodies_to_sleep(mBodyManager, (BodyID *)JPH_STACK_ALLOC(BodiesToSleep::cBodiesToSleepSize * sizeof(BodyID)));
  1856. bool check_islands = true, check_split_islands = mPhysicsSettings.mUseLargeIslandSplitter;
  1857. do
  1858. {
  1859. // First try to get work from large islands
  1860. if (check_split_islands)
  1861. {
  1862. bool first_iteration;
  1863. uint split_island_index;
  1864. uint32 *constraints_begin, *constraints_end, *contacts_begin, *contacts_end;
  1865. switch (mLargeIslandSplitter.FetchNextBatch(split_island_index, constraints_begin, constraints_end, contacts_begin, contacts_end, first_iteration))
  1866. {
  1867. case LargeIslandSplitter::EStatus::BatchRetrieved:
  1868. // Solve the batch
  1869. ConstraintManager::sSolvePositionConstraints(active_constraints, constraints_begin, constraints_end, delta_time, baumgarte);
  1870. mContactManager.SolvePositionConstraints(contacts_begin, contacts_end);
  1871. // Mark the batch as processed
  1872. bool last_iteration, final_batch;
  1873. mLargeIslandSplitter.MarkBatchProcessed(split_island_index, constraints_begin, constraints_end, contacts_begin, contacts_end, last_iteration, final_batch);
  1874. // The final batch will update all bounds and check sleeping
  1875. if (final_batch)
  1876. CheckSleepAndUpdateBounds(mLargeIslandSplitter.GetIslandIndex(split_island_index), ioContext, ioStep, bodies_to_sleep);
  1877. // We processed work, loop again
  1878. continue;
  1879. case LargeIslandSplitter::EStatus::WaitingForBatch:
  1880. break;
  1881. case LargeIslandSplitter::EStatus::AllBatchesDone:
  1882. check_split_islands = false;
  1883. break;
  1884. }
  1885. }
  1886. // If that didn't succeed try to process an island
  1887. if (check_islands)
  1888. {
  1889. // Next island
  1890. uint32 island_idx = ioStep->mSolvePositionConstraintsNextIsland++;
  1891. if (island_idx >= mIslandBuilder.GetNumIslands())
  1892. {
  1893. // We processed all islands, stop checking islands
  1894. check_islands = false;
  1895. continue;
  1896. }
  1897. JPH_PROFILE("Island");
  1898. // Get iterators for this island
  1899. uint32 *constraints_begin, *constraints_end, *contacts_begin, *contacts_end;
  1900. mIslandBuilder.GetConstraintsInIsland(island_idx, constraints_begin, constraints_end);
  1901. mIslandBuilder.GetContactsInIsland(island_idx, contacts_begin, contacts_end);
  1902. // If this island is a large island, it will be picked up as a batch and we don't need to do anything here
  1903. uint num_items = uint(constraints_end - constraints_begin) + uint(contacts_end - contacts_begin);
  1904. if (mPhysicsSettings.mUseLargeIslandSplitter
  1905. && num_items >= LargeIslandSplitter::cLargeIslandTreshold)
  1906. continue;
  1907. // Check if this island needs solving
  1908. if (num_items > 0)
  1909. {
  1910. // First iteration
  1911. int num_position_steps = mPhysicsSettings.mNumPositionSteps;
  1912. if (num_position_steps > 0)
  1913. {
  1914. // In the first iteration also calculate the number of position steps (this way we avoid pulling all constraints into the cache twice)
  1915. bool applied_impulse = ConstraintManager::sSolvePositionConstraints(active_constraints, constraints_begin, constraints_end, delta_time, baumgarte, num_position_steps);
  1916. applied_impulse |= mContactManager.SolvePositionConstraints(contacts_begin, contacts_end);
  1917. // If no impulses were applied we can stop, otherwise we already did 1 iteration
  1918. if (!applied_impulse)
  1919. num_position_steps = 0;
  1920. else
  1921. --num_position_steps;
  1922. }
  1923. else
  1924. {
  1925. // Iterate the constraints to see if they override the number of position steps
  1926. for (const uint32 *c = constraints_begin; c < constraints_end; ++c)
  1927. num_position_steps = max(num_position_steps, active_constraints[*c]->GetNumPositionStepsOverride());
  1928. }
  1929. // Further iterations
  1930. for (int position_step = 0; position_step < num_position_steps; ++position_step)
  1931. {
  1932. bool applied_impulse = ConstraintManager::sSolvePositionConstraints(active_constraints, constraints_begin, constraints_end, delta_time, baumgarte);
  1933. applied_impulse |= mContactManager.SolvePositionConstraints(contacts_begin, contacts_end);
  1934. if (!applied_impulse)
  1935. break;
  1936. }
  1937. }
  1938. // After solving we will update all bounds and check sleeping
  1939. CheckSleepAndUpdateBounds(island_idx, ioContext, ioStep, bodies_to_sleep);
  1940. // We processed work, loop again
  1941. continue;
  1942. }
  1943. // If we didn't find any work, give up a time slice
  1944. std::this_thread::yield();
  1945. }
  1946. while (check_islands || check_split_islands);
  1947. }
  1948. void PhysicsSystem::JobUpdateSoftBodies(const PhysicsUpdateContext *ioContext)
  1949. {
  1950. JPH_PROFILE_FUNCTION();
  1951. #ifdef JPH_ENABLE_ASSERTS
  1952. // Can activate bodies only
  1953. BodyManager::GrantActiveBodiesAccess grant_active(true, false);
  1954. #endif
  1955. static constexpr int cBodiesBatch = 64;
  1956. BodyID *bodies_to_update_bounds = (BodyID *)JPH_STACK_ALLOC(cBodiesBatch * sizeof(BodyID));
  1957. int num_bodies_to_update_bounds = 0;
  1958. // Loop through active bodies
  1959. const BodyID *active_bodies = mBodyManager.GetActiveBodiesUnsafe(EBodyType::SoftBody);
  1960. const BodyID *active_bodies_end = active_bodies + mBodyManager.GetNumActiveBodies(EBodyType::SoftBody);
  1961. for (const BodyID *b = active_bodies; b < active_bodies_end; ++b)
  1962. {
  1963. Body &body = mBodyManager.GetBody(*b);
  1964. SoftBodyMotionProperties *mp = static_cast<SoftBodyMotionProperties *>(body.GetMotionProperties());
  1965. // Update the soft body
  1966. Vec3 delta_position;
  1967. mp->Update(ioContext->mStepDeltaTime, body, delta_position, *this);
  1968. body.SetPositionAndRotationInternal(body.GetPosition() + delta_position, body.GetRotation());
  1969. bodies_to_update_bounds[num_bodies_to_update_bounds++] = *b;
  1970. if (num_bodies_to_update_bounds == cBodiesBatch)
  1971. {
  1972. // Buffer full, flush now
  1973. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1974. num_bodies_to_update_bounds = 0;
  1975. }
  1976. }
  1977. // Notify change bounds on requested bodies
  1978. if (num_bodies_to_update_bounds > 0)
  1979. mBroadPhase->NotifyBodiesAABBChanged(bodies_to_update_bounds, num_bodies_to_update_bounds, false);
  1980. }
  1981. void PhysicsSystem::SaveState(StateRecorder &inStream) const
  1982. {
  1983. JPH_PROFILE_FUNCTION();
  1984. inStream.Write(mPreviousStepDeltaTime);
  1985. inStream.Write(mGravity);
  1986. mBodyManager.SaveState(inStream);
  1987. mContactManager.SaveState(inStream);
  1988. mConstraintManager.SaveState(inStream);
  1989. }
  1990. bool PhysicsSystem::RestoreState(StateRecorder &inStream)
  1991. {
  1992. JPH_PROFILE_FUNCTION();
  1993. inStream.Read(mPreviousStepDeltaTime);
  1994. inStream.Read(mGravity);
  1995. if (!mBodyManager.RestoreState(inStream))
  1996. return false;
  1997. if (!mContactManager.RestoreState(inStream))
  1998. return false;
  1999. if (!mConstraintManager.RestoreState(inStream))
  2000. return false;
  2001. // Update bounding boxes for all bodies in the broadphase
  2002. Array<BodyID> bodies;
  2003. for (const Body *b : mBodyManager.GetBodies())
  2004. if (BodyManager::sIsValidBodyPointer(b) && b->IsInBroadPhase())
  2005. bodies.push_back(b->GetID());
  2006. if (!bodies.empty())
  2007. mBroadPhase->NotifyBodiesAABBChanged(&bodies[0], (int)bodies.size());
  2008. return true;
  2009. }
  2010. JPH_NAMESPACE_END