0

私はちょっと迷っています、

私はついにGPU上のMD5を使用してスキンメッシュで作業する時間ができました-マトリックスを介して、そして私は必死に正しい結果を得ることができません(それはとても間違っています)!

だからここに私がすることです:

  • MD5MESHファイルをロードします

  • バインドポーズメッシュを構築します(この1つのステップは正しく実行されます-ジオメトリは正しいです)

  • このようにbindposeとinversebindposeを作成します(ジョイントは親によって変換されるのではなく、ロードされた状態で使用されることに注意してください。必要ですか?):

        for(unsigned int i = 0; i < this->mMatricesCount; i++)
    {
        mat4 mBoneTranslation = mat4(
                1, 0, 0, mModel->mJoints[i].mPosition.x, 
                0, 1, 0, mModel->mJoints[i].mPosition.y, 
                0, 0, 1, mModel->mJoints[i].mPosition.z, 
                0, 0, 0, 1);
        mat4 mBoneRotation = mat4(mModel->mJoints[i].mOrientation);
    
        mat4 mBoneMatrix = mBoneTranslation * mBoneRotation;
    
        this->mMatrices[i] = mBoneMatrix;
        this->mInverseMatrices[i] = inverse(mBoneMatrix);
    }
    
  • MD5ANIMファイルをロードします(各フレームジョイントは次のように計算されます)。

                    if(mAnimation->mJoints[i].mParent < 0)
                    {
                        mAnimation->mFrames[mFrameID][i].mPosition = _position;
                        mAnimation->mFrames[mFrameID][i].mOrientation = _orientation;
                    }
                    else
                    {
                        MD5FrameJoint *mParent = &mAnimation->mFrames[mFrameID][mAnimation->mJoints[i].mParent];
    
                        float4 rpos = rotate(mParent->mOrientation, _position);
    
                        mAnimation->mFrames[mFrameID][i].mPosition = rpos + mParent->mPosition;
                        mAnimation->mFrames[mFrameID][i].mOrientation = mParent->mOrientation * _orientation;                           
                    }
    
  • 各フレームで、次のようなボーンマトリックスを作成します(現在、単純なテッセレーションされたクワッドのシーンにボーンが3つしかないため、現在最大4つのウェイトが問題を引き起こしていません-誤って回転します):

    for(unsigned int i = 0; i < this->mJoints; i++)
    {
        const mat4 mTranslate = mat4(
            1, 0, 0, this->mFramePositions[mFrame][i].x, 
            0, 1, 0, this->mFramePositions[mFrame][i].y, 
            0, 0, 1, this->mFramePositions[mFrame][i].z, 
            0, 0, 0, 1);
        const mat4 mRotate = mat4(this->mFrameOrientations[mFrame][i]);
    
        this->mOutput[i] = mTranslate * mRotate;
    }
    
  • そして、次のような頂点を計算します(CPUで実行し、GPUに移動したい):

            for(unsigned int j = 0; j < mSkinnedModel->mVertexCount[i]; j++)
            {
                float4 mResult = float4(0, 0, 0, 0);
    
                float4 mPosition = float4(mSkinnedModel->mVertices[i][j].mPosition[0],
                                          mSkinnedModel->mVertices[i][j].mPosition[1],
                                          mSkinnedModel->mVertices[i][j].mPosition[2],
                                          1.0f);
    
                for(unsigned int k = 0; k < 4; k++)
                {
                    mResult += (mAnimatedBones[mSkinnedModel->mVertices[i][j].mBoneIndices[k]] * mPosition) * mSkinnedModel->mVertices[i][j].mBoneWeights[k];
                }
    
                mBuffer[j].mPosition[0] = mResult.x;
                mBuffer[j].mPosition[1] = mResult.y;
                mBuffer[j].mPosition[2] = mResult.z;
                mBuffer[j].mPosition[3] = 1.0f;
            }
    

メッシュ+アニメーションファイルは正しいです(それらをエクスポートして3Dモデリングソフトウェアにインポートしました、動作します!)

