Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Ragdoll/Ragdoll.h
22800 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Core/Reference.h>7#include <Jolt/Core/Result.h>8#include <Jolt/Physics/Body/BodyCreationSettings.h>9#include <Jolt/Physics/Constraints/TwoBodyConstraint.h>10#include <Jolt/Skeleton/Skeleton.h>11#include <Jolt/Skeleton/SkeletonPose.h>12#include <Jolt/Physics/EActivation.h>1314JPH_NAMESPACE_BEGIN1516class Ragdoll;17class PhysicsSystem;1819/// Contains the structure of a ragdoll20class JPH_EXPORT RagdollSettings : public RefTarget<RagdollSettings>21{22JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, RagdollSettings)2324public:25/// Stabilize the constraints of the ragdoll26/// @return True on success, false on failure.27bool Stabilize();2829/// Initializes the constraint priorities so that constraints near the leaves of the ragdoll have a lower priority30/// than constraints near the root of the ragdoll.31/// @param inBasePriority The lowest priority that will be used in the ragdoll.32void CalculateConstraintPriorities(uint32 inBasePriority = 0);3334/// After the ragdoll has been fully configured, call this function to automatically create and add a GroupFilterTable collision filter to all bodies35/// and configure them so that parent and children don't collide.36///37/// This will:38/// - Create a GroupFilterTable and assign it to all of the bodies in a ragdoll.39/// - Each body in your ragdoll will get a SubGroupID that is equal to the joint index in the Skeleton that it is attached to.40/// - Loop over all joints in the Skeleton and call GroupFilterTable::DisableCollision(joint index, parent joint index).41/// - When a pose is provided through inJointMatrices the function will detect collisions between joints42/// (they must be separated by more than inMinSeparationDistance to be treated as not colliding) and automatically disable collisions.43///44/// When you create an instance using Ragdoll::CreateRagdoll pass in a unique GroupID for each ragdoll (e.g. a simple counter), note that this number45/// should be unique throughout the PhysicsSystem, so if you have different types of ragdolls they should not share the same GroupID.46void DisableParentChildCollisions(const Mat44 *inJointMatrices = nullptr, float inMinSeparationDistance = 0.0f);4748/// Saves the state of this object in binary form to inStream.49/// @param inStream The stream to save the state to50/// @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)51/// @param inSaveGroupFilter If the group filter should be saved as well (these could be shared)52void SaveBinaryState(StreamOut &inStream, bool inSaveShapes, bool inSaveGroupFilter) const;5354using RagdollResult = Result<Ref<RagdollSettings>>;5556/// Restore a saved ragdoll from inStream57static RagdollResult sRestoreFromBinaryState(StreamIn &inStream);5859/// Create ragdoll instance from these settings60/// @return Newly created ragdoll or null when out of bodies61Ragdoll * CreateRagdoll(CollisionGroup::GroupID inCollisionGroup, uint64 inUserData, PhysicsSystem *inSystem) const;6263/// Access to the skeleton of this ragdoll64const Skeleton * GetSkeleton() const { return mSkeleton; }65Skeleton * GetSkeleton() { return mSkeleton; }6667/// Calculate the map needed for GetBodyIndexToConstraintIndex()68void CalculateBodyIndexToConstraintIndex();6970/// 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.71/// Note that this will only tell you which constraint connects the body to its parent, it will not look in the additional constraint list.72const Array<int> & GetBodyIndexToConstraintIndex() const { return mBodyIndexToConstraintIndex; }7374/// Map a single body index to a constraint index75int GetConstraintIndexForBodyIndex(int inBodyIndex) const { return mBodyIndexToConstraintIndex[inBodyIndex]; }7677/// Calculate the map needed for GetConstraintIndexToBodyIdxPair()78void CalculateConstraintIndexToBodyIdxPair();7980using BodyIdxPair = std::pair<int, int>;8182/// Table that maps a constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)83const Array<BodyIdxPair> & GetConstraintIndexToBodyIdxPair() const { return mConstraintIndexToBodyIdxPair; }8485/// Map a single constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)86BodyIdxPair GetBodyIndicesForConstraintIndex(int inConstraintIndex) const { return mConstraintIndexToBodyIdxPair[inConstraintIndex]; }8788/// A single rigid body sub part of the ragdoll89class Part : public BodyCreationSettings90{91JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, Part)9293public:94Ref<TwoBodyConstraintSettings> mToParent;95};9697/// List of ragdoll parts98using PartVector = Array<Part>; ///< The constraint that connects this part to its parent part (should be null for the root)99100/// A constraint that connects two bodies in a ragdoll (for non parent child related constraints)101class AdditionalConstraint102{103JPH_DECLARE_SERIALIZABLE_NON_VIRTUAL(JPH_EXPORT, AdditionalConstraint)104105public:106/// Constructors107AdditionalConstraint() = default;108AdditionalConstraint(int inBodyIdx1, int inBodyIdx2, TwoBodyConstraintSettings *inConstraint) : mBodyIdx { inBodyIdx1, inBodyIdx2 }, mConstraint(inConstraint) { }109110int mBodyIdx[2]; ///< Indices of the bodies that this constraint connects111Ref<TwoBodyConstraintSettings> mConstraint; ///< The constraint that connects these bodies112};113114/// List of additional constraints115using AdditionalConstraintVector = Array<AdditionalConstraint>;116117/// The skeleton for this ragdoll118Ref<Skeleton> mSkeleton;119120/// For each of the joints, the body and constraint attaching it to its parent body (1-on-1 with mSkeleton.GetJoints())121PartVector mParts;122123/// A list of constraints that connects two bodies in a ragdoll (for non parent child related constraints)124AdditionalConstraintVector mAdditionalConstraints;125126private:127/// 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.128Array<int> mBodyIndexToConstraintIndex;129130/// Table that maps a constraint index (index in mConstraints) to the indices of the bodies that the constraint is connected to (index in mBodyIDs)131Array<BodyIdxPair> mConstraintIndexToBodyIdxPair;132};133134/// Runtime ragdoll information135class JPH_EXPORT Ragdoll : public RefTarget<Ragdoll>, public NonCopyable136{137public:138JPH_OVERRIDE_NEW_DELETE139140/// Constructor141explicit Ragdoll(PhysicsSystem *inSystem) : mSystem(inSystem) { }142143/// Destructor144~Ragdoll();145146/// Add bodies and constraints to the system and optionally activate the bodies147void AddToPhysicsSystem(EActivation inActivationMode, bool inLockBodies = true);148149/// Remove bodies and constraints from the system150void RemoveFromPhysicsSystem(bool inLockBodies = true);151152/// Wake up all bodies in the ragdoll153void Activate(bool inLockBodies = true);154155/// Check if one or more of the bodies in the ragdoll are active.156/// Note that this involves locking the bodies (if inLockBodies is true) and looping over them. An alternative and possibly faster157/// way could be to install a BodyActivationListener and count the number of active bodies of a ragdoll as they're activated / deactivated158/// (basically check if the body that activates / deactivates is in GetBodyIDs() and increment / decrement a counter).159bool IsActive(bool inLockBodies = true) const;160161/// Set the group ID on all bodies in the ragdoll162void SetGroupID(CollisionGroup::GroupID inGroupID, bool inLockBodies = true);163164/// Set the ragdoll to a pose (calls BodyInterface::SetPositionAndRotation to instantly move the ragdoll)165void SetPose(const SkeletonPose &inPose, bool inLockBodies = true);166167/// Lower level version of SetPose that directly takes the world space joint matrices168void SetPose(RVec3Arg inRootOffset, const Mat44 *inJointMatrices, bool inLockBodies = true);169170/// Get the ragdoll pose (uses the world transform of the bodies to calculate the pose)171void GetPose(SkeletonPose &outPose, bool inLockBodies = true);172173/// Lower level version of GetPose that directly returns the world space joint matrices174void GetPose(RVec3 &outRootOffset, Mat44 *outJointMatrices, bool inLockBodies = true);175176/// This function calls ResetWarmStart on all constraints. It can be used after calling SetPose to reset previous frames impulses. See: Constraint::ResetWarmStart.177void ResetWarmStart();178179/// Drive the ragdoll to a specific pose by setting velocities on each of the bodies so that it will reach inPose in inDeltaTime180void DriveToPoseUsingKinematics(const SkeletonPose &inPose, float inDeltaTime, bool inLockBodies = true);181182/// Lower level version of DriveToPoseUsingKinematics that directly takes the world space joint matrices183void DriveToPoseUsingKinematics(RVec3Arg inRootOffset, const Mat44 *inJointMatrices, float inDeltaTime, bool inLockBodies = true);184185/// Drive the ragdoll to a specific pose by activating the motors on each constraint186void DriveToPoseUsingMotors(const SkeletonPose &inPose);187188/// Control the linear and velocity of all bodies in the ragdoll189void SetLinearAndAngularVelocity(Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, bool inLockBodies = true);190191/// Set the world space linear velocity of all bodies in the ragdoll.192void SetLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies = true);193194/// Add a world space velocity (in m/s) to all bodies in the ragdoll.195void AddLinearVelocity(Vec3Arg inLinearVelocity, bool inLockBodies = true);196197/// Add impulse to all bodies of the ragdoll (center of mass of each of them)198void AddImpulse(Vec3Arg inImpulse, bool inLockBodies = true);199200/// Get the position and orientation of the root of the ragdoll201void GetRootTransform(RVec3 &outPosition, Quat &outRotation, bool inLockBodies = true) const;202203/// Get number of bodies in the ragdoll204size_t GetBodyCount() const { return mBodyIDs.size(); }205206/// Access a body ID207BodyID GetBodyID(int inBodyIndex) const { return mBodyIDs[inBodyIndex]; }208209/// Access to the array of body IDs210const Array<BodyID> & GetBodyIDs() const { return mBodyIDs; }211212/// Get number of constraints in the ragdoll213size_t GetConstraintCount() const { return mConstraints.size(); }214215/// Access a constraint by index216TwoBodyConstraint * GetConstraint(int inConstraintIndex) { return mConstraints[inConstraintIndex]; }217218/// Access a constraint by index219const TwoBodyConstraint * GetConstraint(int inConstraintIndex) const { return mConstraints[inConstraintIndex]; }220221/// Get world space bounding box for all bodies of the ragdoll222AABox GetWorldSpaceBounds(bool inLockBodies = true) const;223224/// Get the settings object that created this ragdoll225const RagdollSettings * GetRagdollSettings() const { return mRagdollSettings; }226227private:228/// For RagdollSettings::CreateRagdoll function229friend class RagdollSettings;230231/// The settings that created this ragdoll232RefConst<RagdollSettings> mRagdollSettings;233234/// The bodies and constraints that this ragdoll consists of (1-on-1 with mRagdollSettings->mParts)235Array<BodyID> mBodyIDs;236237/// Array of constraints that connect the bodies together238Array<Ref<TwoBodyConstraint>> mConstraints;239240/// Cached physics system241PhysicsSystem * mSystem;242};243244JPH_NAMESPACE_END245246247