Partage
  • Partager sur Facebook
  • Partager sur Twitter

[OpenGL]classe camera: mouvement(srtout la rotation) bizarre

    30 mai 2008 à 0:34:22

    Salut,
    j'ai implementé ma propore classe camera utilisant opengl, mais je costate que le mouvement est un peu ... bizarre o_O .
    je sens que je ne suis pas tout a fait à l'aise quand je me deplace dans la scene, mais je ne sais pas pourquoi.
    Voici camera.h:
    #ifndef CAMERA_H_INCLUDED
    #define CAMERA_H_INCLUDED
    
    #include "Vector3D.h"
    #include <math.h>
    #include <SFML/Window.hpp>
    #include <GL/gl.h>
    #include <GL/glu.h>
    
    
    class Camera {
    public:
        Camera(const Vector3D& = Vector3D(0, 0, -100));
        void Translate(const double, const double);
    
        void OnEvent(const sf::Input& , const double dt);
        void Look();
    
    protected:
        void VectorFromAngles();
    
        Vector3D m_position;//position in the world
        Vector3D m_target;
        //directions
        Vector3D m_forward;
        Vector3D m_left;
        Vector3D m_up;
    
        //the traget of the camera
        Vector3D m_traget;
    
        //rotation
        double m_theta;
        double m_phi;
        double m_speed;
    
        double m_pi;
    
        double m_oldX;
        double m_oldY;
    };
    
    
    #endif // CAMERA_H_INCLUDED
    


    et le .cpp
    #include "Camera.h"
    
    Camera::Camera(const Vector3D& position): m_position(position), m_up(0, 1, 0), m_forward(0, 0, 1), m_left(1, 0, 0) {
        m_speed = .1;
        m_oldX = -1;
        m_oldY = -1;
    
        m_pi = 3.14;
    
        m_theta = 0;
        m_phi = 0;
    
    }
    
    
    void Camera::Translate(const double x, const double z) {
        m_position += m_left * x;
        m_position += m_forward * z;
    }
    
    
    
    void Camera::VectorFromAngles() {
        double xTemp = cos(m_theta * M_PI / 180);
    
        m_forward.Y = sin(m_theta * M_PI / 180);
        m_forward.X = cos(m_phi * M_PI / 180) * xTemp;
        m_forward.Z = sin(m_phi * M_PI / 180) * xTemp;
    
    
        m_left = m_up.crossProduct(m_forward).normalize();
    
        m_target = m_position + m_forward;
    }
    
    
    void Camera::Look() {
        gluLookAt(
            m_position.X, m_position.Y, m_position.Z,
            m_target.X, m_target.Y, m_target.Z,
            m_up.X, m_up.Y, m_up.Z
        );
    
    }
    
    void Camera::OnEvent(const sf::Input& input, const double dt) {
        double z = 0, x = 0, y = 0;
        if ( input.IsKeyDown(sf::Key::Z) )
            z += m_speed * dt;
        if ( input.IsKeyDown(sf::Key::S) )
            z -= m_speed * dt;
        if ( input.IsKeyDown(sf::Key::Q) )
            x += m_speed * dt;
        if ( input.IsKeyDown(sf::Key::D) )
            x -= m_speed * dt;
    
        Translate(x, z);
    
    
        x = input.GetMouseX();
        y = input.GetMouseY();
        if (m_oldX < 0) m_oldX = x;
        if (m_oldY < 0) m_oldY = y;
    
        m_phi += (x - m_oldX) * dt * m_speed * 0.1;
        m_theta -= (y - m_oldY) * dt * m_speed *  0.1;
        VectorFromAngles();
        m_oldX = x;
        m_oldY = y;
    
    
    
    }
    
    PS: j'utilise la SFML pour le fenetrage!
    • Partager sur Facebook
    • Partager sur Twitter
      30 mai 2008 à 1:26:41

      Tu peux préciser un peu ce que tu appelles bizarre?

      La seule chose d'incorrect que je vois, c'est que tu multiplies le déplacement de la souris par dt * m_speed:
      • La vitesse de rotation est indépendante de la vitesse de déplacement. Je présume que tu t'en es rendu compte et c'est pour cela que tu as ajouté cette constante 0.1. Les deux vitesses sont suffisamment indépendante pour justifier deux variables (même les unités sont totalement différentes, la première est en degré/pixel et la seconde en unité/seconde).
      • Il n'y a pas besoin de multiplier par dt, le nombre de pixels dont s'est déplacée la souris depuis la dernière frame suffit à rendre la rotation indépendante du framerate. En effet, plus tu auras de frames par seconde et moins la souris aura le temps de se déplacer entre chaque frame, au final ça s'équilibrera. En multipliant par dt, tu prends en compte deux fois le framerate et du coup, tu dois sans doute avoir des variations de vitesses de rotation quand celui ci varie.


      Et par logique, j'aurais plutôt calculer les rotations avant les déplacements, le second dépendant du premier mais pas l'inverse, mais je ne pense pas que la différence soit perceptible.
      • Partager sur Facebook
      • Partager sur Twitter
        30 mai 2008 à 10:27:37

        Erreur classique : tu négliges le vecteur up. Tu le mets a 0,0,1 et tu ne le bouges jamais.

        Donc si tu "leves le nez", tu es mort : tu dénormalises le systeme.
        • Partager sur Facebook
        • Partager sur Twitter

        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

          30 mai 2008 à 12:40:02

          Citation : Fvirtman

          Erreur classique : tu négliges le vecteur up. Tu le mets a 0,0,1 et tu ne le bouges jamais.

          Donc si tu "leves le nez", tu es mort : tu dénormalises le systeme.

          mais pourquoi dois_je le calculer? kayl ne le recalcule pas parcequ'il est seulement utile pour avoir le vecteur left ;)
          • Partager sur Facebook
          • Partager sur Twitter
            30 mai 2008 à 14:20:12

            Non, ça ne va pas. Tu n'as pas compris a quoi sert le vecteur UP.
            Imagine que tu es la caméra.
            Le vecteur UP part du haut de ta tete, et va vers le ciel.

            Si tu décides de lever le nez, le vecteur UP part en arriere.
            Si tu hoches la tete, le vecteur s'incline a gauche ou a droite.

            Le vecteur up doit toujours etre orthogonal au vecteur de vue.
            • Partager sur Facebook
            • Partager sur Twitter

            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

              30 mai 2008 à 14:36:35

              et on le calcule comment?sinon je crois que c'est toi qui n'a pas compris, moi j'utilise le veteur up SEULEMENT pour calculer le vecteur left, et pas pour autre chose, donc qu'il soit perpendicualire a forward ou au monde entier, ça ne change rien au final!
              • Partager sur Facebook
              • Partager sur Twitter
                30 mai 2008 à 15:06:18

                faux, ton vecteur up ne sert pas que pour left : parce que tu passes ton vecteur up non touché a gluLookAt...
                Et c'est ça qui te fait foirer :)
                • Partager sur Facebook
                • Partager sur Twitter

                Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                  30 mai 2008 à 15:11:33

                  eh bien, faut passer le up global a lookAt, non?
                  • Partager sur Facebook
                  • Partager sur Twitter
                    30 mai 2008 à 15:12:41

                    pour savoir si ton up est valide, fait un produit scalaire entre lui et le vecteur de vue (at-origin)
                    si ça ne vaut pas 0, c'est que ce n'est pas bon.
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                      30 mai 2008 à 15:16:52

                      oui biensur, mais je crois qu'il faut passer le up global a gluLookAtn non?

                      Citation : Fvirtman

                      faux, ton vecteur up ne sert pas que pour left : parce que tu passes ton vecteur up non touché a gluLookAt...
                      Et c'est ça qui te fait foirer :)


                      Citation : kayl

                      gluLookAt(_position.X,_position.Y,_position.Z,
                      _target.X,_target.Y,_target.Z,
                      0,0,1);

                      un peu contradictoire, vous trouvez pas?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        30 mai 2008 à 15:27:51

                        Parce que Kyle fait varier le point position et le point target sur le meme plan Z. Dans ce cas particulier la, up n'a pas besoin de bouger (c'est comme si tu te déplaçais dans un monde sans jamais lever la tete).
                        Toi, ce n'est pas le cas (puisque tu as un angle Psi) donc il faut que tu modifies le vecteur up.

                        Je te laisse voir mon petit programme "Klostro Laby" (cf ma signature), qui te propose 6 degrés de liberté, pour voir que je ne te dis pas de conneries.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                          30 mai 2008 à 15:31:25

                          eh ben non, j'ai les meme angles que kayl(alpha et phi)!
                          • Partager sur Facebook
                          • Partager sur Twitter
                            30 mai 2008 à 15:35:54

                            peut etre que kayl les leve moins (et l'erreur ne se voit pas :) )

                            Une façon de vérifier dans ton cas : _position.z et _target.z : s'ils ne sont pas égaux, c'est que ton up (0,0,1) n'est pas bon.
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                              30 mai 2008 à 15:36:57

                              et comment je dois calculer le up?
                              • Partager sur Facebook
                              • Partager sur Twitter
                                30 mai 2008 à 15:38:36

                                ça dépend de comment tu veux incliner la caméra.
                                C'est un probleme de trigo.
                                • Partager sur Facebook
                                • Partager sur Twitter

                                Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                  30 mai 2008 à 15:39:43

                                  ok, merci pour toutes tes reponses Fvirtman!
                                  MAIS CE QUE JE NE COMPREND PAS? C4EST QUE COMMENT KAYL POUVAIT IL S4EN SORTIR SANS CALUCULER LE UP? ALORS QUE SA DEMO MARCHE NICKEL!
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    30 mai 2008 à 19:25:10

                                    http://opengl.org/sdk/docs/man/xhtml/gluLookAt.xml

                                    gluLookAt projette le vecteur up sur le plan de la caméra, il n'y a donc pas besoin de le faire soi même. La seule chose à s'assurer, c'est que ton vecteur direction ne soit pas colinéaire à ton vecteur up, ce qui arrive quand theta vaut 90° ou -90° modulo 360.
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      30 mai 2008 à 19:27:50

                                      Y'a pas nécessairement besoin que le vecteur UP soit orthogonal au vecteur de direction (EyeX-CenterX): gluLookAt le fait lui-même (http://www.opengl.org/documentation/sp [...] u/lookat.html). Ce qui est absolument nécessaire, c'est que le vecteur UP et le vecteur de direction soient linéairement indépendant, pour qu'il ne reste qu'un seul vecteur à trouver pour établir une base de l'espace a trois dimension dans lequel on travail. (En fait c'est un espace a 4 dimension, mais dans ce cas particulier, on travail sur un sous-espace, et glulookat complète la base par un quatrième vecteur: (0,0,0,1)... Avis aux amateurs d'algèbre linéaire!)
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        30 mai 2008 à 19:31:26

                                        voila, c'est ce que je voulais entendre et ce que je voulais daire comprendre a fivrtman.
                                        mais maintenant, qu'est ce qui cloche avec mo programme?
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          30 mai 2008 à 19:44:36

                                          Repense un peu toutes les étapes de ton calcul. Tu as visiblement voulu découpé le problème em plusieurs parties, mais peut-etre un peu trop, ou pas de la bonne manière.

                                          Prend un crayon, du papier, dessine un système d'axes, les vecteur qui decrivent ta camera, les angles, etc.
                                          Ensuite reflechi à ce qui doit etre temporaire, et a ce qui ne doit pas l'etre.

                                          L'etat de ta caméra est décrit par trois choses: une position <math>\(\vec P\)</math> et 2 angles (<math>\(\theta, \phi\)</math>). La souris modifie la valeur des deux angles. Le clavier modifie la position, mais c'est un peu plus compliqué:
                                          si <math>\(\vec P(t_{0}) = \vec P_{0}\)</math>, on a: <math>\(\vec P(t_{0} + dt) = \vec P_0 + dt\cdot \vec d\cdot v\)</math>, ou <math>\(\vec d\)</math> est le vecteur unitaire qui pointe vers l'avant, et <math>\(v\)</math> la vitesse de deplacement. <math>\(\vec d\)</math> doit etre calculé en fonction de tes 2 angles <math>\(\theta \text{ et } \phi\)</math>. Formellement, il s'agit de passer d'un système de coordonnées sphérique en coordonnées cartésiennes. (cf wikipedia, pour de plus amples info)
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            30 mai 2008 à 19:47:18

                                            je crois que c'est ce que j'ai fait dans la fonction VectorFromAngles(), non? je passe des angles alpha et phi au vecteur forward(vers l'avant) et puis au vecteur left!
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              30 mai 2008 à 19:56:49

                                              Oui, peut-etre. Mais c'est pas une bonne idée d'un point de vue conceptuelle de faire une fonction qui "modifie juste" un attribut, pour l'utiliser ensuite. Pense plutot a une fonction qui retourne un "Vecteur3D"..

                                              C'est la même chose pour le vecteur left.

                                              A prioris, ces vecteur sont des objets "temporaire" du calcul de la position, donc c'est pas très malin de les mettre en attributs. Sauf si tu penses avoir a les réutiliser ailleurs.

                                              EDIT: Et surtout, ton calcul pour trouver "m_Forward" est faux! Ou alors je vois pas a quoi correspondent les angles, et la verticale (habituellement z...) (cf. wikipedia)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                30 mai 2008 à 19:59:31

                                                oui d'accord, mais ça ne resoud pas mon probleme :(
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  30 mai 2008 à 20:02:23

                                                  Recommance proprement:
                                                  Dans ta classe tu ne dois avoir en attribut que:
                                                  - double m_Phi;
                                                  - double m_Theta;
                                                  - Vecteur3D m_Position;
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    30 mai 2008 à 20:03:57

                                                    ok, je vais faire ces modifs cette nuit, et je verrais ce que ça donnerais!entout cas je laisse ce topic non resolu pour mes eventuels futur-problemes.
                                                    merci à toi aussi Gravstein !
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      30 mai 2008 à 22:50:50

                                                      ok, je me rétractes, je ne pensais pas que glulookat recalculait un vecteur up en fonction de celui entré (avec 2 produits vectoriels donc), je pensais qu'il fallait l'entrer correctement sois meme.

                                                      Je pense qu'il est tout de meme important de savoir ce qu'il se passe, et qu'est ce que ce mystérieux vecteur up.

                                                      Bref, je vous laisse entre vous !
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter

                                                      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                                        31 mai 2008 à 9:58:42

                                                        En fait, l'idée du gluLookAt, c'est de multiplier la matrice courante par une matrice de changement de base:
                                                        le vecteur de direction normalisé sera la nouvelle coordonnees Z, le Up' (donc le Up recalculé par gluLookAt) sera la coordonnée y, et le vecteur Left (resultat d'un produit vectoriel entre Up' et direction) sera la coordonnée x. Le tout est ensuite multiplié par une matrice de translation pour tenir compte de la position de la caméra.

                                                        C'est trivial, mais sans quelques notions d'algèbre linéaire, ça peu paraître obscure..
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          31 mai 2008 à 12:53:39

                                                          bon voila ce que j'ai reussi a avoir en suivant les conseils de Gravstein : (vous aurez remarqué que la normal est l'axe Z maintenant!)
                                                          void Camera::OnEvent(const sf::Input& input, const double dt) {
                                                                  //on MouseMotion
                                                                      m_theta -= input.GetMouseX() - m_oldX;
                                                                      m_phi -= input.GetMouseY() - m_oldY;
                                                          
                                                                      m_oldX = input.GetMouseX();
                                                                      m_oldY = input.GetMouseY();
                                                                  //vector from angles
                                                                      Vector3D forward, left, up(0, 0, 1);
                                                                      forward.Z = sin(m_phi * M_PI / 180);
                                                                      double xTemporraire = cos(m_phi * M_PI / 180);
                                                                      forward.X = xTemporraire * cos(m_theta * M_PI / 180);
                                                                      forward.Y = xTemporraire * sin(m_theta * M_PI / 180);
                                                                      left = up.crossProduct(forward).normalize();
                                                                  //on keyboard
                                                                      if(input.IsKeyDown(sf::Key::Z))
                                                                          m_position += forward * m_speed * dt;
                                                                      if(input.IsKeyDown(sf::Key::S))
                                                                          m_position -= forward * m_speed * dt;
                                                                      if(input.IsKeyDown(sf::Key::D))
                                                                          m_position -= left * m_speed * dt;
                                                                       if(input.IsKeyDown(sf::Key::Q))
                                                                          m_position += left * m_speed * dt;
                                                          
                                                                      m_target = m_position + forward;
                                                          }
                                                          
                                                          voila, si vous avez une remarque, dites le moi!
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            1 juin 2008 à 18:32:15

                                                            mnt je me trouve confronté a un autre probleme: j'essaye d'avoir un cube devant ma camera(qui va la suivre tout en restant devant), mais malheureureusemenet, les resultats sont un peu bizarres là encore :(. Voici le code responsable:
                                                            const Vector3D& pos = Cam.Position();
                                                                            glRotated(Cam.phi(), 1, 0, 0);//rotation autour de l'axe des x
                                                                            glRotated(Cam.theta(), 0, 0, 1);//rotation autour de Z
                                                                            glTranslatef(pos.X , pos.Y + 2, pos.Z - 0.3);
                                                            
                                                                        cube(.5);//dessiner un cube
                                                            
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                              1 juin 2008 à 20:43:45

                                                              Moi j'essayerai d'inverser l'ordre des glRotated et du glTranslate.
                                                              Le but c'est bien de le tourner dans l'orientation de la caméra, einh?

                                                              Avec opengl, il faut réflechir au transformation dans l'ordre inverse: La dernière transformation que tu donnes est la première qui est appliquée à ton objet.

                                                              Donc la tu dois:
                                                              1 - Orienter ton cube
                                                              2 - Le placer en face de la camera..

                                                              Donc l'ordre est:
                                                              1 - glTranslate()
                                                              2 - glRotate(m_Phi, ...); glRotate(m_Theta, ...);

                                                              Et il ne faut pas juste décrémenter la coordonnée Z de la caméra, ca ca marche pas: il va juste placer le cube "sous" la position de la camera.
                                                              A mon avis, c'est pas la bonne solution.

                                                              Utilise plutot une première camera pour dessiner ton cube (genre une projection le long de Z, gluOrtho2D, par ex, ou simplement gluPerspective, mais sans la déplacer après) et ensuite tu utilise une autre camera pour le reste du dessin. (C'est exactement le principe utilisé pour les Gui, et autre truc qui s'affichent à l'écran dans les jeux)
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              [OpenGL]classe camera: mouvement(srtout la rotation) bizarre

                                                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                              • Editeur
                                                              • Markdown