该例子有几个难点不好分析,该例子总体来讲主要就是采用手动的方式(而不是自动的方式,该as->setLoop(false)函数可体现)去进行动画的循环,ANIM_CHOP控制动画的截断点

第一个难点首先出现在 tweakSneakAnim()函数中

TransformKeyFrame* newKf = track->createNodeKeyFrame(ANIM_CHOP);
TransformKeyFrame
* startKf = track->getNodeKeyFrame(0);

该函数就是创建一帧作为动画截断点,将第0帧作为动画的起始点。

第二个难点是tweakSneakAnim()函数中一下代码的理解:

if (bone->getName() == "Spineroot")   // adjust spine root relative to new location
{
mSneakStartPos
= startKf->getTranslate() + bone->getInitialPosition();
mSneakEndPos
= oldKf.getTranslate() + bone->getInitialPosition();
mSneakStartPos.y
= mSneakEndPos.y;

newKf
->setTranslate(oldKf.getTranslate());
newKf
->setRotation(oldKf.getRotation());
newKf
->setScale(oldKf.getScale());
}
else // make all other bones loop back
{
newKf
->setTranslate(startKf->getTranslate());
newKf
->setRotation(startKf->getRotation());
newKf
->setScale(startKf->getScale());
}

根据骨骼bone 的位置来获得mSneakStartPos,mSneakEndPos,即该骨骼在开始和结束和所处的位置,注意oldKf保存的是track->getInterpolatedKeyFrame(ANIM_CHOP, &oldKf);,也就是差值后,ANIM_CHOP处的帧。至于mSneakStartPos.y = mSneakEndPos.y;
,个人认为将代码注释掉,对画面效果没影响(此处为个人理解,如有不对,望加指正),之后的三行,就是将ANIM_CHOP处的帧newKf通过平移旋转缩放到经过差值后的oldKf所指的那帧,动画就是这样循环起来了,至于else中的内容,是对于骨骼名字不是Spineroot
的骨骼而进行设置,只需简单的循环到初始帧即可。

 

第三个难点,就是在 frameRenderingQueued函数中,也就是这个程序的关键所在

if (mAnimStates[i]->getTimePosition() >= ANIM_CHOP)   // when it's time to loop...
{
/* We need reposition the scene node origin, since the animation includes translation.
Position is calculated from an offset to the end position, and rotation is calculated
from how much the animation turns the character.
*/

Quaternion rot(Degree(
-60), Vector3::UNIT_Y); // how much the animation turns the character

// find current end position and the offset
Vector3 currEnd = mModelNodes[i]->getOrientation() * mSneakEndPos + mModelNodes[i]->getPosition();
Vector3 offset
= rot * mModelNodes[i]->getOrientation() * -mSneakStartPos;

mModelNodes[i]
->setPosition(currEnd + offset);
mModelNodes[i]
->rotate(rot);

mAnimStates[i]
->setTimePosition(0); // reset animation time
}

理解这个if语句至关重要,(注,如果读者对于四元数存在理解问题,请看我的另一篇文章,《Ogre四元数应用简析》),Quaternion rot只是定义了一个绕y轴旋转的-60度得四元数,currEnd=后面那一堆,mModelNodes[i]->getPosition()好理解,就是模型的位置,mModelNodes[i]->getOrientation() * mSneakEndPos意思就是获取模型当前的方向,可能很多人在这里要问为什么要乘以getOrientation() ,我们看到在之前的函数中mSneakEndPos = oldKf.getTranslate() + bone->getInitialPosition();注意这里的mSneakEndPos只是一个相对的向量值,也可以理解成方向,对每个模型都一样,然而实际中,每个模型有自己的运行方向,所以要先乘以getOrientation() ,才能像自己的运行方向发生位移,也就是绝对意义的位移。

 

接着Vector3 offset = rot * mModelNodes[i]->getOrientation() * -mSneakStartPos;这行代码比较难理解,如果你去掉这行代码,运行起来,没完成ANIM_ChOP的帧后,人会飞起来,那是因为在接近ANIM_CHOP时,人的方向此时不是在平面上,而是指向斜上方的,此时的mSneakEndPos和mSneakStartPos就将不是处在同一平面的关系了,此时如果不沿着负方向进行抵消既offset,那么人肯定飞起来。

 

这就是我对于SkeletonAnimation的理解,如有不妥,希望大家指正,共同学习。

 

posted on 2011-07-27 23:26  apapaxionga  阅读(4546)  评论(0编辑  收藏  举报