動作融合是一種將當前動作跟目標動作中骨骼位置進行動態插值的算法。得到的結果可以使角色的動作表現更加的平滑。
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:如果你的主模型的子節點也需要做動畫的話,對子節點也需要上述三個步驟。