2

私は骨格アニメーションの用語に不慣れで、骨格を使用してメッシュをアニメーション化するには、シーングラフで各ボーンノードを作成したボーンの階層を使用する必要があることを読みました。次に、メッシュを変形する必要があります補間前にボーンの逆絶対行列を取得します(これは彼らがポーズと呼んでいるものだと思います)。補間されたボーンの絶対行列を乗算して遷移行列を取得し、メッシュを変形するには、頂点に乗算する必要があります。トランジション マトリックスに重みを掛けて、このすべての結果を、同じ頂点を変形する他のボーンと合計します。

各ボーンの絶対値を取得するために、より具体的にするには、これを行います

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 を 1 回だけ変更する補間の前に、この 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 度回転するので、頂点を変形しているボーンの親の周りで頂点を回転させるための何かが欠けていると思います。助けて。

これは、絶対行列ではなく、relativeMatrix に対する補間を行う方法です。絶対行列を更新するコードは上記のものです。

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

}
4

1 に答える 1

0

コードが機能するようになりました。行列の乗算が間違った順序で行われたように見えます。これは、inverPose * absoluteMatrx のように実行され、間違っていたため、absoluteMatrx * inverPose であり、正常に動作します。

于 2012-11-02T19:28:12.193 に答える