网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
//fTimeInSeconds = (fCurrentTime - fStartTime) / 1000.0f;
fTimeInSeconds = ( fCurrentTime - fStartTime ) / 5.0f;
### 10.2、遍历动作CalcAnimation
如前所述,在Assimp加载的模型数据中,关键帧数据被放在aiScene::mAnimations对象数组中,每一个数组成员即代表一个完整动作中所有相关骨骼的全部关键帧数据,所以动画实际播放时,一定要记录当前播放的数组索引号(stMeshData.m\_nCurrentAnimIndex),也就是当前播放动作索引。对于复杂的角色模型来说,有十几套甚至几十套完整动作是很常见的,但更多更复杂的动作集合也往往意味着更高的造价!
当根据索引找到当前需要播放的动作数据后,接着就是重要的Tick解算。Tick可以理解为一个频率值,即一个动作每秒钟播放多少个关键帧,然后需要将当前秒数乘以Tick值(fTimeInSeconds \* TicksPerSecond),并对整个动画持续时间值(pAnimation->mDuration)取余(fmod(TimeInTicks, (FLOAT)pAnimation->mDuration);),即得到当前需要播放哪一个关键帧。因为这个值往往不太可能恰好落在某个关键帧的时间点上,常常会落在某两个关键帧之间,所以最终需要在两个关键帧之间进行变换插值。
确定了最终需要“播放”的动画的关键帧的“时间点”,就可以根据“骨架”,通过调用ReadNodeHeirarchy递归遍历计算当前动画的所有骨骼变换矩阵了。
VOID CalcAnimation(ST_GRS_MESH_DATA& stMeshData
, FLOAT fTimeInSeconds
, CGRSARMatrix& arTransforms)
{
XMMATRIX mxIdentity = XMMatrixIdentity();
aiNode* pNode = stMeshData.m_paiModel->mRootNode;
aiAnimation* pAnimation
= stMeshData.m_paiModel->mAnimations[stMeshData.m_nCurrentAnimIndex];
FLOAT TicksPerSecond = (FLOAT)(pAnimation->mTicksPerSecond != 0
? pAnimation->mTicksPerSecond
: 25.0f);
FLOAT TimeInTicks = fTimeInSeconds \* TicksPerSecond;
FLOAT AnimationTime = fmod(TimeInTicks, (FLOAT)pAnimation->mDuration);
ReadNodeHeirarchy(stMeshData, pAnimation, AnimationTime, pNode, mxIdentity);
UINT nNumBones = (UINT)stMeshData.m_arBoneDatas.GetCount();
for (UINT i = 0; i < nNumBones; i++)
{
arTransforms.Add(stMeshData.m_arBoneDatas[i].m_mxFinalTransformation);
}
}
### 10.2、递归遍历骨骼树ReadNodeHeirarchy
ReadNodeHeirarchy函数,是个比较老套的“先根序”