PhysicsSystem.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Physics/Body/BodyInterface.h>
  5. #include <Physics/Collision/NarrowPhaseQuery.h>
  6. #include <Physics/Collision/ContactListener.h>
  7. #include <Physics/Constraints/ContactConstraintManager.h>
  8. #include <Physics/Constraints/ConstraintManager.h>
  9. #include <Physics/IslandBuilder.h>
  10. #include <Physics/PhysicsUpdateContext.h>
  11. namespace JPH {
  12. class JobSystem;
  13. class StateRecorder;
  14. class TempAllocator;
  15. class PhysicsStepListener;
  16. /// The main class for the physics system. It contains all rigid bodies and simulates them.
  17. ///
  18. /// The main simulation is performed by the Update() call on multiple threads (if the JobSystem is configured to use them). Please refer to the general architecture overview in the Docs folder for more information.
  19. class PhysicsSystem : public NonCopyable
  20. {
  21. public:
  22. /// Constructor / Destructor
  23. PhysicsSystem() : mContactManager(mPhysicsSettings) { }
  24. ~PhysicsSystem();
  25. /// Initialize the system.
  26. /// @param inMaxBodies Maximum number of bodies to support.
  27. /// @param inMaxBodyPairs Maximum amount of body pairs to process (anything else will fall through the world), this number should generally be much higher than the max amount of contact points as there will be lots of bodies close that are not actually touching
  28. /// @param inMaxContactConstraints Maximum amount of contact constraints to process (anything else will fall through the world)
  29. /// @param inObjectToBroadPhaseLayer Maps object layer to broadphase layer, @see ObjectToBroadPhaseLayer.
  30. /// @param inObjectLayerPairFilter Filter callback function that is used to determine if two object layers collide.
  31. void Init(uint inMaxBodies, uint inMaxBodyPairs, uint inMaxContactConstraints, const ObjectToBroadPhaseLayer &inObjectToBroadPhaseLayer, BroadPhaseLayerPairFilter inBroadPhaseLayerPairFilter, ObjectLayerPairFilter inObjectLayerPairFilter);
  32. /// Listener that is notified whenever a body is activated/deactivated
  33. void SetBodyActivationListener(BodyActivationListener *inListener) { mBodyManager.SetBodyActivationListener(inListener); }
  34. BodyActivationListener * GetBodyActivationListener() const { return mBodyManager.GetBodyActivationListener(); }
  35. /// Listener that is notified whenever a contact point between two bodies is added/updated/removed
  36. void SetContactListener(ContactListener *inListener) { mContactManager.SetContactListener(inListener); }
  37. ContactListener * GetContactListener() const { return mContactManager.GetContactListener(); }
  38. /// Set the function that combines the friction of two bodies and returns it
  39. /// Default method is the geometric mean: sqrt(friction1 * friction2).
  40. void SetCombineFriction(ContactConstraintManager::CombineFunction inCombineFriction) { mContactManager.SetCombineFriction(inCombineFriction); }
  41. /// Set the function that combines the restitution of two bodies and returns it
  42. /// Default method is max(restitution1, restitution1)
  43. void SetCombineRestitution(ContactConstraintManager::CombineFunction inCombineRestition) { mContactManager.SetCombineRestitution(inCombineRestition); }
  44. /// Control the main constants of the physics simulation
  45. void SetPhysicsSettings(const PhysicsSettings &inSettings) { mPhysicsSettings = inSettings; }
  46. const PhysicsSettings & GetPhysicsSettings() const { return mPhysicsSettings; }
  47. /// Access to the body interface. This interface allows to to create / remove bodies and to change their properties.
  48. BodyInterface & GetBodyInterface() { return mBodyInterfaceLocking; }
  49. BodyInterface & GetBodyInterfaceNoLock() { return mBodyInterfaceNoLock; } ///< Version that does not lock the bodies, use with great care!
  50. /// Access to the broadphase interface that allows coarse collision queries
  51. const BroadPhaseQuery & GetBroadPhaseQuery() const { return *mBroadPhase; }
  52. /// Interface that allows fine collision queries against first the broad phase and then the narrow phase.
  53. const NarrowPhaseQuery & GetNarrowPhaseQuery() const { return mNarrowPhaseQueryLocking; }
  54. const NarrowPhaseQuery & GetNarrowPhaseQueryNoLock() const { return mNarrowPhaseQueryNoLock; } ///< Version that does not lock the bodies, use with great care!
  55. /// Add constraint to the world
  56. void AddConstraint(Constraint *inConstraint) { mConstraintManager.Add(&inConstraint, 1); }
  57. /// Remove constraint from the world
  58. void RemoveConstraint(Constraint *inConstraint) { mConstraintManager.Remove(&inConstraint, 1); }
  59. /// Batch add constraints. Note that the inConstraints array is allowed to have nullptrs, these will be ignored.
  60. void AddConstraints(Constraint **inConstraints, int inNumber) { mConstraintManager.Add(inConstraints, inNumber); }
  61. /// Batch remove constraints. Note that the inConstraints array is allowed to have nullptrs, these will be ignored.
  62. void RemoveConstraints(Constraint **inConstraints, int inNumber) { mConstraintManager.Remove(inConstraints, inNumber); }
  63. /// Optimize the broadphase, needed only if you've added many bodies prior to calling Update() for the first time.
  64. void OptimizeBroadPhase();
  65. /// Adds a new step listener
  66. void AddStepListener(PhysicsStepListener *inListener);
  67. /// Removes a step listener
  68. void RemoveStepListener(PhysicsStepListener *inListener);
  69. /// Simulate the system.
  70. /// The world steps for a total of inDeltaTime seconds. This is divided in inCollisionSteps iterations. Each iteration
  71. /// consists of collision detection followed by inIntegrationSubSteps integration steps.
  72. void Update(float inDeltaTime, int inCollisionSteps, int inIntegrationSubSteps, TempAllocator *inTempAllocator, JobSystem *inJobSystem);
  73. #ifdef JPH_STAT_COLLECTOR
  74. /// Collect stats of the previous time step
  75. void CollectStats();
  76. #endif // JPH_STAT_COLLECTOR
  77. /// Saving state for replay
  78. void SaveState(StateRecorder &inStream) const;
  79. /// Restoring state for replay. Returns false if failed.
  80. bool RestoreState(StateRecorder &inStream);
  81. #ifdef JPH_DEBUG_RENDERER
  82. // Drawing properties
  83. static bool sDrawMotionQualityLinearCast; ///< Draw debug info for objects that perform continuous collision detection through the linear cast motion quality
  84. /// Draw the state of the bodies (debugging purposes)
  85. void DrawBodies(const BodyManager::DrawSettings &inSettings, DebugRenderer *inRenderer) { mBodyManager.Draw(inSettings, mPhysicsSettings, inRenderer); }
  86. /// Draw the constraints only (debugging purposes)
  87. void DrawConstraints(DebugRenderer *inRenderer) { mConstraintManager.DrawConstraints(inRenderer); }
  88. /// Draw the constraint limits only (debugging purposes)
  89. void DrawConstraintLimits(DebugRenderer *inRenderer) { mConstraintManager.DrawConstraintLimits(inRenderer); }
  90. /// Draw the constraint reference frames only (debugging purposes)
  91. void DrawConstraintReferenceFrame(DebugRenderer *inRenderer) { mConstraintManager.DrawConstraintReferenceFrame(inRenderer); }
  92. #endif // JPH_DEBUG_RENDERER
  93. /// Set gravity value
  94. void SetGravity(Vec3Arg inGravity) { mGravity = inGravity; }
  95. Vec3 GetGravity() const { return mGravity; }
  96. /// Returns a locking interface that won't actually lock the body. Use with great care!
  97. inline const BodyLockInterfaceNoLock & GetBodyLockInterfaceNoLock() const { return mBodyLockInterfaceNoLock; }
  98. /// Returns a locking interface that locks the body so other threads cannot modify it.
  99. inline const BodyLockInterfaceLocking & GetBodyLockInterface() const { return mBodyLockInterfaceLocking; }
  100. /// Get an broadphase layer filter that uses the default pair filter and a specified object layer to determine if broadphase layers collide
  101. DefaultBroadPhaseLayerFilter GetDefaultBroadPhaseLayerFilter(ObjectLayer inLayer) const { return DefaultBroadPhaseLayerFilter(mBroadPhaseLayerPairFilter, mObjectToBroadPhaseLayer[inLayer]); }
  102. /// Get an object layer filter that uses the default pair filter and a specified layer to determine if layers collide
  103. DefaultObjectLayerFilter GetDefaultLayerFilter(ObjectLayer inLayer) const { return DefaultObjectLayerFilter(mObjectLayerPairFilter, inLayer); }
  104. /// Gets the current amount of bodies that are in the body manager
  105. uint GetNumBodies() const { return mBodyManager.GetNumBodies(); }
  106. /// Gets the current amount of active bodies that are in the body manager
  107. uint32 GetNumActiveBodies() const { return mBodyManager.GetNumActiveBodies(); }
  108. /// Get the maximum amount of bodies that this physics system supports
  109. uint GetMaxBodies() const { return mBodyManager.GetMaxBodies(); }
  110. /// Helper struct that counts the number of bodies of each type
  111. using BodyStats = BodyManager::BodyStats;
  112. /// Get stats about the bodies in the body manager (slow, iterates through all bodies)
  113. BodyStats GetBodyStats() const { return mBodyManager.GetBodyStats(); }
  114. /// Get copy of the list of all bodies under protection of a lock.
  115. /// @param outBodyIDs On return, this will contain the list of BodyIDs
  116. void GetBodies(BodyIDVector &outBodyIDs) const { return mBodyManager.GetBodyIDs(outBodyIDs); }
  117. /// Get copy of the list of active bodies under protection of a lock.
  118. /// @param outBodyIDs On return, this will contain the list of BodyIDs
  119. void GetActiveBodies(BodyIDVector &outBodyIDs) const { return mBodyManager.GetActiveBodies(outBodyIDs); }
  120. private:
  121. using CCDBody = PhysicsUpdateContext::SubStep::CCDBody;
  122. // Various job entry points
  123. void JobStepListeners(PhysicsUpdateContext::Step *ioStep);
  124. void JobDetermineActiveConstraints(PhysicsUpdateContext::Step *ioStep);
  125. void JobApplyGravity(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep);
  126. void JobSetupVelocityConstraints(float inDeltaTime, PhysicsUpdateContext::Step *ioStep);
  127. void JobBuildIslandsFromConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::Step *ioStep);
  128. void JobFindCollisions(PhysicsUpdateContext::Step *ioStep, int inJobIndex);
  129. void JobFinalizeIslands(PhysicsUpdateContext *ioContext);
  130. void JobBodySetIslandIndex(PhysicsUpdateContext *ioContext);
  131. void JobSolveVelocityConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::SubStep *ioSubStep);
  132. void JobIntegrateVelocity(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::SubStep *ioSubStep);
  133. void JobFindCCDContacts(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::SubStep *ioSubStep);
  134. void JobResolveCCDContacts(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::SubStep *ioSubStep);
  135. void JobContactRemovedCallbacks();
  136. void JobSolvePositionConstraints(PhysicsUpdateContext *ioContext, PhysicsUpdateContext::SubStep *ioSubStep);
  137. /// Tries to spawn a new FindCollisions job if max concurrency hasn't been reached yet
  138. void TrySpawnJobFindCollisions(PhysicsUpdateContext::Step *ioStep);
  139. /// Process narrow phase for a single body pair
  140. void ProcessBodyPair(const BodyPair &inBodyPair);
  141. /// Number of constraints to process at once in JobDetermineActiveConstraints
  142. static constexpr int cDetermineActiveConstraintsBatchSize = 64;
  143. /// Number of bodies to process at once in JobApplyGravity
  144. static constexpr int cApplyGravityBatchSize = 64;
  145. /// Number of active bodies to test for collisions per batch
  146. static constexpr int cActiveBodiesBatchSize = 16;
  147. /// Number of contacts that need to be queued before another narrow phase job is started
  148. static constexpr int cNarrowPhaseBatchSize = 16;
  149. /// Number of continuous collision shape casts that need to be queued before another job is started
  150. static constexpr int cNumCCDBodiesPerJob = 4;
  151. /// Mapping table that maps from Object Layer to tree
  152. ObjectToBroadPhaseLayer mObjectToBroadPhaseLayer;
  153. /// Broadphase layer filter that decides if two objects can collide
  154. BroadPhaseLayerPairFilter mBroadPhaseLayerPairFilter = nullptr;
  155. /// Object layer filter that decides if two objects can collide
  156. ObjectLayerPairFilter mObjectLayerPairFilter = nullptr;
  157. /// The body manager keeps track which bodies are in the simulation
  158. BodyManager mBodyManager;
  159. /// Body locking interfaces
  160. BodyLockInterfaceNoLock mBodyLockInterfaceNoLock { mBodyManager };
  161. BodyLockInterfaceLocking mBodyLockInterfaceLocking { mBodyManager };
  162. /// Body interfaces
  163. BodyInterface mBodyInterfaceNoLock;
  164. BodyInterface mBodyInterfaceLocking;
  165. /// Narrow phase query interface
  166. NarrowPhaseQuery mNarrowPhaseQueryNoLock;
  167. NarrowPhaseQuery mNarrowPhaseQueryLocking;
  168. /// The broadphase does quick collision detection between body pairs
  169. BroadPhase * mBroadPhase = nullptr;
  170. /// The contact manager resolves all contacts during a simulation step
  171. ContactConstraintManager mContactManager;
  172. /// All non-contact constraints
  173. ConstraintManager mConstraintManager;
  174. /// Keeps track of connected bodies and builds islands for multithreaded velocity/position update
  175. IslandBuilder mIslandBuilder;
  176. /// Mutex protecting mStepListeners
  177. Mutex mStepListenersMutex;
  178. /// List of physics step listeners
  179. using StepListeners = vector<PhysicsStepListener *>;
  180. StepListeners mStepListeners;
  181. /// This is the global gravity vector
  182. Vec3 mGravity = Vec3(0, -9.81f, 0);
  183. /// Previous frame's delta time of one sub step to allow scaling previous frame's constraint impulses
  184. float mPreviousSubStepDeltaTime = 0.0f;
  185. /// Simulation settings
  186. PhysicsSettings mPhysicsSettings;
  187. #ifdef JPH_STAT_COLLECTOR
  188. /// Statistics
  189. alignas(JPH_CACHE_LINE_SIZE) atomic<int> mManifoldsBeforeReduction { 0 };
  190. alignas(JPH_CACHE_LINE_SIZE) atomic<int> mManifoldsAfterReduction { 0 };
  191. #endif // JPH_STAT_COLLECTOR
  192. };
  193. } // JPH