Travaux Pratiques OpenGL
TP5
-
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, à partir des paramètres du gluLookat(...), 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 créé les fichiers camera.h et camera.c, créez un type tCamera (avec le type du pointeur associé pCamera) à partir d'une structure ayant pour champs :
-
la position de la camera : Vector4 pos,
-
le point visé : Vector4 vise,
-
le vecteur up : Vector4 up,
Ajoutez la fonction pCamera creerCamera(...) prenant ces 3 champs en paramètre, puis créez un objet pCamera dans votre programme principal avec les paramètres suivants : pos = {0.,0.,0.,1.}, vise = {0.,0.,2.,1.} et 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. Les attributs de la fonction gluLookAt sont donnés par les champs de la caméra.
-
Que ce passe-t-il quand vous utilisez les valeurs ci-dessus pour les paramètres du gluLookAt() ? Pourquoi ? En modifiant une seule valeur des paramètres de la caméra, restaurez l'ancienne visualisation de la scène.
-
Expliquez les valeurs des coordonnées homogènes des champs pos, vise et up de la caméra.
-
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 de la caméra.
-
Dans un premier temps, enrichissez le type Vector4 (dans les fichiers vector4.h et vector4.s téléchargés au TP3) avec les fonctions suivantes (n'oubliez pas la coordonnée homogène du vecteur res) :
-
void crossProductVector4 (Vector4 v1, Vector4 v2, Vector4 res) qui calcule dans res le produit vectoriel des vecteurs v1 et v2,
-
void normalizeVector4 (Vector4 v) qui normalise le vecteur v,
-
void sumVector4 (Vector4 v1, Vector4 v2, Vector4 res) qui retourne dans res la somme des vecteurs v1 et v2,
-
void diffVector4 (Vector4 v1, Vector4 v2, Vector4 res) qui retourne dans res le vecteur v1 moins le vecteur v2,
-
void multFloatVector4 (float f, Vector4 v, Vector4 res) qui retourne dans res le vecteur v multiplié par un flottant f,
-
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 ?
-
Remplacez les attributs de la caméra (pos, vise et up) par O, X, Y et Z, puis écrivez une fonction void repereCamera (pCamera c, Vector4 pos, Vector4 vise, Vector4 up) qui calcule les attributs O, X, Y et Z du repère orthonormé de la caméra (X, Y et Z sont donc des vecteurs unitaires) à partir des valeurs de pos, vise et up passés en paramètre. Ensuite, mettez à jour le corps de la fonction pCamera creerCamera(...). Pour finir cette étape, écrivez les fonctions qui suivent et mettez à jour les paramètres du gluLookAt() :
-
void posCamera (pCamera c, Vector4 pos) qui retourne la position de la caméra,
-
void viseCamera (pCamera c, Vector4 vise) qui retourne le point vise par la caméra. Le point visé est toujours égal à O + Z,
-
void upCamera (pCamera c, Vector4 up) qui retourne un vecteur up de la caméra (donné tout simplement par le vecteur Y),
-
Maintenant, votre gluLookAt(...) est définie de la manière suivante :
-
Commencez par faire le déplacement avant/arrière de la camera à l'aide d'une fonction void avanceCamera (pCamera c, float pas). Attention, le déplacement s'effectue dans la direction du vecteur Z de la caméra.
-
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é (qui vaut toujours O+Z) dans la direction du vecteur X. La taille du déplacement correspond à un pas dX pour une pression sur une touche gauche ou droite (le point visé est déplacé de dX * X)
-
Calculez le nouveau vecteur unitaire Z correspondant à la nouvelle position du point visé et enfin calculez le nouveau vecteur X.
-
Sur le même principe, effectuez la rotation haut/bas.
Fin du TP5