骨骼动画初步完成

骨骼动画初步完成

        演示程序下载地址:这里 

骨骼动画是角色动画的重要组成部分,因为只有把骨骼的位置摆准确了才能正确反映角色地姿势,后面的蒙皮动画就好做了。花了我十多天的时间,一直在琢磨着如何顺利地进行骨骼位置的变换,以达到MikuMikuDance中的样子。我做了很多实验,这回也算是有一定的成果吧,虽然关于反向运动学(Inverse Kinematics,IK)的部分我还没有吃透,不过做出一个东西,想分享分享。

         关于骨骼的实现,一开始使用的是多叉树,后面发现使用多叉树进行遍历并不是那么好,因为要求的是层序遍历,我写过二叉树,发现层序遍历比较难实现,而先序遍历需要一个栈数据结构来保存父骨骼的变换,显得有些多余。我从PMD格式中读取骨骼数据,在PMD中骨骼数据是线性存储的,于是我想能不能也用线性存储这些数据,再辅以一些数据结构实现多叉树的功能?

         最终我发现了多值散列表(MultiHash),我是这么做的,在骨骼读入后不久做一次遍历,以每个骨骼的索引为键,骨骼的层次关系(Hierachy)为值来建立多值散列表。因为模型的骨骼旋转和平移数据都是相对于父骨骼,考虑到要使用VBO,无法像以前那样push和pop模型矩阵,因此有必要将相对的旋转和平移转为绝对的旋转和平移。这个时候只需要对散列表中某一骨骼的层次关系进行遍历然后累加即可。下面是实现上述功能的关键代码:

voidMMDAnimationPrivate::InitBoneHierarchy( void )// 初始化骨骼的层次(孩子在尾端,祖先在首端)
{
   // 需要MMDRenderHandler的骨骼列表
   QVector<MMDRenderHandler::Bone>& bones = m_pRenderHandler->Bones();
 
   for ( int i = 0; i < bones.size( ); ++i )
    {
       quint16 parent = bones[i].parent;
 
       m_BoneHierarchy.insert( i, i );// 先将自己压入层次中
       while ( parent != quint16( -1 ) )
       {
           m_BoneHierarchy.insert( i, parent );// 将父骨骼压入层次中
           parent = bones[parent].parent;
       }
    }
}

……

// 旋转进行叠加
for ( int i = 0; i < bones.size( ); ++i)
{
   Quaternion absRotation;
   foreach ( quint16 index, m_BoneHierarchy.values( i ) )
    {
       absRotation *= bones[index].rotation;
    }
   bones[i].rotation = absRotation;
}

         这里给出运行程序截图:

 骨骼动画初步完成_第1张图片


你可能感兴趣的:(动画,qt,OpenGL,骨骼动画)