Travaux Pratiques OpenGL
TP2
-
Le but de ce TP est d'apprendre à affecter des matériaux aux objets, à ajouter/contrôler des sources de lumière pour éclairer la scène ainsi qu'à déplacer la caméra. Voici ce que vous allez obtenir à la fin de ce TP :
-
Dans un premier temps, rappeler à quoi correspondent les composantes:
-
ambiante,
-
diffuse,
-
spéculaire,
pour une source de lumière puis pour un matériau.
Rappelez ensuite le modèle d'éclairage utilisé par OpenGL.
A Noter : Toute fonctionnalité activée avec la fonction glEnable(...) est désactivée avec la fonction glDisable(...).
-
Dans un premier temps, vous allez éclairer vos objets. Ajoutez la commande glEnable(GL_NORMALIZE) juste après l'activation du Z-Buffer (avec glEnable(GL_DEPTH_TEST)). Cette commande permet de normer automatiquement les normales des différents objets afin que leur éclairage soit calculé correctement.
-
Utilisez la touche e pour activer/désactiver l'éclairage. L'éclairage est activé à l'aide de la fonction glEnable(GL_LIGHTING). Que se passe-t-il quand vous activez l'éclairage ? Pourquoi ?
-
Il existe plusieurs lampes accessibles avec OpenGL : LIGHT_0, LIGHT_1, LIGHT_2, ...
-
Quelles sont les couleurs par défaut des composantes ambiante, diffuse et spéculaire de ces lumières ?
-
Ces lumières sont-elles directionnelles (type spot) ou éclairent-elles dans toutes les directions ?
-
Quelle est leur position par défaut ?
A l'aide de la fonction glEnable(GL_LIGHT0), éclairez/éteignez la lumière LIGHT_0 avec la touche 0. Que se passe-t-il quand elle est éclairée ? Pourquoi ?
-
Pour ce TP, vous pourrez utiliser le type Vector4 défini dans les fichiers vector4.h et vector4.c afin de vous faciliter la manipulation des couleurs des lumières et des matériaux.
-
A l'aide de la variable float light0_ambient []= {0.0,0.0,0.0,1.0} (ou Vector4 light0_ambient initialisée avec la fonction setVector4 (...)) et de la fonction glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient) modifiez la couleur de la lumière ambiante émise par la lampe 0. Observez et commentez le résultat.
-
De la même façon, observez et commentez ce qui se passe quand on change la composante diffuse avec la fonction glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse).
-
Toujours pareil, observez et commentez ce qui se passe quand on change la composante spéculaire avec la fonction glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular).
-
Vous pouvez déplacer la source de lumière avec la fonction glLightfv(GL_LIGHT0, GL_POSITION, light0_position).
Attention, la lampe se positionne dans le repère objet (dans la fonction display, dans la pile de matrice GL_MODELVIEW) et toutes les lampes doivent être positionnées avant le tracer des objets.
Placez la lampe 0 dans une position fixe, sur la gauche de la teapot.
-
Avant de regarder le matériau de l'objet, nous allons prendre un éclairage blanc commun:
light0_ambient []= {0.01,0.01,0.01,1.0};
light0_diffuse []= {1.,1.,1.,1.0};
light0_specular []= {1.,1.,1.,1.0};
light0_position []= {-5.,0.,0.,1.0};
Nous allons maintenant modifier les matériaux. Pour simplifier, nous allons utiliser le même matériau pour le cube et la teapot (même si les couleurs pourront différer par la suite).
-
Que constatez vous pour les fonctions glColor3f (...) de votre programme ?
-
Quelles sont les valeurs par défaut des composantes suivantes du matériau :
-
ambiante,
-
diffuse,
-
spéculaire,
-
brillance (shininess).
-
Note : Le matériau est un attribut des objets qui sont affichés. On peut imaginer que l'on peut utiliser un matériau différent pour le cube et la teapot. Ainsi, le matériau se définit dans notre cas dans la fonction d'affichage de l'objet (dans le fichier objet.c), avant le tracé.
A l'aide de la variable float obj_ambient [] = {0.2,0.2,0.2,1.0} et de la fonction glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, obj_ambient) modifiez la composante ambiante du matériau. Observez et commentez le résultat.
-
De la même façon, observez et commentez ce qu'il se passe quand on change la composante diffuse avec la fonction glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, obj_diffuse).
-
Toujours pareil, observez et commentez ce qui se passe quand on change la composante spéculaire avec la fonction glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, obj_specular).
-
Enfin, observez et commentez ce qui se passe quand on change la composante "brillance" avec la fonction glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, obj_shininess). Dans quel intervalle doit-on prendre cette valeur ?
-
Donnez des valeurs pour les composantes ambiante, diffuse, spéculaire et brillance du matériau pour produire un matériau type plâtre rouge.
-
Donnez les valeurs pour produire un matériau type miroir rouge.
-
Sachant qu'un matériau isolant (type plastique) a une composante spéculaire de la couleur de la source de lumière. Proposez des valeurs pour les différentes composantes du matériau pour produire un plastique PVC rouge.
-
Enfin, un matériau conducteur (type métal) a une composante spéculaire de la couleur de sa composante diffuse (les intensités peuvent être différentes). Proposez des valeurs pour les différentes composantes du matériau pour produire un métal poli rouge.
-
En passant, observons le lissage de Gouraud.
-
Rappelez le principe de ce lissage.
-
Le mode de rendu des facettes sans lissage est activé avec la fonction glShadeModel(GL_FLAT) (voir image ci-dessous). Le rendu des facettes avec le lissage de Gouraud est quant à lui activé avec la fonction glShadeModel(GL_SMOOTH). Utilisez la touche g pour basculer d'un mode de rendu à l'autre.
-
Nous allons maintenant déplacer la caméra à l'aide des flèches du clavier.
-
A quoi sert la fonction gluLookAt(...) ?
-
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.
-
Expliquez maintenant comment construire, à partir des paramètres O, X, Y, Z de la caméra, les paramètres eye (position de la caméra), vise et up du gluLookat(...).
-
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 :
-
le centre du repère caméra (= position de la caméra) : Vector4 O,
-
les 3 vecteurs du repère caméra : Vector4 X, Vector4 Y, Vector4 Z
-
Ajoutez la fonction pCamera creerCamera(Vector4 eye, Vector4 vise, Vector4 up) prenant en paramètres les 3 paramètres du gluLookat(...) et calculant le repère caméra correspondant. Créez ensuite un objet pCamera dans votre programme principal à partir des paramètres suivants : eye = {0.,0.,0.,1.}, vise = {0.,0.,-1.,1.} et up = {0.,1.,0.5,0.}.
-
Ajoutez les fonctions void eyeCamera (pCamera c, Vector4 eye), void viseCamera (pCamera c, Vector4 vise), void upCamera (pCamera c, Vector4 up) qui calculent les paramètres du gluLookat(...) à partir des attributs O,X,Y,Z de la caméra.
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.
-
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 1 pour allumer/éteindre la lumière GL_LIGHT1. GL_LIGHT1 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.
-
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 O,X,Y,Z de la caméra pour la déplacer. Par exemple, pour une translation vers l'avant, on déplace la position O de la caméra d'un certain nombre de fois le vecteur Z. Pour une rotation, O est fixe, mais on va changer l'orientation des vecteurs X,Y et Z.
-
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. Pour vous aider, vous avez à disposition les fonctions du fichier Vector4.h pour modifier les valeurs du O,X,Y et 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 TP2