154 lines
5.7 KiB
C++
154 lines
5.7 KiB
C++
#pragma once
|
|
|
|
namespace verus
|
|
{
|
|
namespace Anim
|
|
{
|
|
//! Standard skeleton, which can be animated using motion object (Motion).
|
|
|
|
//! X3D format can support up to 256 bones, but the hardware has certain
|
|
//! limitations. With Shader Model 2.0 the shader can hold about 32 bone
|
|
//! matrices. Other bones must be remapped using Primary Bones concept.
|
|
//!
|
|
//! Alpha Motions (AlphaMotion) add the ability to mix multiple motions,
|
|
//! just like images are mixed with alpha channel. Alpha Motion affects
|
|
//! it's root bone and all descendants of that bone.
|
|
//!
|
|
//! A ragdoll can be created automatically or configured using XML .rig file.
|
|
//! Ragdoll's simulation can start from any motion frame and any simulated pose
|
|
//! can be baked back into motion object, allowing smooth transition to ragdoll
|
|
//! simulation and back to motion.
|
|
//!
|
|
class Skeleton : public Object
|
|
{
|
|
public:
|
|
struct AlphaMotion
|
|
{
|
|
PMotion _pMotion = nullptr;
|
|
CSZ _rootBone = nullptr;
|
|
float _alpha = 0;
|
|
float _time = 0;
|
|
};
|
|
VERUS_TYPEDEFS(AlphaMotion);
|
|
|
|
struct Bone : public AllocatorAware
|
|
{
|
|
Transform3 _matToBoneSpace = Transform3::identity();
|
|
Transform3 _matFromBoneSpace = Transform3::identity();
|
|
Transform3 _matFinal = Transform3::identity();
|
|
Transform3 _matFinalInv = Transform3::identity();
|
|
Transform3 _matExternal = Transform3::identity();
|
|
Transform3 _matAdapt = Transform3::identity();
|
|
Transform3 _matToActorSpace = Transform3::identity();
|
|
Vector3 _rigRot = Vector3(0); //!< Rotation angles of ragdoll's rigid component.
|
|
Vector3 _cRot = Vector3(0); //!< Constraint's rotation angles.
|
|
Vector3 _cLimits = Vector3(0); //!< Constraint's limits.
|
|
Vector3 _boxSize = Vector3(0); //!< For a box shape.
|
|
String _name;
|
|
String _parentName;
|
|
btCollisionShape* _pShape = nullptr;
|
|
btRigidBody* _pBody = nullptr;
|
|
btTypedConstraint* _pConstraint = nullptr;
|
|
float _width = 0;
|
|
float _length = 0;
|
|
float _mass = 0;
|
|
int _shaderIndex = 0; //!< Index of a matrix in the vertex shader.
|
|
bool _ready = false;
|
|
bool _rigBone = true;
|
|
bool _hinge = false; //!< btHingeConstraint vs btConeTwistConstraint.
|
|
bool _noCollision = false;
|
|
};
|
|
VERUS_TYPEDEFS(Bone);
|
|
|
|
private:
|
|
typedef Map<String, Bone> TMapBones;
|
|
typedef Map<int, int> TMapPrimary;
|
|
|
|
Transform3 _matParents = Transform3::identity();
|
|
Transform3 _matRagdollToWorld = Transform3::identity();
|
|
Transform3 _matRagdollToWorldInv = Transform3::identity();
|
|
TMapBones _mapBones;
|
|
TMapPrimary _mapPrimary;
|
|
PBone _pCurrentBone = nullptr;
|
|
PMotion _pCurrentMotion = nullptr;
|
|
PAlphaMotion _pAlphaMotions = nullptr;
|
|
float _currentTime = 0;
|
|
float _mass = 0;
|
|
int _numPrimaryBones = 0;
|
|
int _numAlphaMotions = 0;
|
|
bool _ragdollMode = false;
|
|
|
|
public:
|
|
Skeleton();
|
|
~Skeleton();
|
|
|
|
void operator=(const Skeleton& that);
|
|
|
|
void Init();
|
|
void Done();
|
|
|
|
void Draw(bool bindPose = true, int selected = -1);
|
|
|
|
static CSZ RootName() { return "$ROOT"; }
|
|
|
|
PBone InsertBone(RBone bone);
|
|
PBone FindBone(CSZ name);
|
|
PcBone FindBone(CSZ name) const;
|
|
//! Uses shader's array index to find a bone.
|
|
PBone FindBoneByIndex(int index);
|
|
|
|
//! Sets the current pose using motion object (Motion).
|
|
void ApplyMotion(RMotion motion, float time,
|
|
int numAlphaMotions = 0, PAlphaMotion pAlphaMotions = nullptr);
|
|
|
|
//! Fills the array of matrices that will be used by a shader.
|
|
void FillMatrixArray(mataff* p) const;
|
|
|
|
void ResetFinalPose();
|
|
|
|
VERUS_P(void ResetBones());
|
|
VERUS_P(void RecursiveBoneUpdate());
|
|
|
|
int GetNumBones() const { return _numPrimaryBones ? _numPrimaryBones : Utils::Cast32(_mapBones.size()); }
|
|
|
|
void VisitBones(std::function<Continue(RBone)> fn);
|
|
void VisitBones(std::function<Continue(RcBone)> fn) const;
|
|
|
|
//! Adds skeleton's bones to motion object (Motion).
|
|
void InsertBonesIntoMotion(RMotion motion) const;
|
|
//! Removes motion's bones, which are not skeleton's bones.
|
|
void DeleteOutsiders(RMotion motion) const;
|
|
|
|
void AdjustPrimaryBones(const Vector<String>& vPrimaryBones);
|
|
int RemapBoneIndex(int index) const;
|
|
|
|
bool IsParentOf(CSZ bone, CSZ parent) const;
|
|
|
|
void LoadRigInfo(CSZ url);
|
|
void LoadRigInfoFromPtr(const BYTE* p);
|
|
void BeginRagdoll(RcTransform3 matW, RcVector3 impulse = Vector3(0), CSZ bone = "Spine2");
|
|
void EndRagdoll();
|
|
bool IsRagdollMode() const { return _ragdollMode; }
|
|
RcTransform3 GetRagdollToWorldMatrix() { return _matRagdollToWorld; }
|
|
|
|
//! Saves the current pose into motion object (Motion) at some frame.
|
|
void BakeMotion(RMotion motion, int frame = 0, bool kinect = false);
|
|
void AdaptBindPoseOf(const Skeleton& that);
|
|
void SimpleIK(CSZ boneDriven, CSZ boneDriver, RcVector3 dirDriverSpace, RcVector3 dirDesiredMeshSpace, float limitDot, float alpha);
|
|
|
|
void ProcessKinectData(const BYTE* p, RMotion motion, int frame = 0);
|
|
void ProcessKinectJoint(const BYTE* p, CSZ name, RcVector3 skeletonPos);
|
|
void LoadKinectBindPose(CSZ xml);
|
|
static bool IsKinectBone(CSZ name);
|
|
static bool IsKinectLeafBone(CSZ name);
|
|
|
|
void FixateFeet(RMotion motion);
|
|
|
|
//! Tries to compute the highest speed at which a bone would move with this motion applied.
|
|
//! Can be used to sync animation and movement to fix the sliding feet problem.
|
|
Vector3 GetHighestSpeed(RMotion motion, CSZ name, RcVector3 scale = Vector3(1, 0, 1), bool positive = false);
|
|
};
|
|
VERUS_TYPEDEFS(Skeleton);
|
|
}
|
|
}
|