Comment mettre en œuvre une caméra basée sur quaternion?

14

MISE À JOUR L'erreur ici était assez simple. J'ai raté une conversion de radian en degrés. Pas besoin de lire le tout si vous avez un autre problème.

J'ai regardé plusieurs tutoriels à ce sujet et quand j'ai cru comprendre, j'ai essayé d'implémenter une caméra basée sur quaternion. Le problème est qu'il ne fonctionne pas correctement, après avoir tourné pendant env. 10 degrés, il revient à -10 degrés. Je n'ai aucune idée de ce qui ne va pas. J'utilise openTK et il a déjà une classe quaternion. Je suis un noob chez opengl, je fais ça juste pour le plaisir, et je ne comprends pas vraiment les quaternions, donc je fais probablement quelque chose de stupide ici. Voici du code: (En fait, presque tout le code, sauf les méthodes qui chargent et dessinent un vbo (il est tiré d'un exemple OpenTK qui illustre les vbo-s))

Je charge un cube dans un vbo et initialise le quaternion pour la caméra

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

Je charge ici une projection en perspective. Ceci est chargé au début et chaque fois que je redimensionne la fenêtre.

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

Ici, j'obtiens la dernière valeur de rotation et crée un nouveau quaternion qui ne représente que la dernière rotation et le multiplie avec le quaternion de la caméra. Après cela, je le transforme en axe-angle afin que opengl puisse l'utiliser. (Voici comment je l'ai compris à partir de plusieurs tutoriels quaternion en ligne)

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

Voici 2 images pour mieux expliquer: je tourne un moment et à partir de là:

cette

ça saute dedans

entrez la description de l'image ici

Toute aide est appréciée.

Update1 : je les ajoute à un streamwriter qui écrit dans un fichier:

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

Le journal est disponible ici: http://www.pasteall.org/26133/text . À la ligne 770, le cube saute de droite à gauche lorsque camerarot.Y change de signe. Je ne sais pas si c'est normal.

Update2 Voici le projet complet.

gyozo kudor
la source
2
Je ne comprends pas le problème. Avez-vous essayé d'imprimer les quaternions avec lesquels vous utilisez le rendu?
Nicol Bolas
1
D'accord, déboguez vos valeurs rx, ry et Quaternion.
deceleratedcaviar
Pourquoi ne téléchargez-vous pas l'intégralité de votre projet quelque part sur rapidshare? Ce serait plus facile.
bobobobo
OK, je le téléchargerai quand je rentrerai.
gyozo kudor

Réponses:

9

Bien que vous n'ayez pas montré le code nécessaire pour vérifier mon hypothèse ici, je peux presque garantir que votre problème est en fait que cette ligne:

cameraRot.ToAxisAngle(out axis, out angle);

renvoie une valeur d' angle exprimée en radians , tandis que

GL.Rotate(angle, axis);

veut que l' angle soit fourni en degrés .

Pour le corriger, vous devez convertir la valeur d' angle lors du passage à GL.Rotate (), comme ceci:

GL.Rotate(angle * 180.0/3.141593, axis);
Trevor Powell
la source
Oui, c'était le problème. :) Merci beaucoup. Je savais que opengl attend des degrés, j'ai supposé que ToAxisAngle renvoie des degrés. Je viens de regarder le code opentk et ce sont les radians. BTW J'ai fourni le code source complet à la fin.
gyozo kudor
@NickCaplinger souligne correctement qu'en C #, il existe une Math.Piconstante disponible, qui doit être utilisée de préférence à la valeur littérale de 3,141593 que j'ai utilisée dans ce calcul final.
Trevor Powell
1

Non. Il peut sembler que ce serait moins de travail d'avoir une caméra qui peut être manipulée comme d'autres objets de scène, mais à long terme, il est préférable d'avoir une caméra où vous pouvez définir une position, une direction des yeux et un vecteur vers le haut. Surtout lorsque vous commencez à programmer des modèles de mouvement, c'est vraiment pénible de travailler avec des quaternions.

wooyay
la source
1
D'accord. Je ne suis pas non plus fan de la méthode "si c'est difficile à prononcer, ça doit être mieux" pour concevoir mes applications =)
Patrick Hughes
Le quaternion est difficile à prononcer?
2011
1
Un peu d'humour va très loin = D Par déduction, j'implique que la question vient de quelqu'un qui n'a aucune idée POURQUOI il veut un appareil photo quaternion, juste que c'est un mot à la mode soigné et OMG je le veux tellement mauvais maintenant! Ce n'est certainement pas un sujet à aborder lorsque quelque chose comme la gestion correcte des radians et des paramètres de degré dans le code cassé ci-dessus n'est pas traité correctement.
Patrick Hughes
3
Cette question ne concerne pas vraiment les caméras; il s'agit de savoir comment représenter les rotations dans le code du jeu et comment convertir ces représentations de jeu sous une forme telle qu'OpenGL puisse les utiliser. C'est une question parfaitement légitime, et je ne pense pas que se moquer du manque d'expérience du domaine du PO ne soit d'aucune utilité. Ce n'est pas comme si l'OP avait fait une stupide erreur; L'insistance d'OpenGL sur l'utilisation des degrés lors de l'expression des angles est carrément bizarre. Tout le monde fait cette erreur la première fois qu'il utilise OpenGL. Alors descendez de vos grands chevaux, les gens. Décidément.
Trevor Powell,
Je voulais juste comprendre comment fonctionne une caméra à base de quaternion et j'ai réalisé ce projet à une époque où je n'avais rien d'autre à faire. Je n'ai pas vraiment de plans avec ça.
gyozo kudor
0

Je ne sais pas grand chose sur les internes d'OpenTK. D'après mon expérience, je n'ai pas vu de bibliothèque mathématique avec une implémentation correcte de quat qui conserve la précision nécessaire (machine), car toutes affectent les erreurs e ^ 2-e ^ 3. Donc l'effet que vous voyez: la précision (et la valeur epsilon) est d'environ 10 ^ -5, et elle "saute" près de zéro. C'est ma conjecture :)

infra
la source