11

そのため、現在、2 つの 3D ポイント A と B を取り、ポイント A がポイント B を「見る」ために必要な回転を表すクォータニオンを提供する関数を作成しようとしています (ポイント A のローカル Z 軸が通過するように)必要に応じてポイント B)。

私は最初にこの投稿を見つけました。その一番の答えは、良い出発点を提供してくれたようです。次のコードを実装しました。元の回答が示唆するように、デフォルトの (0, 0, -1) 方向を想定する代わりに、カメラの実際の方向を表す単位ベクトルを抽出しようとします。

void Camera::LookAt(sf::Vector3<float> Target)
{
    ///Derived from pseudocode found here:
    ///https://stackoverflow.com/questions/13014973/quaternion-rotate-to

    //Get the normalized vector from the camera position to Target
    sf::Vector3<float> VectorTo(Target.x - m_Position.x,
                                Target.y - m_Position.y,
                                Target.z - m_Position.z);
    //Get the length of VectorTo
    float VectorLength = sqrt(VectorTo.x*VectorTo.x +
                              VectorTo.y*VectorTo.y +
                              VectorTo.z*VectorTo.z);
    //Normalize VectorTo
    VectorTo.x /= VectorLength;
    VectorTo.y /= VectorLength;
    VectorTo.z /= VectorLength;

    //Straight-ahead vector
    sf::Vector3<float> LocalVector = m_Orientation.MultVect(sf::Vector3<float>(0, 0, -1));

    //Get the cross product as the axis of rotation
    sf::Vector3<float> Axis(VectorTo.y*LocalVector.z - VectorTo.z*LocalVector.y,
                            VectorTo.z*LocalVector.x - VectorTo.x*LocalVector.z,
                            VectorTo.x*LocalVector.y - VectorTo.y*LocalVector.x);

    //Get the dot product to find the angle
    float Angle = acos(VectorTo.x*LocalVector.x +
                       VectorTo.y*LocalVector.y +
                       VectorTo.z*LocalVector.z);

    //Determine whether or not the angle is positive
    //Get the cross product of the axis and the local vector
    sf::Vector3<float> ThirdVect(Axis.y*LocalVector.z - Axis.z*LocalVector.y,
                                 Axis.z*LocalVector.x - Axis.x*LocalVector.z,
                                 Axis.x*LocalVector.y - Axis.y*LocalVector.x);
    //If the dot product of that and the local vector is negative, so is the angle
    if (ThirdVect.x*VectorTo.x + ThirdVect.y*VectorTo.y + ThirdVect.z*VectorTo.z < 0)
    {
        Angle = -Angle;
    }

    //Finally, create a quaternion
    Quaternion AxisAngle;
    AxisAngle.FromAxisAngle(Angle, Axis.x, Axis.y, Axis.z);

    //And multiply it into the current orientation
    m_Orientation = AxisAngle * m_Orientation;
}

これはほとんど機能します。何が起こるかというと、カメラがターゲット ポイントに向かって半分の距離だけ回転しているように見えます。もう一度回転を試みると、残りの半分の回転が無限に実行されるため、「Look-At-Button」を押したままにすると、カメラの向きがターゲットを直接見る方向にどんどん近づいていきますが、常に回転が遅くなり、そこに到達することはありませ

gluLookAt() に頼りたくないことに注意してください。最終的には、カメラ以外のオブジェクトを互いに向けるためにこのコードが必要になるためです。私のオブジェクトは既に向きにクォータニオンを使用しています。たとえば、目の前を動き回る物体の位置を追跡する眼球や、ターゲットを探すために方向を更新する発射体を作成したい場合があります。

4

2 に答える 2

4

Normalize Axis vector before passing it to FromAxisAngle.

于 2013-01-15T14:17:19.943 に答える
1

なぜクォータニオンを使用しているのですか?この場合、物事をより複雑にし、より多くの計算を必要とするだけです。マトリックスを設定するには:-

calculate vector from observer to observed (which you're doing already)
normalise it (again, doing it already) = at
cross product this with the observer's up direction = right
normalise right
cross product at and right to get up

これで完了です。right、up、および at ベクトルは、行列の最初、2 番目、3 番目の行 (または、設定方法によっては列) です。最後の行/列はオブジェクトの位置です。

しかし、いくつかのフレームで既存のマトリックスをこの新しいマトリックスに変換したいようです。SLERP は行列と四元数に対してこれを行います (数学を調べると驚くことではありません)。変換では、初期マトリックスとターゲットマトリックスを保存し、それらの間の SLERP を保存し、フレームごとに量を SLERP に変更します (たとえば、0、0.25、0.5、0.75、1.0 - 非線形の進行が見栄えがよくなります)。

クォータニオンをマトリックスに変換してレンダリング パイプラインに渡すことを忘れないでください (シェーダーにクォータニオンをネイティブに処理する新しい機能がない限り)。したがって、クォータニオンの使用による効率は、変換プロセスも考慮する必要があります。

于 2013-01-15T14:12:39.780 に答える