2
0

Ragdoll.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Core/Reference.h>
  5. #include <Jolt/Core/Result.h>
  6. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  7. #include <Jolt/Physics/Constraints/TwoBodyConstraint.h>
  8. #include <Jolt/Skeleton/Skeleton.h>
  9. #include <Jolt/Skeleton/SkeletonPose.h>
  10. #include <Jolt/Physics/EActivation.h>
  11. JPH_NAMESPACE_BEGIN
  12. class Ragdoll;
  13. class PhysicsSystem;
  14. /// Contains the structure of a ragdoll
  15. class RagdollSettings : public RefTarget<RagdollSettings>
  16. {
  17. public:
  18. JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(RagdollSettings)
  19. /// Stabilize the constraints of the ragdoll
  20. /// @return True on success, false on failure.
  21. bool Stabilize();
  22. /// After the ragdoll has been fully configured, call this function to automatically create and add a GroupFilterTable collision filter to all bodies
  23. /// and configure them so that parent and children don't collide.
  24. ///
  25. /// This will:
  26. /// - Create a GroupFilterTable and assign it to all of the bodies in a ragdoll.
  27. /// - Each body in your ragdoll will get a SubGroupID that is equal to the joint index in the Skeleton that it is attached to.
  28. /// - Loop over all joints in the Skeleton and call GroupFilterTable::DisableCollision(joint index, parent joint index).
  29. /// - When a pose is provided through inJointMatrices the function will detect collisions between joints
  30. /// (they must be separated by more than inMinSeparationDistance to be treated as not colliding) and automatically disable collisions.
  31. ///
  32. /// When you create an instance using Ragdoll::CreateRagdoll pass in a unique GroupID for each ragdoll (e.g. a simple counter), note that this number
  33. /// should be unique throughout the PhysicsSystem, so if you have different types of ragdolls they should not share the same GroupID.
  34. void DisableParentChildCollisions(const Mat44 *inJointMatrices = nullptr, float inMinSeparationDistance = 0.0f);
  35. /// Saves the state of this object in binary form to inStream.
  36. /// @param inStream The stream to save the state to
  37. /// @param inSaveShapes If the shapes should be saved as well (these could be shared between ragdolls, in which case the calling application may want to write custom code to restore them)
  38. /// @param inSaveGroupFilter If the group filter should be saved as well (these could be shared)
  39. void SaveBinaryState(StreamOut &inStream, bool inSaveShapes, bool inSaveGroupFilter) const;
  40. using RagdollResult = Result<Ref<RagdollSettings>>;
  41. /// Restore a saved ragdoll from inStream
  42. static RagdollResult sRestoreFromBinaryState(StreamIn &inStream);
  43. /// Create ragdoll instance from these settings
  44. /// @return Newly created ragdoll or null when out of bodies
  45. Ragdoll * CreateRagdoll(CollisionGroup::GroupID inCollisionGroup, uint64 inUserData, PhysicsSystem *inSystem) const;
  46. /// Access to the skeleton of this ragdoll
  47. const Skeleton * GetSkeleton() const { return mSkeleton; }
  48. Skeleton * GetSkeleton() { return mSkeleton; }
  49. /// Calculate the map needed for GetBodyIndexToConstraintIndex()
  50. void CalculateBodyIndexToConstraintIndex();
  51. /// Get table that maps a body index to the constraint index with which it is connected to its parent. -1 if there is no constraint associated with the body.
  52. const Array<int> & GetBodyIndexToConstraintIndex() const { return mBodyIndexToConstraintIndex; }
  53. /// Map a single body index to a constraint index
  54. int GetConstraintIndexForBodyIndex(int inBodyIndex) const { return mBodyIndexToConstraintIndex[inBodyIndex]; }
  55. /// Calculate the map needed for GetConstraintIndexToBodyIdxPair()
  56. void CalculateConstraintIndexToBodyIdxPair();
  57. using BodyIdxPair = pair<int, int>;
  58. /// Table that maps a constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)
  59. const Array<BodyIdxPair> & GetConstraintIndexToBodyIdxPair() const { return mConstraintIndexToBodyIdxPair; }
  60. /// Map a single constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)
  61. BodyIdxPair GetBodyIndicesForConstraintIndex(int inConstraintIndex) const { return mConstraintIndexToBodyIdxPair[inConstraintIndex]; }
  62. /// A single rigid body sub part of the ragdoll
  63. class Part : public BodyCreationSettings
  64. {
  65. public:
  66. JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(Part)
  67. Ref<TwoBodyConstraintSettings> mToParent;
  68. };
  69. /// List of ragdoll parts
  70. using PartVector = Array<Part>; ///< The constraint that connects this part to its parent part (should be null for the root)
  71. /// The skeleton for this ragdoll
  72. Ref<Skeleton> mSkeleton;
  73. /// For each of the joints, the body and constraint attaching it to its parent body (1-on-1 with mSkeleton.GetJoints())
  74. PartVector mParts;
  75. private:
  76. /// Table that maps a body index (index in mBodyIDs) to the constraint index with which it is connected to its parent. -1 if there is no constraint associated with the body.
  77. Array<int> mBodyIndexToConstraintIndex;
  78. /// Table that maps a constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)
  79. Array<BodyIdxPair> mConstraintIndexToBodyIdxPair;
  80. };
  81. /// Runtime ragdoll information
  82. class Ragdoll : public RefTarget<Ragdoll>, public NonCopyable
  83. {
  84. public:
  85. JPH_OVERRIDE_NEW_DELETE
  86. /// Constructor
  87. explicit Ragdoll(PhysicsSystem *inSystem) : mSystem(inSystem) { }
  88. /// Destructor
  89. ~Ragdoll();
  90. /// Add bodies and constraints to the system and optionally activate the bodies
  91. void AddToPhysicsSystem(EActivation inActivationMode, bool inLockBodies = true);
  92. /// Remove bodies and constraints from the system
  93. void RemoveFromPhysicsSystem(bool inLockBodies = true);
  94. /// Wake up all bodies in the ragdoll
  95. void Activate(bool inLockBodies = true);
  96. /// Set the group ID on all bodies in the ragdoll
  97. void SetGroupID(CollisionGroup::GroupID inGroupID, bool inLockBodies = true);
  98. /// Set the ragdoll to a pose (calls BodyInterface::SetPositionAndRotation to instantly move the ragdoll)
  99. void SetPose(const SkeletonPose &inPose, bool inLockBodies = true);
  100. /// Lower level version of SetPose that directly takes the world space joint matrices
  101. void SetPose(const Mat44 *inJointMatrices, bool inLockBodies = true);
  102. /// Get the ragdoll pose (uses the world transform of the bodies to calculate the pose)
  103. void GetPose(SkeletonPose &outPose, bool inLockBodies = true);
  104. /// Lower level version of GetPose that directly returns the world space joint matrices
  105. void GetPose(Mat44 *outJointMatrices, bool inLockBodies = true);
  106. /// Drive the ragdoll to a specific pose by setting velocities on each of the bodies so that it will reach inPose in inDeltaTime
  107. void DriveToPoseUsingKinematics(const SkeletonPose &inPose, float inDeltaTime, bool inLockBodies = true);
  108. /// Lower level version of DriveToPoseUsingKinematics that directly takes the world space joint matrices
  109. void DriveToPoseUsingKinematics(const Mat44 *inJointMatrices, float inDeltaTime, bool inLockBodies = true);
  110. /// Drive the ragdoll to a specific pose by activating the motors on each constraint
  111. void DriveToPoseUsingMotors(const SkeletonPose &inPose);
  112. /// Control the linear and velocity of all bodies in the ragdoll
  113. void SetLinearAndAngularVelocity(Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, bool inLockBodies = true);
  114. /// Set the world space linear velocity of all bodies in the ragdoll.
  115. void SetLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies = true);
  116. /// Add a world space velocity (in m/s) to all bodies in the ragdoll.
  117. void AddLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies = true);
  118. /// Add impulse to all bodies of the ragdoll (center of mass of each of them)
  119. void AddImpulse(Vec3Arg inImpulse, bool inLockBodies = true);
  120. /// Get the position and orientation of the root of the ragdoll
  121. void GetRootTransform(Vec3 &outPosition, Quat &outRotation, bool inLockBodies = true) const;
  122. /// Get number of bodies in the ragdoll
  123. size_t GetBodyCount() const { return mBodyIDs.size(); }
  124. /// Access a body ID
  125. BodyID GetBodyID(int inBodyIndex) const { return mBodyIDs[inBodyIndex]; }
  126. /// Access to the array of body IDs
  127. const Array<BodyID> & GetBodyIDs() const { return mBodyIDs; }
  128. /// Get number of constraints in the ragdoll
  129. size_t GetConstraintCount() const { return mConstraints.size(); }
  130. /// Access a constraint by index
  131. TwoBodyConstraint * GetConstraint(int inConstraintIndex) { return mConstraints[inConstraintIndex]; }
  132. /// Access a constraint by index
  133. const TwoBodyConstraint * GetConstraint(int inConstraintIndex) const { return mConstraints[inConstraintIndex]; }
  134. /// Get world space bounding box for all bodies of the ragdoll
  135. AABox GetWorldSpaceBounds(bool inLockBodies = true) const;
  136. /// Get the settings object that created this ragdoll
  137. const RagdollSettings * GetRagdollSettings() const { return mRagdollSettings; }
  138. private:
  139. /// For RagdollSettings::CreateRagdoll function
  140. friend class RagdollSettings;
  141. /// The settings that created this ragdoll
  142. RefConst<RagdollSettings> mRagdollSettings;
  143. /// The bodies and constraints that this ragdoll consists of (1-on-1 with mRagdollSettings->mParts)
  144. Array<BodyID> mBodyIDs;
  145. /// Array of constraints that connect the bodies together
  146. Array<Ref<TwoBodyConstraint>> mConstraints;
  147. /// Cached physics system
  148. PhysicsSystem * mSystem;
  149. };
  150. JPH_NAMESPACE_END