Fixed child bones inheriting scale from their parent, fixed null weights on CSkin being incorrect, fixed uncompressed animations being read incorrectly

This commit is contained in:
parax0 2016-04-29 15:58:50 -06:00
parent 82f037c69e
commit e781908205
6 changed files with 58 additions and 31 deletions

View File

@ -15,8 +15,10 @@ CAnimation::CAnimation()
} }
} }
void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const void CAnimation::EvaluateTransform(float Time, u32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const
{ {
const bool kInterpolate = true;
if (!pOutTranslation && !pOutRotation && !pOutScale) return;
if (mDuration == 0.f) return; if (mDuration == 0.f) return;
if (Time >= mDuration) Time = mDuration; if (Time >= mDuration) Time = mDuration;
@ -29,25 +31,25 @@ void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) c
u8 RotChannel = mBoneInfo[BoneID].RotationChannelIdx; u8 RotChannel = mBoneInfo[BoneID].RotationChannelIdx;
u8 TransChannel = mBoneInfo[BoneID].TranslationChannelIdx; u8 TransChannel = mBoneInfo[BoneID].TranslationChannelIdx;
if (ScaleChannel != 0xFF) if (ScaleChannel != 0xFF && pOutScale)
{ {
const CVector3f& rkLow = mScaleChannels[ScaleChannel][LowKey]; const CVector3f& rkLow = mScaleChannels[ScaleChannel][LowKey];
const CVector3f& rkHigh = mScaleChannels[ScaleChannel][LowKey + 1]; const CVector3f& rkHigh = mScaleChannels[ScaleChannel][LowKey + 1];
rOut.Scale( Math::Lerp<CVector3f>(rkLow, rkHigh, t) ); *pOutScale = (kInterpolate ? Math::Lerp<CVector3f>(rkLow, rkHigh, t) : rkLow);
} }
if (RotChannel != 0xFF) if (RotChannel != 0xFF && pOutRotation)
{ {
const CQuaternion& rkLow = mRotationChannels[RotChannel][LowKey]; const CQuaternion& rkLow = mRotationChannels[RotChannel][LowKey];
const CQuaternion& rkHigh = mRotationChannels[RotChannel][LowKey + 1]; const CQuaternion& rkHigh = mRotationChannels[RotChannel][LowKey + 1];
rOut.Rotate( rkLow.Slerp(rkHigh, t) ); *pOutRotation = (kInterpolate ? rkLow.Slerp(rkHigh, t) : rkLow);
} }
if (TransChannel != 0xFF) if (TransChannel != 0xFF && pOutTranslation)
{ {
const CVector3f& rkLow = mTranslationChannels[TransChannel][LowKey]; const CVector3f& rkLow = mTranslationChannels[TransChannel][LowKey];
const CVector3f& rkHigh = mTranslationChannels[TransChannel][LowKey + 1]; const CVector3f& rkHigh = mTranslationChannels[TransChannel][LowKey + 1];
rOut.Translate( Math::Lerp<CVector3f>(rkLow, rkHigh, t) ); *pOutTranslation = (kInterpolate ? Math::Lerp<CVector3f>(rkLow, rkHigh, t) : rkLow);
} }
} }

View File

