Body.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Core/NonCopyable.h>
  5. #include <Geometry/AABox.h>
  6. #include <Physics/Collision/Shape/Shape.h>
  7. #include <Physics/Collision/BroadPhase/BroadPhaseLayer.h>
  8. #include <Physics/Collision/ObjectLayer.h>
  9. #include <Physics/Collision/CollisionGroup.h>
  10. #include <Physics/Collision/TransformedShape.h>
  11. #include <Physics/Body/MotionProperties.h>
  12. #include <Physics/Body/BodyID.h>
  13. #include <Physics/Body/BodyAccess.h>
  14. #include <Core/StringTools.h>
  15. namespace JPH {
  16. class StateRecorder;
  17. class BodyCreationSettings;
  18. /// A rigid body that can be simulated using the physics system
  19. ///
  20. /// Note that internally all properties (position, velocity etc.) are tracked relative to the center of mass of the object to simplify the simulation of the object.
  21. ///
  22. /// The offset between the position of the body and the center of mass position of the body is GetShape()->GetCenterOfMass().
  23. /// The functions that get/set the position of the body all indicate if they are relative to the center of mass or to the original position in which the shape was created.
  24. ///
  25. /// The linear velocity is also velocity of the center of mass, to correct for this: \f$VelocityCOM = Velocity - AngularVelocity \times ShapeCOM\f$.
  26. class Body : public NonCopyable
  27. {
  28. public:
  29. /// Default constructor
  30. Body() = default;
  31. /// Destructor
  32. ~Body() { JPH_ASSERT(mMotionProperties == nullptr); }
  33. #ifdef _DEBUG
  34. /// Name of the body for debugging purposes
  35. void SetDebugName(const string &inName) { mDebugName = inName; }
  36. string GetDebugName() const;
  37. #else
  38. string GetDebugName() const { return ConvertToString(mID.GetIndex()); }
  39. #endif
  40. /// Get the id of this body
  41. inline const BodyID & GetID() const { return mID; }
  42. /// If this body is currently actively simulating (true) or sleeping (false)
  43. inline bool IsActive() const { return mMotionProperties != nullptr && mMotionProperties->mIndexInActiveBodies != cInactiveIndex; }
  44. /// Check if this body is static (not movable)
  45. inline bool IsStatic() const { return mMotionType == EMotionType::Static; }
  46. /// Check if this body is kinematic (keyframed), which means that it will move according to its current velocity, but forces don't affect it
  47. inline bool IsKinematic() const { return mMotionType == EMotionType::Kinematic; }
  48. /// Check if this body is dynamic, which means that it moves and forces can act on it
  49. inline bool IsDynamic() const { return mMotionType == EMotionType::Dynamic; }
  50. /// Check if a body could be made kinematic or dynamic (if it was created dynamic or with mAllowDynamicOrKinematic set to true)
  51. inline bool CanBeKinematicOrDynamic() const { return mMotionProperties != nullptr; }
  52. /// Check if this body is a sensor. A sensor will receive collision callbacks, but will not cause any collision responses and can be used as a trigger volume.
  53. inline bool IsSensor() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::IsSensor)) != 0; }
  54. /// Motion type of this body
  55. inline EMotionType GetMotionType() const { return mMotionType; }
  56. void SetMotionType(EMotionType inMotionType);
  57. /// Get broadphase layer, this determines in which broad phase sub-tree the object is placed
  58. inline BroadPhaseLayer GetBroadPhaseLayer() const { return mBroadPhaseLayer; }
  59. /// Get object layer, this determines which other objects it collides with
  60. inline ObjectLayer GetObjectLayer() const { return mObjectLayer; }
  61. /// Collision group and sub-group ID, determines which other objects it collides with
  62. const CollisionGroup & GetCollisionGroup() const { return mCollisionGroup; }
  63. CollisionGroup & GetCollisionGroup() { return mCollisionGroup; }
  64. void SetCollisionGroup(const CollisionGroup &inGroup) { mCollisionGroup = inGroup; }
  65. /// If this body can go to sleep. Note that disabling sleeping on a sleeping object wil not wake it up.
  66. bool GetAllowSleeping() const { return mMotionProperties->mAllowSleeping; }
  67. void SetAllowSleeping(bool inAllow);
  68. /// Friction (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals force that presses the two bodies together)
  69. inline float GetFriction() const { return mFriction; }
  70. void SetFriction(float inFriction) { JPH_ASSERT(inFriction >= 0.0f); mFriction = inFriction; }
  71. /// Restitution (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision response, 1 = completely elastic collision response)
  72. inline float GetRestitution() const { return mRestitution; }
  73. void SetRestitution(float inRestitution) { JPH_ASSERT(inRestitution >= 0.0f && inRestitution <= 1.0f); mRestitution = inRestitution; }
  74. /// Get world space linear velocity of the center of mass (unit: m/s)
  75. inline Vec3 GetLinearVelocity() const { return !IsStatic()? mMotionProperties->GetLinearVelocity() : Vec3::sZero(); }
  76. /// Set world space linear velocity of the center of mass (unit: m/s)
  77. void SetLinearVelocity(Vec3Arg inLinearVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetLinearVelocity(inLinearVelocity); }
  78. /// Set world space linear velocity of the center of mass, will make sure the value is clamped against the maximum linear velocity
  79. void SetLinearVelocityClamped(Vec3Arg inLinearVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetLinearVelocityClamped(inLinearVelocity); }
  80. /// Get world space angular velocity of the center of mass (unit: rad/s)
  81. inline Vec3 GetAngularVelocity() const { return !IsStatic()? mMotionProperties->GetAngularVelocity() : Vec3::sZero(); }
  82. /// Set world space angular velocity of the center of mass (unit: rad/s)
  83. void SetAngularVelocity(Vec3Arg inAngularVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetAngularVelocity(inAngularVelocity); }
  84. /// Set world space angular velocity of the center of mass, will make sure the value is clamped against the maximum angular velocity
  85. void SetAngularVelocityClamped(Vec3Arg inAngularVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetAngularVelocityClamped(inAngularVelocity); }
  86. /// Velocity of point inPoint (in center of mass space, e.g. on the surface of the body) of the body (unit: m/s)
  87. inline Vec3 GetPointVelocityCOM(Vec3Arg inPointRelativeToCOM) const { return !IsStatic()? mMotionProperties->GetPointVelocityCOM(inPointRelativeToCOM) : Vec3::sZero(); }
  88. /// Velocity of point inPoint (in world space, e.g. on the surface of the body) of the body (unit: m/s)
  89. inline Vec3 GetPointVelocity(Vec3Arg inPoint) const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return GetPointVelocityCOM(inPoint - mPosition); }
  90. /// Add force (unit: N) for the next time step, will be reset after the next call to PhysicsSimulation::Update
  91. inline void AddForce(Vec3Arg inForce) { JPH_ASSERT(IsDynamic()); (Vec3::sLoadFloat3Unsafe(mMotionProperties->mForce) + inForce).StoreFloat3(&mMotionProperties->mForce); }
  92. /// Add torque (unit: N m) for the next time step, will be reset after the next call to PhysicsSimulation::Update
  93. inline void AddTorque(Vec3Arg inTorque) { JPH_ASSERT(IsDynamic()); (Vec3::sLoadFloat3Unsafe(mMotionProperties->mTorque) + inTorque).StoreFloat3(&mMotionProperties->mTorque); }
  94. /// Get inverse inertia tensor in world space
  95. inline Mat44 GetInverseInertia() const;
  96. /// Add impulse to center of mass (unit: kg m/s)
  97. inline void AddImpulse(Vec3Arg inImpulse);
  98. /// Add impulse to point in world space (unit: kg m/s)
  99. inline void AddImpulse(Vec3Arg inImpulse, Vec3Arg inPosition);
  100. /// Add angular impulse in world space (unit: N m s)
  101. inline void AddAngularImpulse(Vec3Arg inAngularImpulse);
  102. /// Set velocity of body such that it will be positioned at inTargetPosition/Rotation in inDeltaTime seconds.
  103. void MoveKinematic(Vec3Arg inTargetPosition, QuatArg inTargetRotation, float inDeltaTime);
  104. /// Applies an impulse to the body that simulates fluid buoyancy and drag
  105. /// @param inSurface The fluid surface (normal should point up) in world space
  106. /// @param inBuoyancy The buoyancy factor for the body. 1 = neutral body, < 1 sinks, > 1 floats. Note that we don't use the fluid density since it is harder to configure than a simple number between [0, 2]
  107. /// @param inLinearDrag Linear drag factor that slows down the body when in the fluid (approx. 0.5)
  108. /// @param inAngularDrag Angular drag factor that slows down rotation when the body is in the fluid (approx. 0.01)
  109. /// @param inFluidVelocity The average velocity of the fluid (in m/s) in which the body resides
  110. /// @param inGravity The graviy vector (pointing down)
  111. /// @param inDeltaTime Delta time of the next simulation step (in s)
  112. void ApplyBuoyancyImpulse(const Plane &inSurface, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime);
  113. /// Check if this body has been added to the physics system
  114. inline bool IsInBroadPhase() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::IsInBroadPhase)) != 0; }
  115. /// Check if this body has been changed in such a way that the collision cache should be considered invalid for any body interacting with this body
  116. inline bool IsCollisionCacheInvalid() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::InvalidateContactCache)) != 0; }
  117. /// Get the shape of this body
  118. inline const Shape * GetShape() const { return mShape; }
  119. /// World space position of the body
  120. inline Vec3 GetPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mPosition - mRotation * mShape->GetCenterOfMass(); }
  121. /// World space rotation of the body
  122. inline Quat GetRotation() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mRotation; }
  123. /// Calculates the transform of this body
  124. inline Mat44 GetWorldTransform() const;
  125. /// Gets the world space position of this body's center of mass
  126. inline Vec3 GetCenterOfMassPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return mPosition; }
  127. /// Calculates the transform for this body's center of mass
  128. inline Mat44 GetCenterOfMassTransform() const;
  129. /// Calculates the inverse of the transform for this body's center of mass
  130. inline Mat44 GetInverseCenterOfMassTransform() const;
  131. /// Get world space bounding box
  132. inline const AABox & GetWorldSpaceBounds() const { return mBounds; }
  133. /// Access to the motion properties
  134. const MotionProperties *GetMotionProperties() const { JPH_ASSERT(!IsStatic()); return mMotionProperties; }
  135. MotionProperties * GetMotionProperties() { JPH_ASSERT(!IsStatic()); return mMotionProperties; }
  136. /// Access to the motion properties (version that does not check if the object is kinematic or dynamic)
  137. const MotionProperties *GetMotionPropertiesUnchecked() const { return mMotionProperties; }
  138. MotionProperties * GetMotionPropertiesUnchecked() { return mMotionProperties; }
  139. /// Access to the user data, can be used for anything by the application
  140. uint64 GetUserData() const { return mUserData; }
  141. void SetUserData(uint64 inUserData) { mUserData = inUserData; }
  142. /// Get surface normal of a particular sub shape and its world space surface position on this body
  143. inline Vec3 GetWorldSpaceSurfaceNormal(const SubShapeID &inSubShapeID, Vec3Arg inPosition) const;
  144. /// Get the transformed shape of this body, which can be used to do collision detection outside of a body lock
  145. inline TransformedShape GetTransformedShape() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::Read)); return TransformedShape(mPosition, mRotation, mShape, mID); }
  146. /// Debug function to convert a body back to a body creation settings object to be able to save/recreate the body later
  147. BodyCreationSettings GetBodyCreationSettings() const;
  148. /// A dummy body that can be used by constraints to attach a constraint to the world instead of another body
  149. static Body sFixedToWorld;
  150. ///@name THESE FUNCTIONS ARE FOR INTERNAL USE ONLY AND SHOULD NOT BE CALLED BY THE APPLICATION
  151. ///@{
  152. /// Helper function for BroadPhase::FindCollidingPairs that returns true when two bodies can collide
  153. /// It assumes that body 1 is dynamic and active and guarantees that it body 1 collides with body 2 that body 2 will not collide with body 1 in order to avoid finding duplicate collision pairs
  154. static inline bool sFindCollidingPairsCanCollide(const Body &inBody1, const Body &inBody2);
  155. /// Update position using an Euler step (used during position integrate & constraint solving)
  156. inline void AddPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::ReadWrite)); mPosition += inLinearVelocityTimesDeltaTime; JPH_ASSERT(!mPosition.IsNaN()); }
  157. inline void SubPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess, BodyAccess::EAccess::ReadWrite)); mPosition -= inLinearVelocityTimesDeltaTime; JPH_ASSERT(!mPosition.IsNaN()); }
  158. /// Update rotation using an Euler step (using during position integrate & constraint solving)
  159. inline void AddRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime);
  160. inline void SubRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime);
  161. /// Flag if body is in the broadphase (should only be called by the BroadPhase)
  162. inline void SetInBroadPhaseInternal(bool inInBroadPhase) { if (inInBroadPhase) mFlags.fetch_or(uint8(EFlags::IsInBroadPhase), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::IsInBroadPhase)), memory_order_relaxed); }
  163. /// Invalidate the contact cache (should only be called by the BodyManager), will be reset the next simulation step. Returns true if the contact cache was still valid.
  164. inline bool InvalidateContactCacheInternal() { return (mFlags.fetch_or(uint8(EFlags::InvalidateContactCache), memory_order_relaxed) & uint8(EFlags::InvalidateContactCache)) == 0; }
  165. /// Reset the collision cache invalid flag (should only be called by the BodyManager).
  166. inline void ValidateContactCacheInternal() { JPH_IF_ENABLE_ASSERTS(uint8 old_val = ) mFlags.fetch_and(uint8(~uint8(EFlags::InvalidateContactCache)), memory_order_relaxed); JPH_ASSERT((old_val & uint8(EFlags::InvalidateContactCache)) != 0); }
  167. /// Updates world space bounding box (should only be called by the PhysicsSystem)
  168. void CalculateWorldSpaceBoundsInternal();
  169. /// Function to update body's position (should only be called by the BodyInterface since it also requires updating the broadphase)
  170. void SetPositionAndRotationInternal(Vec3Arg inPosition, QuatArg inRotation);
  171. /// Updates the center of mass and optionally mass propertes after shifting the center of mass or changes to the shape (should only be called by the BodyInterface since it also requires updating the broadphase)
  172. /// @param inPreviousCenterOfMass Center of mass of the shape before the alterations
  173. /// @param inUpdateMassProperties When true, the mass and inertia tensor is recalculated
  174. void UpdateCenterOfMassInternal(Vec3Arg inPreviousCenterOfMass, bool inUpdateMassProperties);
  175. /// Function to update a body's shape (should only be called by the BodyInterface since it also requires updating the broadphase)
  176. /// @param inShape The new shape for this body
  177. /// @param inUpdateMassProperties When true, the mass and inertia tensor is recalculated
  178. void SetShapeInternal(const Shape *inShape, bool inUpdateMassProperties);
  179. /// Access to the index in the BodyManager::mActiveBodies list
  180. uint32 GetIndexInActiveBodiesInternal() const { return mMotionProperties != nullptr? mMotionProperties->mIndexInActiveBodies : cInactiveIndex; }
  181. enum class ECanSleep
  182. {
  183. CannotSleep = 0, ///< Object cannot go to sleep
  184. CanSleep = 1, ///< Object can go to sleep
  185. };
  186. /// Update eligibility for sleeping
  187. ECanSleep UpdateSleepStateInternal(float inDeltaTime, float inMaxMovement, float inTimeBeforeSleep);
  188. /// Saving state for replay
  189. void SaveState(StateRecorder &inStream) const;
  190. /// Restoring state for replay
  191. void RestoreState(StateRecorder &inStream);
  192. ///@}
  193. static const uint32 cInactiveIndex = uint32(-1); ///< Constant indicating that body is not active
  194. private:
  195. friend class BodyManager;
  196. explicit Body(bool); ///< Alternative constructor that initializes all members
  197. inline void GetSleepTestPoints(Vec3 *outPoints) const; ///< Determine points to test for checking if body is sleeping: COM, COM + largest bounding box axis, COM + second largest bounding box axis
  198. inline void ResetSleepTestSpheres(); ///< Reset spheres to current position as returned by GetSleepTestPoints
  199. enum class EFlags : uint8
  200. {
  201. IsSensor = 1 << 0, ///< If this object is a sensor. A sensor will receive collision callbacks, but will not cause any collision responses and can be used as a trigger volume.
  202. IsInBroadPhase = 1 << 1, ///< Set this bit to indicate that the body is in the broadphase
  203. InvalidateContactCache = 1 << 2 ///< Set this bit to indicate that all collision caches for this body are invalid, will be reset the next simulation step.
  204. };
  205. // 16 byte aligned
  206. Vec3 mPosition; ///< World space position of center of mass
  207. Quat mRotation; ///< World space rotation of center of mass
  208. AABox mBounds; ///< World space bounding box of the body
  209. // 8 byte aligned
  210. RefConst<Shape> mShape; ///< Shape representing the volume of this body
  211. MotionProperties * mMotionProperties = nullptr; ///< If this is a keyframed or dynamic object, this object holds all information about the movement
  212. uint64 mUserData = 0; ///< User data, can be used for anything by the application
  213. CollisionGroup mCollisionGroup; ///< The collision group this body belongs to (determines if two objects can collide)
  214. // 4 byte aligned
  215. float mFriction; ///< Friction of the body (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals force that presses the two bodies together)
  216. float mRestitution; ///< Restitution of body (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision response, 1 = completely elastic collision response)
  217. BodyID mID; ///< ID of the body (index in the bodies array)
  218. // 2 bytes aligned
  219. ObjectLayer mObjectLayer; ///< The collision layer this body belongs to (determines if two objects can collide)
  220. // 1 byte aligned
  221. BroadPhaseLayer mBroadPhaseLayer; ///< The broad phase layer this body belongs to
  222. EMotionType mMotionType; ///< Type of motion (static, dynamic or kinematic)
  223. atomic<uint8> mFlags = 0; ///< See EFlags for possible flags
  224. // 121 bytes up to here
  225. #ifdef _DEBUG
  226. string mDebugName; ///< Name for debugging purposes
  227. #endif
  228. };
  229. #ifndef _DEBUG
  230. static_assert(sizeof(Body) == 128, "Body should be 128 bytes");
  231. static_assert(alignof(Body) == 16, "Body should align to 16 bytes");
  232. #endif
  233. } // JPH
  234. #include "Body.inl"