Travaux Pratiques OpenGL
TP6
-
Le but de ce TP est de se familiariser avec le déplacement de la caméra dans une scène avec la fonction gluLookAt(...). A la fin de ce TP, vous pourrez naviguer dans la scène ainsi :
-
A quoi sert la fonction gluLookAt(...) ?
-
Donnez les paramètres de la fonction gluLookAt(...) et expliquez ce qu'ils représentent.
-
Expliquez comment construire le repère orthonormé direct de la caméra ayant comme origine O la position de la caméra, comme vecteur X la direction de droite, comme vecteur Y la direction du haut et comme vecteur Z la position visée.
-
Après avoir déclaré :
-
la position de la camera : static float _pos[] = {0.,0.,0.,1.},
-
le point visé : static float _vise[] = {0.,0.,2.,1.},
-
le vecteur up : static float _up[] = {0.,1.,0.5,0.},
ajoutez la fonction gluLookAt(...) dans votre code. Il faut savoir que cette fonction s'applique sur la pile de matrices MODELVIEW et que l'on souhaite positionner la caméra avant de placer et tracer les différents objets de la scène.
-
Que ce passe-t-il quand vous utilisez les valeurs ci-dessus pour les paramètres du gluLookAt() ? Pourquoi ? En modifiant une seule valeur, restaurez l'ancienne visualisation de la scène.
-
Expliquez les valeurs des coordonnées homogènes des variables _pos, _vise et _up.
-
A ce niveau, il est intéressant de noter le comportement d'une source de lumière par rapport à la caméra. Une source de lumière positionnée après le gluLookAt() ne tiendra pas compte de la position de la caméra. Sa position est définie par rapport au repère scène. Par contre, une source de lumière dont la position est définie juste avant le gluLookAt() est positionnée par rapport au repère de la caméra (sa position est alors relative à celle de la caméra). Positionnez correctement la lumière GL_LIGHT0 pour qu'elle soit fixe dans la scène (elle ne doit pas bouger si on déplace la caméra).
Utilisez la touche 2 pour allumer/éteindre la lumière GL_LIGHT2. GL_LIGHT2 doit être un spot de lumière blanche, avec un angle d'ouverture de 40 degrés et un coefficient d'atténuation de 20. Ce spot positionné à la position de la caméra et éclairant droit devant, doit se déplacer avec la caméra. C'est un peu comme une lampe de poche attachée à la caméra pour éclairer ce que l'on a devant nous dans la scène.
Illustration à gauche de la lampe GL_LIGHT0 et à droite du spot GL_LIGHT2 :
Lumière GL_LIGHT_0 allumée
|
Spot GL_LIGHT_2 allumé
|
|
|
-
Nous allons créer une navigation de type walk, c'est à dire que l'on va pouvoir se déplacer dans la scène comme un utilisateur qui peut marcher dans le vide. Il va falloir développer les fonctionnalités suivantes :
-
avancer/reculer : la caméra se déplace vers l'avant ou l'arrière dans sa direction Z,
-
tourner sur la gauche/droite par rotation autour de l'axe verical Y de la caméra,
-
s'orienter vers le haut/bas par rotation autour de l'axe horizontal X de la caméra.
Pour cela, nous allons utiliser les flèches du clavier pour avancer/reculer et gauche/droite, ainsi que les touches h et b pour haut/bas.
-
Pour accéder aux flèches du clavier, ajoutez la fonction glutSpecialFunc (arrow) (par exemple juste sous la fonction glutKeyboardFunc (key) du main de votre programme), puis écrire la fonction void arrow (int key, int mousex, int mousey) {...} sur le même modèle que la fonction void key (void) {...}. Le test switch est effectué sur la variable key et les flèches gauche, droite, bas, haut sont prises en compte avec respectivement case GLUT_KEY_LEFT, case GLUT_KEY_RIGHT, case GLUT_KEY_DOWN, case GLUT_KEY_UP.
-
Chaque pression sur une touche provoque un déplacement (en translation ou rotation) et le déplacement est effectué en calculant les nouvelles valeurs des paramètres de la fonction gluLookAt(). Il ne s'agit donc plus d'empiler et de dépiler des matrices de transformation OpenGL, mais de calculer "à la main" les nouveaux paramètres.
-
Créez le type vecteur : typedef float Vector[4]; puis écrivez les fonctions suivantes (n'oubliez pas la coordonnée homogène du vecteur res):
-
void crossProduct (Vector v1, Vector v2, Vector res){...} qui calcule dans res le produit vectoriel des vecteurs v1 et v2,
-
void normalize (Vector v){...} qui normalise le vecteur v,
-
void sum (Vector v1, Vector v2, Vector res){...} qui retourne dans res la somme des vecteurs v1 et v2,
-
void diff (Vector v1, Vector v2, Vector res){...} qui retourne dans res le vecteur v1 moins le vecteur v2,
-
void multFloat (float f, Vector v, Vector res){...} qui retourne dans res le vecteur v multiplié par un flottant f,
-
void copy (Vector v, Vector res){...} qui recopie le vecteur v dans res.
-
Faites un schéma représentant le centre du repère scène, la position de la caméra _pos, le point visé _vise et le vecteur _up. Faites un autre schéma avec le repère orthonormé de la caméra (OXYZ). Quelle différence y a-t-il entre le vecteur _up et le vecteur Y ?
-
Dans le début de la fonction main() de votre programme, calculez les valeurs initiales du repère orthonormé de la caméra (OXYZ) à partir des valeurs de _pos, _vise et _up, puis modifiez le point visé _vise de la la façon suivante : _vise = _pos + Z. Pourquoi cela ne change-t-il pas ce que l'on voit ?
-
Dans la fonction gluLookAt(), remplacez le vecteur _up par le vecteur Y. Pourquoi cette opération ne modifie pas ce que l'on voit ?
-
Maintenant, votre camera est définie de la manière suivante :
-
Commencez par faire le déplacement avant/arrière. Que va-t-il se passer en avançant si vous ne modifiez que la position de la caméra (_pos) et pas celle du point visé (_vise) ? Pourquoi ? En fait, _vise doit toujours resté égal à _pos+Z.
-
Regardons maintenant les rotations :
-
La rotation autour de l'axe Y va être effectuée en suivant la méthode suivante :
-
Déplacez le point visé de la direction dX*X correspondant à une pression sur une touche gauche ou droite.
-
Calculez le nouveau vecteur unitaire Z, puis la position finale du point visé (_vise = _pos + Z) et enfin le nouveau vecteur X.
-
Sur le même principe, effectuez la rotation haut/bas.
Fin du TP6