2
votes

I am new to the terms of skeletal animation and I have read that, to animate a mesh using skeletal I would have to use a hierarchy of bones which I did making each bone node in my scene graph and then to deform the mesh I have to get the inverse absolute matrix of the bone before interpolation (which I believe is what they call the pose) multiply that for the interpolated absolute matrix of the bone to get transition matrix and the to deform the mesh I would have to multiply the vertex times the transition matrix times the weight and sum all this result with any other bone that deform the same vertex.

to be more specific to get the absolute of each bone I do this

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();
   }
}

now I get the inverse of this absMatrix matrix before any interpolation that change the relativeMatrix one time only so to do the vertex deformation is this function

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;
}

now that doesn't work for me because every vertex rotate around the center of the mesh axis instead of the parent of bone the bone that deform the vertices, I thought it was logical considering that transition = InverAbs *absoulteMatrix will get me the the amount of rotation the bone has gain due to the interpolation so assuming it rotate 20 degrees the vertices will rotate 20 deg from the vertices origin so I guess I am missing something to make the vertices rotation around the parent of the bone which is deforming them, please help me.

so this is how I do the interpolation just that is not to the absolute matrix but to the relativeMatrix the code I update the absolute is the one above.

//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);

    }

and yes I did this and work multiply the bone by it's inverse absolute and then by the absolutematrix and it works perfectly but to many multiplication are happening, like.

//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
Have you tried applying the "inverse absolute matrix of the bone" to your verts directly, and drawing them, to make sure this transform is behaving as intended? This operation should take the verts into 'bone space', that is, verts 'close to the bone' should end up 'close to the origin'. Confirming that this transform is behaving as expected may help narrow down the problem.WeirdlyCheezy
Also, can you briefly explain how you calculate the "interpolated absolute matrix"? If I'm following, this matrix should only contain the transformation between the 'neutral' pose and the current interpolated pose of the bone, specified in mesh space; is this correct?WeirdlyCheezy
when I multiply the verts by the inverse absolute of the bone before the interpolation it bring the verts close the origin and when , multiply by the absolute after interpolation bring then back plus the changes and that way the animation work as it supposed to but that way I have to have to multiplication for each verts.Jman
I'm still a little confused; you say in your intro that you calculate the transition matrix by multiplying inversePose by the absoluteInterpolated, but this is the same multiplication you do in your second CMesh::skinMesh. Why are the two skinMesh behaving differently? Are you sure transitionMatrix is being calculated the way you say it is?WeirdlyCheezy

1 Answers

0
votes

the code is working now it look like my matrix multiplication was in wrong order because it did it like inverPose * absoluteMatrx and was wrong now it is absoluteMatrx * inverPose and works fine