現在、数学ライブラリに問題がないかどうかをテストしていますが、これまでのところ問題はないようです(行列の反転は良好、クォータニオンの乗算も、クォータニオンからの行列のテスト、...)

そして、私に記事を指摘しないでください。それらのいくつか(マトリックスとソースコードを使用してGPUでMD5スキニングを行うものを含む)を開いて、何が悪いのかを理解しています。これまでのところ、コードは私のものとほとんど同じように見えます。それはいくつかの小さなくだらない詳細になります。

誰もが教祖がどこにいるのかわかりますか?

4

1 に答える 1

4

(それはとても間違っています)!

1枚の写真は何千もの言葉の価値があります。あなたは写真を投稿しませんでした。それで、あなたは何を期待しましたか?

 mat4 mBoneTranslation = mat4(
        1, 0, 0, mModel->mJoints[i].mPosition.x, 
        0, 1, 0, mModel->mJoints[i].mPosition.y, 
        0, 0, 1, mModel->mJoints[i].mPosition.z, 
        0, 0, 0, 1);

これはOpenGLマトリックスであると想定されていますか?OpenGLマトリックスの方向は異なり、それらのレイアウトは、転置されたすべてのマトリックスを格納する場合を除いて、DirectXで使用されるD3DXMATRIX/D3DMATRIXと完全に同じです。

非転置変換行列:

 mat4 translation = mat4(
        1, 0, 0, 0, 
        0, 1, 0, 0, 
        0, 0, 1, 0, 
        x, y, z, 1);

そしてもちろん、転置されていない行列は逆の乗算順序を使用します。

mat4 combined = rotation * translation;

また、乗算する代わりに、最後の行(転置されていない)を単純にコピーできます。

mat4 combined = rotation;
combined.rows[3] = translation.rows[3]; 

または列(転置)。

また、この部分では:

 this->mOutput[i] = mTranslate * mRotate;

逆骨変換を計算に含めるのを忘れました。Withotuインバースボーントランスフォームスキンメッシュは「爆発」します。

(転置行列)である必要があります

 this->mOutput[i] = mTranslate * mRotate * mInverseMatrices[i];

または(転置されていない場合)。

 this->mOutput[i] = mInverseMatrices[i] * mRotate * mTranslate;

- 編集 -

ジョイント階層変換を誤って計算している可能性があります。

{
    MD5FrameJoint *mParent = &mAnimation->mFrames[mFrameID][mAnimation->mJoints[i].mParent];

    float4 rpos = rotate(mParent->mOrientation, _position);

    mAnimation->mFrames[mFrameID][i].mPosition = rpos + mParent->mPosition;
    mAnimation->mFrames[mFrameID][i].mOrientation = mParent->mOrientation * _orientation;                           
}

それは通常行われている方法ではありません。

すべてのジョイントのローカル変換を計算します。

this->localTransform = positionMatrix * rotationMatrix

親変換と子変換を乗算して、すべての関節のワールド変換を計算します

this->worldTransform = parent->worldTransform * this->localTransform;

ルートノードの場合、ワールド変換は、オブジェクトマトリックス(メッシュを変換する)とローカル変換の乗算です。

root->worldTransform = worldMatrix * root->localTransform;

階層内の行列(任意の行列)にスケーリングコンポーネントがある場合、スキームは正しく機能しません

これで問題が解決しない場合は、誰かにコードをデバッグしてもらう必要があります。私は無料でデバッグをしていませんが、SOで「フリーランス」サービスを提供することは許可されていません(AFAIK)。だからあなたは他の誰かを見つける必要があります。

もう1つは、「白い点を使用して「あるべき場所」を示す」のではなく、アニメーション化されたmd5形式を表示でき、正しく実行できることが保証されているアプリケーションを使用する必要があることです。それ以外の場合、白い点が正しい位置にあるという保証はありません。

于 2012-05-09T17:46:28.073 に答える