0

四元数で表されるワールド空間に配置されたオブジェクト X があり、後者の X_Base を呼び出します。オブジェクト X からオフセットされ、Y_Base と呼ばれるそのクォータニオン マトリックスによって表される別のオブジェクト Y があります。

これは時間 0 での位置であり、時間 1 で位置を変更します。オブジェクト Y はその軸を中心にある角度で回転します。これが新しいクォータニオンであることがわかります。それは Y_New です。X は Y に対して相対的に回転するため、オフセットが時間 0 に保持されます。必要なのは基本的に X_New です。

英語では、モデルを手動でスキンしようとしています。ボーンから少し離れたメッシュがあり、ボーンが回転するときにこのオフセットを維持する必要があります。どういうわけか、どの式を使用する必要があるかについて明確な答えが見つかりません。

アドバイスをいただければ幸いです。

もう少し明確にします:

太陽系を想像してみてください。地球は太陽とその軸の周りを回転しています。月が地球の周りを回転するのではなく、地球からオフセットされ、地球の位置をどのように変換してもオフセットが維持されるようにしましょう。私が必要としているのは、月が time1 でどこにあるかを調べ、time0 で月がどこにあり、time0 と time1 で地球がどこにあったかを知ることです。

4

3 に答える 3

1

モデルにスキンを適用できました。これが私がしたことです:

  1. 「太陽」は私のモデルの骨です。(ワールド空間で) 平行移動および回転できます。「Earth」は、モデルとともに回転/平行移動するモデル上のカスタム ポイントです。私の目標は、任意のポイントを選択してスキンを適用することはできないことを意味するためです。後者はモデルとともに移動する必要があります。

  2. 私のアプリには 2 つのメソッドがあります。Initialize メソッドでは、モデルは常に T-Pose になっています。

  3. Initialize メソッドでは、太陽と地球の位置を 2 として読み取りますXNA Matrix

  4. 初期化では、私も計算します

    Vector3 Difference = TPoseEarth.Translation - TPoseSun.Translation;
    
  5. 最後に、Initialize で Sun の Matrix を分解して、純粋な Sun の回転行列 (変換なし) を取得します。これは、モデルのボーンの Sun に、T-Pose でも非恒等行列が割り当てられているように見えるためです。そのようです:

    Vector3 scale;
    Quaternion rotation;
    Vector3 tra;
    TPoseSun.Decompose(out scale, out rotation, out tra);
    
    BaseSunRot = Matrix.CreateFromQuaternion(rotation);
    
  6. Update メソッドで、地球と太陽の現在のワールド位置を取得します。太陽のマトリックスを分解して純粋な回転を取得します (再び!)。

    Vector3 scale;
    Quaternion rotation;
    Vector3 tra;
    Sun.Decompose(out scale, out rotation, out tra);
    
    Matrix SunRot = Matrix.CreateFromQuaternion(rotation);
    
  7. ベース回転の逆数に新しい回転を掛けて、固有のボーンと太陽の回転を計算します。

    Matrix UniqueRot = Matrix.Invert(BaseSunRot) * SunRot;
    
  8. 地球の平行移動を差 (太陽の T ポーズ位置と地球の T ポーズ位置の間) と等しくなるように設定します。

    Matrix Earth = Matrix.Identity;
    Earth.Translation = Difference;
    
  9. Earth マトリックスに固有のボーン (Sun) の回転を掛けます。

    Earth *= UniqueRot;
    
  10. フレーム間の可能な変換を提供するために、Sun の CURRENT 位置を追加します。

    Earth += Sun.Translation;
    
  11. 終わり。Earth マトリックスには、スキンされた頂点に関するすべての必要な情報が含まれています。

100%確かではありませんが、これは基本的に、世界中の任意のボーンに対して任意のポイントをスキニングする方法に関するマニュアルのように感じます (つまり、初期オフセットを維持したまま回転/移動します)。問題は、コードが最適化されていないことです:)。誰かがそれを最適化する方法について何かアイデアを持っているなら、私はそれを大いに感謝します.

特に、二重行列分解をスキップして、完全な ScaleRotationTranslation 行列を単純に乗算できるかどうかを知りたいですか? 私はそれを試みていますが、成功していません。

于 2013-07-16T18:22:35.347 に答える
0

まず第一に、四元数ではなく行列を使用すると、この問題をより簡単に解決できると思います。クォータニオンには回転のみが含まれるため、平行移動 (位置) をベクトルに個別に格納する必要がありますが、行列には​​回転と平行移動の両方が含まれます。

太陽系の場合、太陽と地球の両方にワールド マトリックスを割り当てます。太陽は、その中心がワールド原点 [0,0,0] になるように配置されます。太陽の行列には、y 軸を中心とした回転が含まれます (太陽を回転させます)。

sun.World = Matrix.CreateRotationY(angle);

地球は太陽に対して相対的な位置になります。この値は一定のままで、変換マトリックスの作成に使用されます。次に、この行列に太陽の世界行列を掛けると、地球の世界行列が得られます。

earth.World =
    Matrix.CreateTranslation(earth.Position) *
    sun.World;

行列の乗算の順序が重要であることに注意してください。これにより、時間の経過とともに地球の位置が太陽の周りを回転します。次のように、回転を地球に適用して、その軸を中心に回転させることもできます。

earth.World =
    Matrix.CreateRotationY(angle) *
    Matrix.CreateTranslation(earth.Position) *
    sun.World;

月を地球の周りの軌道に配置するには、同じ原理を適用できます。

moon.World =
    Matrix.CreateTranslation(moon.Position) *
    earth.World;

クォータニオンを使用する必要がある場合は、マトリックスとの間で変換できます。

Quaternion quaternion = Quaternion.CreateFromRotationMatrix(matrix);
Vector3 translation = matrix.Translation;

Matrix matrix = Matrix.CreateFromQuaternion(quaternion);
matrix = Matrix.CreateTranslation(translation) * matrix;
于 2013-07-12T09:23:01.940 に答える