クォータニオンベースのカメラを実装するにはどうすればよいですか?


14

更新ここでのエラーは非常に単純なものでした。ラジアンから度への変換を見逃しました。他の問題がある場合は、すべてを読む必要はありません。

私はこれについていくつかのチュートリアルを見て、四元数ベースのカメラを実装しようと思って理解したと思いました。問題は、約1分間回転させた後、正しく動作しないことです。10度戻ると-10度に戻ります。何が悪いのか分かりません。私はopenTKを使用していますが、すでにクォータニオンクラスがあります。私はopenglの初心者であり、楽しみのためだけにこれをやっており、四元数を本当に理解していないので、おそらくここで愚かなことをしているでしょう。ここにいくつかのコードがあります:(実際には、vboを​​ロードおよび描画するメソッドを除くほとんどすべてのコード(vbo-sを示すOpenTKサンプルから取得されます))

vboにキューブをロードし、カメラのクォータニオンを初期化します

protected override void OnLoad(EventArgs e) {
    base.OnLoad(e);

    cameraPos = new Vector3(0, 0, 7);
    cameraRot = Quaternion.FromAxisAngle(new Vector3(0,0,-1), 0);

    GL.ClearColor(System.Drawing.Color.MidnightBlue);
    GL.Enable(EnableCap.DepthTest);

    vbo = LoadVBO(CubeVertices, CubeElements);
}

ここに透視投影をロードします。これは、最初とウィンドウのサイズを変更するたびにロードされます。

protected override void OnResize(EventArgs e) {
    base.OnResize(e);

    GL.Viewport(0, 0, Width, Height);

    float aspect_ratio = Width / (float)Height;

    Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64);
    GL.MatrixMode(MatrixMode.Projection);
    GL.LoadMatrix(ref perpective);
}

ここで、最後の回転値を取得し、最後の回転のみを表す新しいクォータニオンを作成し、カメラクォータニオンと乗算します。この後、これを軸角度に変換して、openglが使用できるようにします。(これは、いくつかのオンラインクォータニオンチュートリアルから理解した方法です)

protected override void OnRenderFrame(FrameEventArgs e) {
    base.OnRenderFrame(e);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    double speed = 1;
    double rx = 0, ry = 0;

    if (Keyboard[Key.A]) {
        ry = -speed * e.Time;
    }

    if (Keyboard[Key.D]) {
        ry = +speed * e.Time;
    }

    if (Keyboard[Key.W]) {
        rx = +speed * e.Time;
    }

    if (Keyboard[Key.S]) {
        rx = -speed * e.Time;
    }

    Quaternion tmpQuat = Quaternion.FromAxisAngle(new Vector3(0,1,0), (float)ry);
    cameraRot = tmpQuat * cameraRot;
    cameraRot.Normalize();

    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadIdentity();

    Vector3 axis;
    float angle;

    cameraRot.ToAxisAngle(out axis, out angle);
    //////////////////////////////////////////////////////////////////////
    // THIS IS WHAT I DID WRONG: I NEED TO CONVERT FROM RADIANS TO DEGREES
    //////////////////////////////////////////////////////////////////////
    //BEFORE
    //GL.Rotate(angle, axis);
    //AFTER
    GL.Rotate(angle * (float)180.0/(float)Math.PI, axis);
    GL.Translate(-cameraPos);

    Draw(vbo);
    SwapBuffers();
}

よく説明する2つの画像を次に示します。しばらくすると、これから回転します。

この

これに飛び込む

ここに画像の説明を入力してください

どんな助けも大歓迎です。

Update1:ファイルに書き込むストリームライターにこれらを追加します:

    sw.WriteLine("camerarot: X:{0} Y:{1} Z:{2} W:{3} L:{4}", cameraRot.X, cameraRot.Y, cameraRot.Z, cameraRot.W, cameraRot.Length);
    sw.WriteLine("ry: {0}", ry);

ログはhttp://www.pasteall.org/26133/textから入手できます。770行目では、camerarot.Yが符号を変更すると、キューブが右から左にジャンプします。これが正常かどうかはわかりません。

アップデート2は、 ここでは完全なプロジェクトです。


2
私は問題を理解していません。レンダリングに使用しているクォータニオンを印刷してみましたか?
ニコルボーラス

1
同意して、rx、ry、およびQuaternionの値をデバッグします。
減速

プロジェクト全体をRapidShareにアップロードしてみませんか?簡単になります。
ボボボボ

OK家に帰ったらアップロードします。
ギョーゾクドール

回答:


9

ここで私の仮定を検証するために必要なコードを示していませんが、問題は実際にこの行であることをほぼ保証できます。

cameraRot.ToAxisAngle(out axis, out angle);

ラジアンで表された角度値を返しますが、

GL.Rotate(angle, axis);

度で角度を提供したい。

これを修正するには、次のようにGL.Rotate()に渡すときに角度値を変換する必要があります。

GL.Rotate(angle * 180.0/3.141593, axis);

はい、それは問題でした。:) どうもありがとう。openglは度を期待することを知っていたので、ToAxisAngleは度を返すと仮定しました。私はopentkコードを見たところ、ラジアンです。ところで、最後に完全なソースコードを提供しました。
ギョーゾクドール

@NickCaplingerは、C#にはMath.Pi利用可能な定数があることを正しく指摘しています。これは、最終計算で使用したリテラル3.141593値よりも優先して使用する必要があります。
トレバーパウエル

1

しないでください。他のシーンオブジェクトのように操作できるカメラを使用する方が作業が少ないように思えるかもしれませんが、長期的には、位置、視線方向、アップベクトルを定義できるカメラを使用する方が適切です。特にモーションモデルのプログラミングを開始するとき、クォータニオンを使用するのは本当に苦痛です。


1
同意した。私は自分のアプリケーションをデザインする「発音が難しいならもっと良いに違いない」という方法も好きではありません=)
パトリックヒューズ

四元数は発音しにくいですか?
notlesh

1
ちょっとしたユーモアが大いに役立つ= D推論によると、質問はクォータニオンカメラが必要な理由がわからない人から来ていることを意味します。上記の壊れたコードでラジアンや度のパラメーターを適切に処理するようなものが適切に処理されない場合、それは確かに取り組む対象ではありません。
パトリックヒューズ

3
この質問はカメラに関するものではありません。ゲームコードで回転を表現する方法と、それらのゲーム表現をOpenGLで使用できる形式に変換する方法についてです。これは完全に正当な質問であり、OPのドメインエクスペリエンスの欠如をあざけることは、決して役立つとは思いません。OPがバカな間違いをしたわけではありません。角度を表現するときに度数を使用するというOpenGLの主張は実に奇妙です。 OpenGLを使用して初めて誰もがこの間違いを犯します。それで、あなたの高い馬、人々を降ろしてください。もう。
トレバーパウエル

クォータニオンベースのカメラがどのように機能するかを理解したかっただけで、他に何もすることがなかった日にこのプロジェクトを作成しました。これには本当の計画はありません。
ギョーゾクドール

0

OpenTK内部についてはあまり知りません。私の経験では、すべてがe ^ 2-e ^ 3エラーに影響するため、必要な精度(マシン)を維持するquatを適切に実装した数学ライブラリは見ませんでした。したがって、表示される効果:精度(およびイプシロン値)は約10 ^ -5であり、ゼロに近い「ジャンプ」します。これは私の推測です:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.