Wie implementiere ich eine quaternionsbasierte Kamera?

14

UPDATE Der Fehler hier war ziemlich einfach. Ich habe eine Umrechnung von Bogenmaß in Grad verpasst. Sie müssen das Ganze nicht lesen, wenn Sie ein anderes Problem haben.

Ich habe mir mehrere Tutorials dazu angesehen und als ich dachte, ich verstehe, habe ich versucht, eine quaternionsbasierte Kamera zu implementieren. Das Problem ist, dass es nach ca. 10 Grad springt es auf -10 Grad zurück. Ich habe keine Ahnung, was los ist. Ich benutze openTK und es hat bereits eine Quaternion-Klasse. Ich bin ein Noob bei opengl, ich mache das nur zum Spaß und verstehe Quaternionen nicht wirklich, also mache ich hier wahrscheinlich etwas Dummes. Hier ist ein bisschen Code: (Eigentlich fast der gesamte Code außer den Methoden, die ein vbo laden und zeichnen (er stammt aus einem OpenTK-Beispiel, das vbo-s demonstriert).

Ich lade einen Würfel in ein VBO und initialisiere die Quaternion für die Kamera

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);
}

Ich lade hier eine perspektivische Projektion. Dies wird zu Beginn geladen und jedes Mal, wenn ich die Fenstergröße verändere.

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);
}

Hier erhalte ich den letzten Rotationswert und erstelle ein neues Quaternion, das nur die letzte Rotation darstellt, und multipliziere es mit dem Kameraquaternion. Danach wandle ich dies in Achsenwinkel um, damit opengl es benutzen kann. (So ​​habe ich es aus mehreren Online-Quaternion-Tutorials verstanden.)

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();
}

Hier sind 2 Bilder zur besseren Erklärung: Ich drehe eine Weile und daraus:

Dies

es springt hinein

Bildbeschreibung hier eingeben

Jede Hilfe wird geschätzt.

Update1 : Ich füge diese einem Streamwriter hinzu, der in eine Datei schreibt:

    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);

Das Protokoll ist hier verfügbar: http://www.pasteall.org/26133/text . In Zeile 770 springt der Würfel von rechts nach links, wenn camerarot.Y die Vorzeichen wechselt. Ich weiß nicht, ob das normal ist.

Update2 Hier ist das komplette Projekt.

Gyozo Kudor
quelle
2
Ich verstehe das Problem nicht. Haben Sie versucht, die Quaternionen auszudrucken, mit denen Sie rendern?
Nicol Bolas
1
Stimmen Sie zu, debuggen Sie Ihre Werte für rx, ry und Quaternion.
verzögerte
Warum lädst du dein gesamtes Projekt nicht irgendwo auf rapidshare hoch? Wäre einfacher.
Bobobobo
OK, ich werde es hochladen, wenn ich nach Hause komme.
Gyozo Kudor

Antworten:

9

Obwohl Sie hier nicht den erforderlichen Code angegeben haben, um meine Vermutung zu überprüfen, kann ich fast garantieren, dass Ihr Problem tatsächlich in der folgenden Zeile besteht:

cameraRot.ToAxisAngle(out axis, out angle);

gibt einen Winkelwert im Bogenmaß zurück , während

GL.Rotate(angle, axis);

möchte, dass der Winkel in Grad angegeben wird .

Um dies zu beheben, müssen Sie den Winkelwert konvertieren , wenn Sie ihn an GL.Rotate () übergeben:

GL.Rotate(angle * 180.0/3.141593, axis);
Trevor Powell
quelle
Ja, das war das Problem. :) Vielen Dank. Ich wusste, dass opengl Grad erwartet, ich ging davon aus, dass ToAxisAngle Grad zurückgibt. Ich habe mir gerade den Opentk-Code angesehen und er ist Radianten. Übrigens habe ich am Ende den vollständigen Quellcode bereitgestellt.
Gyozo Kudor
@ NickCaplinger weist zu Recht darauf hin, dass in C # eine Math.PiKonstante verfügbar ist, die dem Literalwert 3.141593 vorgezogen werden sollte, den ich in dieser endgültigen Berechnung verwendet habe.
Trevor Powell
1

Nicht. Es mag den Anschein haben, als wäre es weniger arbeitsaufwendig, eine Kamera zu haben, die wie andere Szenenobjekte manipuliert werden kann. Auf lange Sicht ist es jedoch besser, eine Kamera zu haben, in der Sie Position, Blickrichtung und Aufwärtsvektor definieren können. Besonders wenn Sie anfangen, Bewegungsmodelle zu programmieren, ist es wirklich mühsam, mit Quaternionen zu arbeiten.

wooyay
quelle
1
Einverstanden. Ich bin kein Fan der Methode "Wenn es schwer auszusprechen ist, muss es besser sein", auch meine Anwendungen zu entwerfen =)
Patrick Hughes
Quaternion ist schwer auszusprechen?
notlesh
1
Ein bisschen Humor ist ein langer Weg = D Ich gehe davon aus, dass die Frage von jemandem kommt, der keine Ahnung hat, WARUM er eine Quaternion-Kamera haben will, nur, dass es ein ordentliches Schlagwort ist und OMG, ich will es jetzt sooo schlecht! Es ist sicherlich kein Thema, das angegangen werden muss, wenn etwas wie der ordnungsgemäße Umgang mit Bogenmaß und Gradparametern im oben abgebrochenen Code nicht ordnungsgemäß behandelt wird.
Patrick Hughes
3
Bei dieser Frage geht es nicht wirklich um Kameras. Es geht darum, wie Rotationen im Spielcode dargestellt werden und wie diese Spielrepräsentationen in eine Form umgewandelt werden, die OpenGL verwenden kann. Es ist eine absolut legitime Frage, und ich denke nicht, dass es in irgendeiner Weise hilfreich ist, sich über die mangelnde Domain-Erfahrung des OP lustig zu machen. Es ist nicht so, als ob die OP einen dummen Fehler gemacht hätte. OpenGLs Beharren auf der Verwendung von Grad beim Ausdrücken von Winkeln ist ausgesprochen bizarr. Jeder macht diesen Fehler zum ersten Mal mit OpenGL. Also steig von deinen hohen Pferden, Leute. Meine Güte.
Trevor Powell
Ich wollte nur verstehen, wie eine quaternionsbasierte Kamera funktioniert, und ich habe dieses Projekt an einem Tag gemacht, an dem ich nichts anderes zu tun hatte. Ich habe damit keine wirklichen Pläne.
Gyozo Kudor
0

Ich weiß nicht viel über OpenTK-Interna. Nach meiner Erfahrung habe ich keine Mathematikbibliothek mit ordnungsgemäßer Implementierung von quat gesehen, die die erforderliche Präzision (Maschine) beibehält, da alle von ihnen e ^ 2-e ^ 3-Fehler betreffen. Der Effekt, den Sie sehen, ist also: Die Genauigkeit (und der Epsilon-Wert) liegen bei etwa 10 ^ -5, und sie springt in die Nähe von Null. Das ist meine Vermutung :)

infra
quelle