7

速度ベクトルに沿って移動している発射体オブジェクトがあります。オブジェクトが常に速度ベクトルの方向を向いていることを確認する必要があります。さらに、行列ではなくクォータニオンを使用してオブジェクトの回転を表現しています。

最初のステップは直交基底を見つけることであることを私は知っています:

forward = direction of velocity vector
up = vector.new(0, 1, 0)
right = cross(up, forward) 
up = cross(forward, right)

基底を回転クォータニオンに変換するにはどうすればよいですか?

解決

注:答えを提供してくれたNoel Hughesの功績を称えたいと思いますが、私自身の経験から明らかにしたいと思います。擬似コードは次のとおりです。

   vec3 vel = direction of velocity vector
   vec3 forward = (1, 0, 0)  // Depends on direction your model faces. See below.
   vec3 axis = cross(forward, vel)
   if (axis == 0) then quit // Already facing the right direction!
   axis = normalize(axis)
   float theta = acos(vel.x/sqrt(vel.x^2, vel.y^2, vel.z^2))
   quat result = (0, axis.y * sin(theta/2), axis.z * sin(theta/2), cos(theta/2)

クォータニオンの最後の要素はスカラー部分であり、最初の3つの要素は虚数部分です。また、上記の擬似コードは、「モデル空間」内のオブジェクトが正のx軸を指していることを前提としています。私の場合、オブジェクトは実際には正のy軸を下に向けていました。この場合、次の変更を行いました。

   vec3 vel = direction of velocity vector
   vec3 forward = (0, 1, 0)  // Note that y-component is now 1
   vec3 axis = cross(forward, vel)
   if (axis == 0) then quit 
   axis = normalize(axis)
   float theta = acos(vel.x/sqrt(vel.x^2, vel.y^2, vel.z^2))
   quat result = (axis.x * sin(theta/2), 0, axis.z * sin(theta/2), cos(theta/2)
   // Note that SECOND component above is now 0
4

3 に答える 3

4

縦軸を速度ベクトルに揃える以外は、発射体の向きを気にせず、縦軸は(1、0、0)のx軸であると仮定します。

あなたは正しい方向に進んでいます。速度ベクトルを正規化します。(vx、vy、vz)/ sqrt(vx ^ 2 + vy ^ 2 + vz ^ 2)x軸と交差し、結果を正規化します-(0、yn、zn)-これは回転ですクォータニオンの軸。回転角は、単純にtheta = vx / sqrt(vx ^ 2 + vy ^ 2 + vz ^ 2)の逆余弦です。結果として得られるクォータニオンは次のようになります。

(0、yn、zn)sn(theta / 2)cos(theta / 2)

ご不明な点がございましたら、お気軽にお問い合わせください。

ノエルヒューズnhughes1ster@gmail.com

于 2009-10-27T04:07:25.830 に答える
0

タイトルに一致するソリューションは次のとおりです。「直交基底からのクォータニオン」

上記の質問と回答は、ベクトルに沿ってクォータニオンを整列させる(「ポインティング」)という問題に対処しますが、ツイスト(方向付け)は無視します。完全な正規直交基底には、方向、上向き、横向きが含まれます(そのうちの1つは冗長ですが、2つではありません)。元の質問は方向のみを考慮しています。

直交基底からのクォータニオンの1つの解決策は、3xベクトルを行列の列に配置し、行列をクォータニオンに変換することで見つけることができます。ただし、この方法では、クォータニオンに加えて追加のマトリックスストレージ(16xフロート)が必要であり、非常に低速です。

より良い解決策は、基底ベクトルa、b、cを書き出し、これらを行列から四元数への変換に接続することで見つかります。ここで、要素は明示的です。(このマトリックスは、列メジャーのOpenGL形式です)

m[0][0] = a.x, m[1][0] = a.y, m[2][0] = a.z
m[0][1] = b.x, m[1][1] = b.y, m[2][1] = b.z
m[0][2] = c.x, m[1][2] = c.z, m[2][2] = c.z

ここで、置換された正規直交ベクトルa、b、cを使用して、行列から四元数への関数を書き直します。結果は次の関数です。

// Quaternion from orthogonal basis
Quaternion& Quaternion::toBasis (Vector3DF a, Vector3DF b, Vector3DF c)
{
    float T = a.x + b.y + c.z;
    float s;
    if (T > 0) {
        float s = sqrt(T + 1) * 2.f;
        X = (b.z - c.y) / s;
        Y = (c.x - a.z) / s;
        Z = (a.y - b.x) / s;
        W = 0.25f * s;
    } else if ( a.x > b.y && a.x > c.z) {
        s = sqrt(1 + a.x - b.y - c.z) * 2;
        X = 0.25f * s;
        Y = (a.y + b.x) / s;
        Z = (c.x + a.z) / s;
        W = (b.z - c.y) / s;
    } else if (b.y > c.z) {
        s = sqrt(1 + b.y - a.x - c.z) * 2;
        X = (a.y + b.x) / s;
        Y = 0.25f * s;
        Z = (b.z + c.y) / s;
        W = (c.x - a.z) / s;
    } else {
        s = sqrt(1 + c.z - a.x - b.y) * 2;
        X = (c.x + a.z) / s;
        Y = (b.z + c.y) / s;
        Z = 0.25f * s;
        W = (a.y - b.x) / s;
    }
    normalize();
    return *this;
}

この関数は、行列を中間に格納することなく、正規直交基底ベクトルa、b、cから直接クォータニオン(X、Y、Z、W)を生成します。(上記の列メジャーのOpenGL形式の行列)。クォータニオンを正規化する必要がある場合があります。方向とアップベクトルがある場合、たとえばカメラの場合、次のように基底を作成できます:a = dir、b = up、c = cross(dir、up)

于 2021-10-31T08:24:53.723 に答える
-1

vecmathライブラリ(Java)を見てみます。それは長い間あり、私たちは私たちのコミュニティでそれを使用しています。これは4タプルに基づいており、変換の簡単な方法がなかったらがっかりします。

また、期待される結果の単体テストも作成します。正と負、左利きと右利き、およびmovinig/参照フレームを混乱させるのは非常に簡単です。単純なもの(xyzなど)から始めて、正しい答えがあることを確認します。

于 2009-10-25T08:41:02.830 に答える