2

移動と回転がグローバル空間で表現される階層的なスケルトンがあります。スケルトンをローカル座標に変換してから戻す必要があります。翻訳には問題ありませんが、回転が機能していないようです。

最初は回転行列を持っていましたが、オイラーやクォータニオンに簡単に変換でき、それぞれを操作してみました。Irrlicht エンジンの数学ライブラリを使用しています。

したがって、私のコードはすべてのボーンを通過し、ボーンに次の親がある限り変換を適用します。

グローバルからローカルへ:

for(; iter != absolutePose.end(); iter++)
{
    if(hierarchy->find(iter->boneID) != hierarchy->end())
    {
        BoneID parentNodeID = hierarchy[iter->boneID];
        relativePose[iter->boneID].position.X = iter->position.X - absolutePose[parentNodeId].position.X;
        relativePose[iter->boneID].position.Y = iter->position.Y - absolutePose[parentNodeId].position.Y;
        relativePose[iter->boneID].position.Z = iter->position.Z - absolutePose[parentNodeId].position.Z;

                    ////Rotation Part/////////
        float pq[4] ={0.0,0.0,0.0,0.0};
        MatrixToQuaternion(absolutePose[parentNodeId].orientation, pq);

        irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
        irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);

        quat = quat.makeInverse();

        quat = quat*parentquat;

        float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
        QuaternionToMatrix(newQuat,relativePose[iter->first].orientation);

    }
    else // top bone
    {
        relativePose[iter->boneID].position.X = iter->position.X;
        relativePose[iter->boneID].position.Y = iter->position.Y;
        relativePose[iter->boneID].position.Z = iter->position.Z;

        relativePose[iter->boneID].orientation = iter->second.orientation;
    }
}

次に、ローカルからグローバルへ:

for(; iter != relativePose.end(); iter++)
    {
        absolutePose[iter->boneID].position.position = iter->position;
        auto nextParent = hierarchy->find(iter->boneID);
        while(nextParent != hierarchy->end())
        {
            absolutePose[iter->boneID].position.X += relativePose[nextParent->boneID].position.X;
            absolutePose[iter->boneID].position.Y += relativePose[nextParent->boneID].position.Y;
            absolutePose[iter->boneID].position.Z += relativePose[nextParent->boneID].position.Z;

            ////Rotation part///
            float q[4] ={0.0,0.0,0.0,0.0};
            MatrixToQuaternion(relativePose[iter->boneID].orientation, q);

            float pq[4] ={0.0,0.0,0.0,0.0};
            MatrixToQuaternion(relativePose[nextParent->boneID].orientation, pq);
            irr::core::quaternion quat(q[0],q[1],q[2],q[3]);
            irr::core::quaternion parentquat(pq[0],pq[1],pq[2],pq[3]);

            quat = parentquat*quat;

            float newQuat[4] = {quat.X, quat.Y, quat.Z, quat.W};
            QuaternionToMatrix(newQuat,absolutePose[iter->boneID].orientation);
            //////

            nextParent = hierarchy->find(nextParent->boneID);
        }
    }

しばらくの間、これに問題があり、マトリックスモードのままにして、オイラー角にも切り替えようとしました。誰かが私が間違っていることを理解するのを手伝ってくれますか?

4

1 に答える 1

4

行列または四元数を使用するかどうかは問題ではありません。ここではオイラー角を使用しないことをお勧めします。問題は、ローカル座標に変換するときに親の代わりに子クォータニオンを反転していて、グローバル座標に変換するときに回転を伝播していないことです。

考慮してください (方向が右側の列ベクトルに適用されると仮定します):

q_1、 q_2 、およびq_3は、チェーン内の 3 つのボディのグローバル方向です相対方向r_2およびr_3を使用する場合は、親の回転をその子孫から取り出す必要があります。したがって、q_2 = q_1 * r_2およびq_3 = q_1 * r_2 * r_3 = q_2 * r_3であることがわかります。

相対値を解くと、r_3 = q_2' * q_3 と、同様に r_2 = q_1' * q_2 ( q_2'は逆行列または四元数) が得られます。

グローバルからローカルに変換するには、次のことを覚えておく必要があります。

q_3 = q_1 * r_2 * r_3

親の向きはすべて、最終的な子孫にまで伝播する必要があります。したがって、再帰を使用して、子からルートまでのすべての向きの変更を取得するか、親から始めて、子をたどって各リンクですべての向きの変更を伝播/蓄積する必要があります。

後付けとして、ルートノードがそれがそのrelativePoseと等しいことを認識していることも確認する必要があると思いますabsolutePose。そうしないと、問題が発生します。

于 2012-12-10T20:24:03.093 に答える