Come posso implementare una fotocamera basata su quaternione?


14

AGGIORNAMENTO L'errore qui è stato piuttosto semplice. Ho perso una conversione da radiante a gradi. Non c'è bisogno di leggere tutto se hai qualche altro problema.

Ho guardato diversi tutorial su questo e quando pensavo di aver capito ho cercato di implementare una fotocamera a quaternione. Il problema è che non funziona correttamente, dopo aver ruotato per ca. 10 gradi torna a -10 gradi. Non ho idea di cosa non vada. Sto usando openTK e ha già una classe quaternion. Sono un novellino di Opengl, lo sto facendo solo per divertimento e non capisco davvero i quaternioni, quindi probabilmente sto facendo qualcosa di stupido qui. Ecco un po 'di codice: (In realtà quasi tutto il codice tranne i metodi che caricano e disegnano un vbo (è preso da un campione OpenTK che dimostra vbo-s))

Carico un cubo in un vbo e inizializzo il quaternione per la videocamera

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

Carico qui una proiezione prospettica. Questo viene caricato all'inizio e ogni volta che ridimensiono la finestra.

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

Qui ottengo l'ultimo valore di rotazione e creo un nuovo quaternione che rappresenta solo l'ultima rotazione e lo moltiplico con il quaternione della fotocamera. Dopo questo, lo trasformo in angolo dell'asse in modo che Opengl possa usarlo. (È così che l'ho capito da diversi tutorial quaternion online)

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

Qui ci sono 2 immagini per spiegare meglio: io giro un po 'e da questo:

Questo

salta in questo

inserisci qui la descrizione dell'immagine

Qualsiasi aiuto è apprezzato.

Update1 : aggiungo questi a uno streamwriter che scrive in un file:

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

Il registro è disponibile qui: http://www.pasteall.org/26133/text . Alla linea 770 il cubo salta da destra a sinistra, quando camerarot.Y cambia segno. Non so se sia normale.

Update2 Ecco il progetto completo.


2
Non capisco il problema. Hai provato a stampare i quaternioni con cui stai utilizzando il rendering?
Nicol Bolas,

1
Concordato, esegui il debug dei valori rx, ry e Quaternion.
deceleratedcaviar

Perché non carichi l'intero progetto da qualche parte su rapidshare? Sarebbe più facile
Bobobobo,

OK lo caricherò quando torno a casa.
Gyozo Kudor,

Risposte:


9

Anche se non hai mostrato il codice necessario per verificare il mio presupposto qui, posso quasi garantire che il tuo problema sia effettivamente che questa riga:

cameraRot.ToAxisAngle(out axis, out angle);

sta restituendo un valore angolare espresso in radianti , mentre

GL.Rotate(angle, axis);

vuole che l' angolo sia fornito in gradi .

Per risolverlo, devi convertire il valore dell'angolo quando lo passi a GL.Rotate (), in questo modo:

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

Sì, quello era il problema. :) Molte grazie. Sapevo che Opengl si aspettava gradi, supponevo che ToAxisAngle restituisse gradi. Ho appena guardato il codice opentk ed è radianti. A proposito, ho fornito il codice sorgente completo alla fine.
Gyozo Kudor,

@NickCaplinger sottolinea correttamente che in C # esiste una Math.Picostante disponibile, che dovrebbe essere utilizzata in preferenza al valore letterale 3.141593 che ho usato in quel calcolo finale.
Trevor Powell,

1

Non farlo. Può sembrare che sarebbe meno faticoso avere una videocamera che può essere manipolata come altri oggetti di scena, ma a lungo andare è meglio avere una videocamera in cui è possibile definire una posizione, la direzione dell'occhio e il vettore. Soprattutto quando inizi a programmare i modelli di movimento, è davvero difficile lavorare con i quaternioni.


1
Concordato. Non sono un fan del metodo "se è difficile pronunciarlo deve essere migliore" anche per progettare le mie applicazioni =)
Patrick Hughes,

Quaternione è difficile da pronunciare?
notlesh,

1
Un po 'di umorismo fa molta strada = D Per deduzione insinuo che la domanda viene da qualcuno che non ha idea del PERCHÉ vuole una camera da quaternione, solo che è una parola d'ordine ordinata e OMG lo voglio così tremendamente ora! Non è certamente un argomento da affrontare quando qualcosa come gestire correttamente i radianti e i parametri di grado nel codice rotto sopra non viene trattato correttamente.
Patrick Hughes,

3
Questa domanda non riguarda davvero le telecamere; si tratta di come rappresentare le rotazioni nel codice di gioco e come convertire quelle rappresentazioni di gioco in una forma tale che OpenGL possa usarle. È una domanda perfettamente legittima e non credo che deridere la mancanza di esperienza nel dominio del PO sia utile in alcun modo. Non è che l'OP abbia fatto uno stupido errore; L'insistenza di OpenGL sull'uso dei gradi nell'espressione degli angoli è decisamente bizzarra. Tutti fanno questo errore per la prima volta usando OpenGL. Quindi scendi dai tuoi cavalli alti, gente. Accidenti.
Trevor Powell,

Volevo solo capire come funziona una fotocamera a quaternione e ho realizzato questo progetto in un giorno in cui non avevo nient'altro da fare. Non ho piani reali con questo.
Gyozo Kudor,

0

Non so molto sugli interni di OpenTK. Nella mia esperienza non ho visto la libreria matematica con la corretta implementazione di quat che mantiene la precisione necessaria (macchina), perché tutti influiscono sugli errori e ^ 2-e ^ 3. Quindi l'effetto che vedi: la precisione (e il valore epsilon) è di circa 10 ^ -5, e "salta" vicino allo zero. Questa è la mia ipotesi :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.