动作融合是一种将当前动作跟目标动作中骨骼位置进行动态插值的算法。得到的结果可以使角色的动作表现更加的平滑。
irrlicht引擎也提供了相应的功能,下面就这个功能的使用方法进行说明。
功能函数
引用下irrlicht的代码
//! Sets the transition time in seconds (note: This needs to enable joints, and setJointmode maybe set to 2)
//! you must call animateJoints(), or the mesh will not animate
void CAnimatedMeshSceneNode::setTransitionTime(f32 time)
{
const u32 ttime = (u32)core::floor32(time*1000.0f);
if (TransitionTime==ttime)
return;
TransitionTime = ttime;
if (ttime != 0)
setJointMode(EJUOR_CONTROL);
else
setJointMode(EJUOR_NONE);
}
使用这个函数,就可以在播放下一个动作的时候自动进行插值。但是,只使用这一个函数,只会让你的模型骨骼便的不受控制。
好在这个时候我们注意到函数前面的两行注释,什么意思呢?
设置融合时间,单位秒(注意:这个需要有骨骼,并且设置骨骼模式为2,就是EJUOR_CONTROL)
你必须调用animateJoints(),否则动画可就不动了哟
然而注释没有提到的是,你必须没一帧都调用animateJoints(),否则动画还是不动哟
这里有英文版解释
Now if you also want your mesh to animate using any built-in animation in the model, call:
Node->animateJoints();
In your game loop, before drawAll().
意思就是你如果要播已有的动画,你需要在游戏的主循环中调用animateJoints();
步骤
- 设置 setTransitionTime(f32 time)
- 每帧调用 animateJoints()
做完这两件事,你就可以可到动作融合可以正常使用了。
更多的要求
但是还不够。当功能正常使用的时候,我们可能会有更多的需求:
- 对不同的动作设置不同的动作融合
- 某些特别的动作不要融合
前面的两个步骤,在动作融合及不融合来回切换的时候会导致模型节点不受控制。有两处问题,再看代码
void CAnimatedMeshSceneNode::setTransitionTime(f32 time)
{
const u32 ttime = (u32)core::floor32(time*1000.0f);
// 问题2
if (TransitionTime==ttime)
return;
TransitionTime = ttime;
if (ttime != 0)
setJointMode(EJUOR_CONTROL);
else
setJointMode(EJUOR_NONE); // 问题1
}
问题1:在把动画的融合设置为0时,期望的是关闭动作融合。但实际导致骨骼模式变成NONE,子节点不能正常变换位置。手动调用 node->setJointMode(scene::EJUOR_READ)解决
问题2:试想下面的操作过程,
- 设置融合时间setTransitionTime(0.3)
- 关闭动作融合setJointMode(scene::EJUOR_READ)
- 再次设置setTransitionTime(0.3)
第三步操作时,代码在 if (TransitionTime==ttime)
处返回,于是没有自动执行setJointMode(EJUOR_CONTROL);
所以结论是:在setTransitionTime时同时设置setJointMode(MODE)来避免这个问题
if (m_AniPlayData.blend > 0) {
node->setTransitionTime(m_AniPlayData.blend);
node->setJointMode(irr::scene::EJUOR_CONTROL);
} else {
node->setTransitionTime(0);
node->setJointMode(irr::scene::EJUOR_READ);
}
最后完整的步骤是:
- 设置 setTransitionTime(f32 time)
- 同1时设置 setJointMode(MODE);
- 每帧调用 animateJoints()
至此,动画融合就完全可用了。
PS:如果你的主模型的子节点也需要做动画的话,对子节点也需要上述三个步骤。