@ -33,7 +33,7 @@ class CAnimation : public CResource
public: public:
CAnimation(); CAnimation();
void EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const; void EvaluateTransform(float Time, u32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const;
bool HasTranslation(u32 BoneID) const; bool HasTranslation(u32 BoneID) const;
inline float Duration() const { return mDuration; } inline float Duration() const { return mDuration; }

View File

@ -10,27 +10,33 @@ CBone::CBone(CSkeleton *pSkel)
{ {
} }
void CBone::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot) void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot)
{ {
CTransform4f& rTransform = rData[mID]; // Get transform data
rTransform.SetIdentity(); SBoneTransformInfo TransformInfo;
TransformInfo.Position = mPosition;
if (pAnim) if (pAnim)
pAnim->EvaluateTransform(Time, mID, rTransform); pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
if (!pAnim || !pAnim->HasTranslation(mID))
rTransform.Translate(mPosition);
if (mpParent)
rTransform = rData[mpParent->ID()] * rTransform;
if (AnchorRoot && IsRoot()) if (AnchorRoot && IsRoot())
rTransform.ZeroTranslation(); TransformInfo.Position = CVector3f::skZero;
// Apply parent transform
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * TransformInfo.Position);
TransformInfo.Rotation = rkParentTransform.Rotation * TransformInfo.Rotation;
// Calculate transform
CTransform4f& rTransform = rData[mID];
rTransform.SetIdentity();
rTransform.Scale(TransformInfo.Scale);
rTransform.Rotate(TransformInfo.Rotation);
rTransform.Translate(TransformInfo.Position);
rTransform *= mInvBind;
// Calculate children
for (u32 iChild = 0; iChild < mChildren.size(); iChild++) for (u32 iChild = 0; iChild < mChildren.size(); iChild++)
mChildren[iChild]->UpdateTransform(rData, pAnim, Time, AnchorRoot); mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
rTransform *= mInvBind;
} }
CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
@ -86,7 +92,7 @@ u32 CSkeleton::MaxBoneID() const
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot) void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
{ {
mpRootBone->UpdateTransform(rData, pAnim, Time, AnchorRoot); mpRootBone->UpdateTransform(rData, SBoneTransformInfo(), pAnim, Time, AnchorRoot);
} }
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData& rkData) void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData& rkData)

View File

@ -12,6 +12,16 @@
class CBoneTransformData; class CBoneTransformData;
class CBone; class CBone;
struct SBoneTransformInfo
{
CVector3f Position;
CQuaternion Rotation;
CVector3f Scale;
SBoneTransformInfo()
: Position(CVector3f::skZero), Rotation(CQuaternion::skIdentity), Scale(CVector3f::skOne) {}
};
class CSkeleton : public CResource class CSkeleton : public CResource
{ {
DECLARE_RESOURCE_TYPE(eSkeleton) DECLARE_RESOURCE_TYPE(eSkeleton)
@ -32,7 +42,8 @@ public:
void Draw(FRenderOptions Options, const CBoneTransformData& rkData); void Draw(FRenderOptions Options, const CBoneTransformData& rkData);
std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData); std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
inline u32 NumBones() const { return mBones.size(); } inline u32 NumBones() const { return mBones.size(); }
inline CBone* RootBone() const { return mpRootBone; }
}; };
class CBone class CBone
@ -49,7 +60,7 @@ class CBone
public: public:
CBone(CSkeleton *pSkel); CBone(CSkeleton *pSkel);
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot); void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
CVector3f TransformedPosition(const CBoneTransformData& rkData) const; CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
bool IsRoot() const; bool IsRoot() const;

View File

@ -22,16 +22,15 @@ class CSkin : public CResource
}; };
std::vector<SVertGroup> mVertGroups; std::vector<SVertGroup> mVertGroups;
u32 mSkinnedVertexCount;
public: public:
CSkin() {} CSkin() {}
const SVertexWeights& WeightsForVertex(u32 VertIdx) const SVertexWeights& WeightsForVertex(u32 VertIdx)
{ {
// Null weights bind everything to the root bone in case there is no matching vertex group
static const SVertexWeights skNullWeights = { static const SVertexWeights skNullWeights = {
{ 0, 0, 0, 0 }, { 3, 0, 0, 0 },
{ 0.f, 0.f, 0.f, 0.f } { 1.f, 0.f, 0.f, 0.f }
}; };
u32 Index = 0; u32 Index = 0;

View File

@ -94,8 +94,17 @@ void CAnimationLoader::ReadUncompressedANIM()
else else
{ {
NumRotationChannels = NumBoneChannels; // In MP1 every bone channel has a rotation, so just copy the valid channels from the bone channel list.
RotationIndices = BoneIndices; RotationIndices.resize(NumBoneChannels);
for (u32 iBone = 0; iBone < BoneIndices.size(); iBone++)
{
if (BoneIndices[iBone] != 0xFF)
{
RotationIndices[NumRotationChannels] = BoneIndices[iBone];
NumRotationChannels++;
}
}
} }
// Translation channel indices // Translation channel indices