PhysicsSystem.cpp 123 KB

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