2011-09-29 20 views
11

私は自分自身のCOLLADA輸入業者を書いています。私はかなり遠くに、メッシュや材料などを載せています。しかし、私はアニメーション、特に関節回転に悩まされました。COLLADA:間違ったスペースの逆バインドポーズ?

私はメッシュをスキニングのため使用している式は単純明快です:

weighted; 
for (i = 0; i < joint_influences; i++) 
{ 
    weighted += 
     joint[joint_index[i]]->parent->local_matrix * 
     joint[joint_index[i]]->local_matrix * 
     skin->inverse_bind_pose[joint_index[i]] * 
     position * 
     skin->weight[j]; 
} 
position = weighted; 

そして限り文献が関係しているように、これは正しい式です。現在、COLLADAはジョイントの回転の2つのタイプ、ローカルとグローバルを指定しています。ジョイントのローカル変換を取得するには、回転を連結する必要があります。

COLLADAのマニュアルでは、ジョイントのローカルローテーションとジョイントのグローバルローテーションが区別されません。しかし、私が見たほとんどのモデルでは、ローテーションのIDはrotate(グローバル)またはjointOrient(ローカル)のいずれかになります。

グローバルローテーションを無視してローカルローテーションのみを使用すると、モデルのバインドポーズが取得されます。しかし、ジョイントのローカル変換にグローバルローテーションを追加すると、奇妙なことが起こり始めます。

これはグローバルな回転を使用することなく、次のとおりです。

Bind pose

そして、これは世界的なローテーションである:私はラインを使用してスケルトンを描くが、中にいます、両方のスクリーンショットで

Weird

ジョイントがメッシュの内側にあるため、最初は目に見えません。 2番目のスクリーンショットでは、頂点はすべての場所にあります!

Collada viewer

それは見えにくいですが、あなたは関節が第二のスクリーンショットの正しい位置にあることがわかります。

比較のために、これは、第二のスクリーンショットどのように見えるかです。

しかし今、奇妙なことです。私は逆バインドを無視した場合COLLADAで指定されたポーズをし、代わりにジョイントの親の逆を取るローカル変換ジョイントのローカル時刻を変換、私は次を得る:

このスクリーンショットで

enter image description here

私が描いています各頂点から影響を受ける関節までの線。式は、今となっているため、私はバインドポーズを取得するということは、それほど不思議ではない:

world_matrix * inverse_world_matrix * position * weight 

しかし、それは、COLLADAの逆バインドポーズと疑うに私をリードし、間違った空間です。

私の質問は次のとおりです。COLLADAはどの空間で逆バインドポーズを指定していますか?そして、逆バインドポーズを必要なスペースに変換するにはどうすればよいですか?

+0

1.4.1仕様の「COLLADAでのスケルトンのスキニング」の項を読んでいますか?あなたの数式は外に見える – jterrace

答えて

10

私は私の値を私がAssimp(オープンソースモデルローダー)から読み込んだものと比較することから始めました。コードを踏んで、バインドマトリックスと逆バインドマトリックスを作成した場所を調べました。

は最終的に私は、次のものが含まれ、SceneAnimator::GetBoneMatricesで終わった:メッシュは何も変換されないため

// Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose 
// Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform 
for(size_t a = 0; a < mesh->mNumBones; ++a) 
{ 
    const aiBone* bone = mesh->mBones[a]; 
    const aiMatrix4x4& currentGlobalTransform 
     = GetGlobalTransform(mBoneNodesByName[ bone->mName.data ]); 
    mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix; 
} 

globalInverseMeshTransformは、常にアイデンティティです。 currentGlobalTransformはバインドマトリックスであり、ジョイントのローカルマトリックスと連結されたジョイントの親ローカルマトリックスです。 mOffsetMatrixは逆バインドマトリックスで、スキンから直接取り出されます。

私はこれらの行列の値を自分で調べました(私は時計のウィンドウでそれらを比較しました)、それらはまったく同じで、おそらく0.0001%であったが、それは重要ではありません。だから、Assimpのバージョンの仕事と私の公式は同じですか?

は、ここで私が得たものです:

Inversed!

Assimpが最終的にスキンシェーダに行列をアップロードし、彼らは次のようにします。

helper->piEffect->SetMatrixTransposeArray("gBoneMatrix", (D3DXMATRIX*)matrices, 60); 

Waaaaait秒。アップロードしたファイルはです。?それは簡単ではありません。とんでもない。

enter image description here

うん。

他の何かが間違っていました:の座標系を右のシステム(センチメートルからメートル)に変換していました。スキニング行列を適用しています。行列が元の座標系用に設計されているため、完全に歪んだモデルになります。

FUTUREのGoogler

  • は(回転、平行移動、スケール、など)すべてのノードの変換は、あなたがそれらを受け取るためにをお読みください。
  • ジョイントのローカルマトリックスに連結します。
  • ジョイントの親を取得し、それにローカルマトリックスを掛けます。
  • バインドマトリックスとして保存します。
  • 皮膚の情報を読んでください。
  • ジョイントの逆バインドポーズマトリックスを格納します。
  • 各頂点に対してのジョイントを格納します。
  • 乗算逆バインドとバインド行列スキニング行列それを呼び出す、マトリックスを提起し、それを転置。
  • 乗算回関節重量位置にスキニング行列加重位置に追加します。
  • 重み付け位置を使用してレンダリングします。

完了!

+0

古い質問が非常に役立ちます!どうもありがとうございました! – Jas

1

ところで、最後に行列を入れ替えるのではなく、読み込み時に行列を転置すると(アニメーション化するときに問題になります)、乗算を別々に行いたいと思っています(上で使用した方法は、

DirectXでは、ファイルからロードされた行列を転置してから(以下の例では単純にするために単純にバインドポーズを適用しています) :

XMMATRIX l_oWorldMatrix = XMMatrixMultiply(l_oBindPose、in_oParentWorldMatrix);

XMMATRIX l_oMatrixPallette = XMMatrixMultiply(l_oInverseBindPose、l_oWorldMatrix);

XMMATRIX l_oFinalMatrix = XMMatrixMultiply(l_oBindShapeMatrix、l_oMatrixPallette);

関連する問題