Travaux Pratiques OpenGL
TPs 4 et 5
-
Le but de ce TP est d'apprendre à affecter des matériaux aux objets et à ajouter/contrôler des sources de lumière pour éclairer la scène. 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 le robo. Mettez la couleur d'effacement du buffer image à noir et utilisez une fenêtre de 800*800 (pensez à ajuster la viewport et le rapport d'aspect de la projection perspective). Positionnez le robo à une profondeur d'environ -10 dans les Z négatifs. Ajoutez aussi 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 ?
-
A l'aide de la variable float light0_ambient []= {0.0,0.0,0.0,1.0} 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 (avec la pile de matrice MODELVIEW) et toutes les lampes doivent être positionnées avant le tracé des objets.
Placez la lampe 0 dans une position fixe, sur la gauche du robo.
-
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 []= {-4.,4.,-8.,1.0};
Nous allons maintenant modifier le matériau du robo. Pour simplifier, tout le robo est composée du même matériau (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 pourrait utiliser un matériau différent pour chaque élément du robo. Ainsi, le matériau se définit dans notre cas dans la fonction de rendu, avant de tracer l'objet.
A l'aide de la variable globale static float robo_ambient [] = {0.2,0.2,0.2,1.0} et de la fonction glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, robo_ambient) modifiez la composante ambiante du matériau. 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 glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, robo_diffuse).
-
Toujours pareil, observez et commentez ce qu'il se passe quand on change la composante spéculaire avec la fonction glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, robo_specular).
-
Enfin, observez et commentez ce qu'il se passe quand on change la composante "brillance" avec la fonction glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, robo_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 (purement diffus).
-
Donnez les valeurs pour produire un matériau type miroir rouge (purement spéculaire).
-
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.
-
Supposons que le robo est en PVC. Nous allons voir comment utiliser la fonction glColor3f(...) pour contrôler la couleur de ses différentes parties.
Tout d'abord, il faut activer le mode de contrôle du matériau par la couleur avec la fonction glEnable(GL_COLOR_MATERIAL).
Puis, la fonction glColorMaterial(...) permet de sélectionner les composantes du matériau qui vont être contrôlées par la fonction glColor3f(). Ainsi glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR) spécifie que la fonction glColor3f() modifie la composante spéculaire du matériau.
Décidons que la composante ambiante et la composante diffuse du matériau sont identiques pour notre PVC. Utilisez convenablement la fonction glColorMaterial() pour obtenir le résultat suivant en contrôlant les couleurs avec les fonctions glColor3f() telles qu'elles sont depuis le TP précédent (sans modifier ni leur valeur, ni leur position).
-
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 ajouter un sol sous la forme d'un rectangle. Un rectangle peut être tracé avec les fonctions glBegin (GL_QUADS) et glEnd(). Entres ces deux fonctions, les sommets des quadrilatères sont donnés avec la fonction glVertex3f (...) et les normales sont spécifiées avec la fonction glNormal3f (...).
Ecrivez la fonction void traceCarreXZ () {...} qui trace un carré de côté 1, centré à l'origine dans le plan (XZ). En utilisant une translation, placez le carré sous le robo et avec un changement d'echelle, donnez lui une largeur de 10.
-
La lampe va être matérialisée avec une sphère de la couleur de la lumière (blanche).
-
Dans un premier temps, avec la fonction gluSphere(_quad, 0.1,20,20) tracez une sphère de rayon 0.1 centrée sur la position de la lumière GL_LIGHT0.
-
Quand vous activez l'éclairage et que vous allumez la lumière GL_LIGHT0, est-ce que la sphère est éclairée ? Pourquoi ?
-
Modifiez le programme pour que la sphère s'éclaire quand vous allumez la lumière GL_LIGHT0. Pour y arriver, vous pouvez inverser les normales de la sphère avec la fonction gluQuadricOrientation (_quad,GLU_INSIDE). N'oubliez pas de restaurer l'orientation correcte des normales après le tracé de la sphère (pour le tracé des autres objets) avec la fonction gluQuadricOrientation (_quad,GLU_OUTSIDE).
-
Pour finir, le matériau de la sphère doit avoir une composante spéculaire nulle. Pensez à restaurer la composante spéculaire des autres matériaux après le tracé de la sphère.
-
Nous allons maintenant enrichir la scène avec une lumière (GL_LIGHT1) jaune type spot placée dans un premier temps au dessus du robo et eclairant vers le bas. Le spot GL_LIGHT1 s'allumera/s'éteindra avec la touche 1. Le spot est représenté par une sphère jaune de rayon 0.1 et il a un angle d'ouverture de 60 degrés. Avec la lampe GL_LIGHT0 éteinte et le spot GL_LIGHT1 allumé, vous obtiendrez le résultat ci-dessous :
Lisez bien toutes les indications qui suivent avant de commencer cet exercice.
Pour faire cet exercice vous aurez besoin des informations suivantes :
-
Rappel : Les sources de lumière sont positionnées avec la pile de matrice MODELVIEW et elles doivent toutes avoir été positionnées avant que le premier objet soit tracé.
-
Pour transformer une lampe en spot, on peut utiliser les fonctions suivantes:
-
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light1_direction) qui spécifie la direction de visée du spot (vers le haut : float light1_direction[] = {0.,1.,0.,0.}). Comme la position de la lampe, ce vecteur est transformé par la matrice MODELVIEW.
-
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, attenuation) qui définit le coefficient d'atténuation (un flottant) de la lumière émise par le spot par rapport à l'axe de visée. Par défaut, cette valeur est à zéro (pas d'atténuation). Utilisez tout d'abord la valeur 20. A la fin du TP, vous pourrez modifier cette valeur pour constater son effet (essayez notament la valeur 0 ou 1).
-
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, angle) qui définit l'angle d'ouverture du spot (un flottant).
-
La sphère jaune représantant le spot GL_LIGHT1 ne doit pas être éclairé par la lampe GL_LIGHT0. Cette sphère doit aussi avoir une composante spéculaire nulle.
-
Observez l'éclairage du plan. Est-il correct ? Quel résurltat devriez-vous obtenir ? Pourquoi est-ce ainsi ?
Pour éviter ce problème, il faut découper le carré en plusieurs petits carré comme illustré ci-dessous (affichage filaire avec les lampes 0 et 1 allumées) :
Modifiez la fonction traceCarreXZ () en void traceCarreXZ (int lig, int col) {...} pour découper le carré unitaire en lig lignes et col colonnes. Une fois fait, affichez le carré avec 20 lignes et 20 colonnes. Vous devez obtenir le résultat suivant quand le spot 1 est allumé seul :
-
Pour finir, placez le spot un peu plus bas sur la droite et orientez le en diagonale. Avec une pression sur la touche s le spot commence/arrête de tourner autour de l'axe vertical du robo comme illustré ci-dessous. Si on active la rotation du robo autour de son axe vertical avec la touche a (TP2-3), sans avoir actionné la touche s, le spot doit tourner avec le robo ainsi que le plan.
Fin des TPs 4 et 5