骨骼动画

时间:2012-10-26 20:18:52

标签: c++ skinning skeletal-mesh

我是骨骼动画术语的新手,我已经读过,要使用骨架制作网格动画,我必须使用骨骼层次结构,我在场景图中制作每个骨骼节点,然后使网格变形我必须在插值之前得到骨骼的逆绝对矩阵(我相信它们称之为姿势)乘以骨骼的插值绝对矩阵以获得转移矩阵并且要使网格变形我将不得不乘以顶点乘以转移矩阵乘以权重,并将所有这些结果与任何其他使相同顶点变形的骨骼相加。

更具体地得到每个骨骼的绝对值我这样做

void CNode::update()
{
   if(this->Parent!=null)
      absMatrix = this->Parent->absMatrix * relativeMatrix;
   else
     absMatrix = RelativeMatrix;

   for(int n=0; n<childs.count; n++)
   {
      childs[n]->update();
   }
}

现在我在任何仅改变relativeMatrix一次的插值之前得到了这个absMatrix矩阵的逆矩阵 所以要做顶点变形就是这个函数

void CMesh::skinMesh(){
     CVec3 vec;
     for(int n=0; n < vertex.count; n++)
     {        
        vec.clear();
        for(int i=0; i < vertex[n].weight.count && vertex[n].bindBone[i] ; i++)
        {
            vec+= vertex[n].vec * vertex[n].bindBone[i]->transitionMatrix * vertex[n].weight[i];
        }
        outVertex[n] = vec;
}

现在这对我不起作用,因为每个顶点围绕网格轴的中心旋转而不是骨骼的父骨骼,这会使顶点变形,我认为这是合乎逻辑的 transition = InverAbs * absoulteMatrix将获得骨骼因插值而获得的旋转量,因此假设它旋转20度,顶点将从顶点原点旋转20度,所以我想我错过了一些使顶点旋转的东西骨头的父母正在变形,请帮助我。

所以这就是我如何进行插值,这不是绝对矩阵,而是相对于相关矩阵,我更新绝对的代码是上面的那个。

//CAnimateObject is a decendent class of CNode
void CAnimateObject::UpdateFrame(unsigned AniNum, float Time)
    {
        float fInterp;

        if(m_AniCount > AniNum)
        {
            CKeyFrame *CurAni = &Ani[ AniNum ];
            if(CurAni->Pos.list.count>0)
            {
                CFrame<CVector3>::CKEY *begin, *end;

                if( CurAni->Pos.getBetweenKeys(&begin, &end, Time, fInterp)){
                    m_Pos.x = begin->Object->x + (end->Object->x - begin->Object->x) * fInterp;
                    m_Pos.y = begin->Object->y + (end->Object->y - begin->Object->y) * fInterp;
                    m_Pos.z = begin->Object->x + (end->Object->z - begin->Object->z) * fInterp;
                }
            }
            if(CurAni->Scale.list.count>0)
            {
                CFrame<CVector3>::CKEY *begin, *end;
                if( CurAni->Scale.getBetweenKeys(&begin, &end, Time, fInterp)){
                    m_Scale.x = begin->Object->x + (end->Object->x - begin->Object->x) * fInterp;
                    m_Scale.y = begin->Object->y + (end->Object->y - begin->Object->y) * fInterp;
                    m_Scale.z = begin->Object->x + (end->Object->z - begin->Object->z) * fInterp;
                }
            }
            if(CurAni->Rot.list.count > 1)
            {
                CFrame<CQuaternion>::CKEY *begin, *end;

                if( CurAni->Rot.getBetweenKeys(&begin, &end, Time, fInterp)){
                    m_Qrel.SLERP(*begin->Object, *end->Object, fInterp);
                }
            }else
                if(CurAni->Rot.list.count==1)
                    m_Qrel = *(CQuaternion*)CurAni->Rot.list.start[0].Object;
        }
                CMatrix4 tm, scale;
    scale.identity();
    tm.identity();
    scale.Scale(m_Scale.Get());
    tm.fromQuaternion(m_Qrel);
    m_Rel = tm * scale;
    m_Rel.Translate(m_Pos);

    }

并且是的,我做了这个并且工作将骨骼乘以它的绝对值,然后是绝对矩阵,并且它完美地工作但是很多乘法正在发生,比如。

//inversePose is the absoluteMatrix before applying the interpolation of the relative matrix
void CMesh::skinMesh(){
     CVec3 vec;
     for(int n=0; n < vertex.count; n++)
     {            
        outVertex[n].clear();
        for(int i=0; i < vertex[n].weight.count && vertex[n].bindBone[i] ; i++)
        {
            vec = vertex[n].vec3 * vertex[n].bindBone[i]->inversePose; 
            vec = vec * vertex[n].bindBone[i]->absMatrix * vertex[n].weight[i];
            outVertex[n]+= vec;
        }

}

1 个答案:

答案 0 :(得分:0)

代码正在运行现在它看起来我的矩阵乘法是错误的顺序,因为它像inverPose * absoluteMatrx那样做错了现在它是absoluteMatrx * inverPose并且工作正常