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 (Time >= mDuration) Time = mDuration;
@ -29,25 +31,25 @@ void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) c
u8 RotChannel = mBoneInfo[BoneID].RotationChannelIdx;
u8 TransChannel = mBoneInfo[BoneID].TranslationChannelIdx;
if (ScaleChannel != 0xFF)
if (ScaleChannel != 0xFF && pOutScale)
{
const CVector3f& rkLow = mScaleChannels[ScaleChannel][LowKey];
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& 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& 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:
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;
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];
rTransform.SetIdentity();
// Get transform data
SBoneTransformInfo TransformInfo;
TransformInfo.Position = mPosition;
if (pAnim)
pAnim->EvaluateTransform(Time, mID, rTransform);
if (!pAnim || !pAnim->HasTranslation(mID))
rTransform.Translate(mPosition);
if (mpParent)
rTransform = rData[mpParent->ID()] * rTransform;
pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
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++)
mChildren[iChild]->UpdateTransform(rData, pAnim, Time, AnchorRoot);
rTransform *= mInvBind;
mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
}
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)
{
mpRootBone->UpdateTransform(rData, pAnim, Time, AnchorRoot);
mpRootBone->UpdateTransform(rData, SBoneTransformInfo(), pAnim, Time, AnchorRoot);
}
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData& rkData)

View File

@ -12,6 +12,16 @@
class CBoneTransformData;
class CBone;
struct SBoneTransformInfo
{
CVector3f Position;
CQuaternion Rotation;
CVector3f Scale;
SBoneTransformInfo()
: Position(CVector3f::skZero), Rotation(CQuaternion::skIdentity), Scale(CVector3f::skOne) {}
};
class CSkeleton : public CResource
{
DECLARE_RESOURCE_TYPE(eSkeleton)
@ -32,7 +42,8 @@ public:
void Draw(FRenderOptions Options, 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
@ -49,7 +60,7 @@ class CBone
public:
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;
bool IsRoot() const;

View File

@ -22,16 +22,15 @@ class CSkin : public CResource
};
std::vector<SVertGroup> mVertGroups;
u32 mSkinnedVertexCount;
public:
CSkin() {}
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 = {
{ 0, 0, 0, 0 },
{ 0.f, 0.f, 0.f, 0.f }
{ 3, 0, 0, 0 },
{ 1.f, 0.f, 0.f, 0.f }
};
u32 Index = 0;

View File

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