Travaux Pratiques OpenGL
TP1
-
Attention: pour pouvoir effectuer les TPs correctement, vous aurez besoin de votre cours. Vous pouvez aussi vous référer au guide de programmation (html) :
http://www.opengl.org/
Vous pouvez aussi accéder à l'aide en ligne avec la commande :
man <nom_fonction>
Ou encore utiliser konqueror et taper :
man:<nom_fonction>
-
L'évaluation des TPs se fera à partir:
-
D'une validation qui se fera au début de chaque scéance : Ainsi, au debut de chaque scéance votre encadrant de TP validera le TP de la scéance précédante. Il est à noter que les TPs demanderont très certainement un investissement supplémentaire pour être correctement terminés.
-
D'un compte rendu de TPs qui sera remis à l'enseignant en version imprimée ou manuscrite lors de la dernière scéance de validation. Ce compte rendu comprendra les réponses aux questions posées dans les sujets des différents TPs, ainsi qu'un récapitulatif mettant en évidence le travail effectué par l'étudiant.
-
Avant de pouvoir commencer votre TP, il vous faut installer la structure de programme de départ. Suivez les instructions suivantes :
-
Créez un répertoire qui sera votre répertoire de travail pour les TPs d'OpenGL.
-
Téléchargez dans ce répertoire le fichier suivant:
https://www.irit.fr/~Loic.Barthe/Enseignements/TPs_OpenGL/TP1/intro_OpenGL.tar.gz
-
Décompressez l'archive dans le répertoire puis effacez la.
-
Dans un shell, placez vous dans le répertoire où vous avez décompressé les fichiers et compilez le programme en tapant:
make
Les fichiers objets (.o) et l'exécutable (nommé "tp1") sont dans le répertoire "bin".
Lancez le programme avec la commande:
./bin/tp1
-
Editez le programme principal "main.c". Il est suggéré d'utiliser l'éditeur "kate" qui se lance avec la commande:
kate main.c &
-
Attendez maintenant que votre enseignant explique les différentes fonctions qui sont déjà présentes dans le programme. Il vous expliquera aussi le principe de la programmation OpenGL: machine à état avec laquelle on fait de la programmation événementielle.
-
Le but de ce TP est de se familiariser avec le mode d'affichage OpenGL, la matrice de projection perspective, le positionnement d'un objet, la gestion de la couleur en RVB ainsi que l'animation d'un objet en modifiant ses matrices de transformation. En même temps, il va être possible de se familiariser avec la programmation évènementielle, l'élimination des parties cachées et le bouble buffer.
A la fin de ce TP vous aurez créé et animé la scène suivante:
-
Effacement de la fenêtre:
-
Que se passe-t-il quand vous exécutez le programme? Pourquoi?
-
Dans la fonction "display" du fichier "main.c", ajoutez la fonction suivante en première ligne:
glClear (GL_COLOR_BUFFER_BIT);
Que se passe-t-il? Pourquoi?
-
Ajoutez juste après la fonction:
glClearColor (1.0, 1.0, 1.0, 0.0);
Quelle est la couleur (1.0, 1.0, 1.0)? On notera que la 4ème composante de la couleur est la composante Alpha qui sert à régler la transparence. Pour les TPs, cette composante sera fixée à 0.0 (pas de transparence).
Que se passe-t-il? Pourquoi?
Positionnez cette fonction à la bonne place pour que la fenêtre soit effacée avec la couleur souhaitée.
Faites effacer la fenêtre en rouge, puis en gris foncé.
-
L'effacement du buffer image est en général la première chose que l'on fait dans la fonction de rendu (display). Ensuite, on va définir la fenêtre de projection puis la matrice de projection et enfin on va tracer les objets.
-
La fenêtre et la matrice de projection ont des valeurs par défaut, ainsi, il est possible de tracer directement un objet.
Tracez une théière (teapot) de rayon 1 centrée sur l'origine du repère scène à l'aide de la fonction suivante:
glutSolidTeapot(1.);
-
La fonction "glColor3f(...)" permet de modifier la couleur d'affichage des objets à l'aide de 3 flottants (rouge,vert,bleu) passés en paramètre. Placez cette fonction au mieux pour que la théière soit tracée en jaune.
-
Il s'agit maintenant de retrouver les valeurs par défaut de la fenêtre. On précise que la projection par défaut est une projection orthogonale (pas de perspective).
Intéressons nous tout d'abord à la fenêtre de projection. Elle définit la position et la taille de l'image qui va être affichée dans la fenêtre de l'application OpenGL. Elle est définie par la fonction:
glViewport(x,y,l,h);
Que représentent les paramètres x,y,l et h?
Insérez cette fonction dans votre programme et retrouvez la valeur par défaut de ses paramètres.
Quelles valeurs faut-il donner à ces paramètres pour obtenir l'image suivante (l'image occupe la moitié supérieure de la fenêtre, calée à droite et elle est carrée: 300 pixels de côté):
Reprenons maintenant les valeurs par défaut de la fenêtre de projection appelée viewport. Nous allons ajouter une matrice de projection perspective.
-
Tout d'abord, il nous faut ajouter à la fonction de rendu (display) les fonctions permettant de contrôler la projection.
-
Dans un premier temps, il nous faut passer en mode de modification de la matrice de projection avec la fonction:
glMatrixMode (GL_PROJECTION);
-
Puis on va initialiser la matrice de projection avec la fonction:
glLoadIdentity ();
Quelle est la valeur de la matrice de projection?
Que se passe-t-il au niveau de l'affichage?
-
Modifiez maintenant la matrice de projection perspective à l'aide de la fonction suivante:
gluPerspective(60.,3.,2.,100.);
Que représentent les paramètres de cette fonctions?
Faites un schéma du volume de vision de la caméra faisant apparaître les différents paramètres.
Pourquoi ne voit-on plus la teapot à l'écran ?
-
Afin de pouvoir voir la teapot, nous allons la déplacer.
-
Pour déplacer la théière, nous allons utiliser les matrices de transformation (mode MODELVIEW). Il nous faut donc dans un premier temps activer le mode de modification de matrice de transformation (ceci désactivera le mode de modification de matrice de projection que nous avions activé précédemment). Ceci est fait en ajoutant au programme la fonction:
glMatrixMode (GL_MODELVIEW);
Comment initialiser cette matrice de transformation? Une fois la fonction précédente ajoutée à votre programme, initialisez la matrice.
-
Déplacez maintenant la théière en faisant la translation suivante:
glTranslatef(0.,0.,-1.5);
Vous pouvez constater que l'on voit un bout de teapot. Modifiez le plan "near" de votre projection puis la translation pour que l'on puisse voir la teapot approximativement comme sur l'image suivante :
-
Ajustez maintenant le rapport d'aspect de la projection pour que la teapot soit visualisée sans distortion comme suit :
-
Ajoutez une rotation et une mise à l'échelle à l'aide des fonctions :
glRotatef (...)
glScalef(...)
pour placer la teapot afin que le rendu s'approche de l'image suivante :
-
L'affichage par défaut est un mode plein. On peut passer en affichage filaire en utilisant la fonction:
glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
On peut repasser en mode plein avec les paramètres:
glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
Modifiez votre programme pour que la théière soit affichée en filaire.
-
Mettons maintenant la scéne et l'affichage dans la disposition présentée dans l'image ci-dessous.
Les objets (teapot et cube) sont à une profondeur de 5 en z (plus de rotation ni de mise à l'échelle).
Le cube peut être tracé avec la fonction :
glutSolidCube(...)
Pourquoi le cube apparait-il devant la teapot ?
-
Nous allons maintenant activer le test de profondeur pour éliminer les faces cachées: le Z-Buffer. Expliquez succinctement son fonctionnement.
-
Tout d'abord, il faut initialiser le mode d'affichage avec test des profondeurs dans la fonction glutInitDisplayMode en ajoutant le paramètre GLUT_DEPTH.
-
Ensuite, il faut activer le test des profondeurs à l'aide de la fonction glEnable(GL_DEPTH_TEST) placée juste après la création de la fenêtre principale avec la glut (dans le main(...)). Il est à noter que le Z-Buffer peut être désactivé n'importe quand avec la commande glDisable(GL_DEPTH_TEST).
-
Enfin, il faut aussi effacer cette mémoire (buffer) au début de chaque tracé, en même temps que la mémoire d'image (color buffer). Ceci est effectué en ajoutant "| GL_DEPTH_BUFFER_BIT" dans la fonction glClear.
-
La teapot doit maintenant apparaître posée sur le cube.
-
Telechargez maintenant les fichiers suivants :
objet.h
objet.c
et positionnez les dans le répertoire contenant votre fichier main.c
Effectuez les modification suivantes dans le fichier main.c :
Ajoutez une variable globale pObjet obj;
Au début du main créez le pointeur avec la ligne obj = creerObjet();
Dans la fonction void display (void) ajoutez la fonction afficheObjetOpenGL (obj); juste après l'initialisation de la pile de matrice GL_MODELVIEW.
Dans la fonction void afficheObjetOpenGL (pObjet obj) du fichier objet.c recopiez les quelques lignes traçant le cube et la teapot et enlevez les de la fonction display du fichier main.c.
Dans le fichier Makefile.common ajoutez objet.c à la variable APPFILES (le séparateur est un espace).
Attention : à chaque fois que vous créez un nouveau fichier .c il vous faut l'ajouter dans le fichier Makefile.common pour qu'il soit correctement compilé.
Compilez le programme et executez le. Si tout va bien, vous devez avoir le même résultat qu'avant ces modifications.
Présentez la nouvelle structure du programme et expliquez l'intérêt de procéder ainsi.
-
Expliquez brièvement le principe d'empilement et de dépilement de matrices. L'empilement est effectué avec glPushMatrix() et le dépilement avec la fonction glPopMatrix().
Pour finir les modifications précédentes, la fonction void afficheObjetOpenGL (pObjet obj) du fichier objet.c doit commencer par la fonction glPushMatrix() et finir par la fonction glPopMatrix(). Faites le dans votre code et expliquez pourquoi.
Utilisez ces fonctions autour du positionnement/tracé de la teapot.
-
Gestion des évènements:
-
Une lettre (par exemple, la lettre a) est testée dans un switch par le test case 'a'. Utilisez la lettre w pour passer en mode d'affichage filaire et la lettre W pour repasser en mode d'affichage plein.
Si vous souhaitez forcer le réaffichage de la fenêtre, cela peut être fait avec la fonction glutPostRedisplay().
-
Utilisez la lettre z pour désactiver le Z-Buffer et la lettre Z pour le réactiver.
-
La glut permet aussi d'appeler une fonction de façon répétitive à tout moment où aucun évènement n'est détecté. Cette fonction que l'on appellera noEvent est activée avec la glut au même niveau que la fonction de rendu (glutDisplayFunc(display)) et la fonction de gestion des évènements clavier (glutKeyboardFunc(key)) en utilisant la fonction glutIdleFunc(noEvent).
Comme les fonctions "display" et "key", cette fonction ce déclare:
void noEvent (void) {}
Avec la fonction void tourneObjet (pObjet obj, float pasRotation), utilisez la fonction noEvent pour faire tourner en continu la teapot sur le cube, autour de l'axe Y centré au centre du cube.
Aide: l'attribut theta de l'objet est incrémenté gràce à la fonction void tourneObjet (pObjet obj, float pasRotation) appelée dans la fonction "noEvent" et la rotation d'angle obj->theta est effectuée dans la fonction void afficheObjetOpenGL (pObjet obj).
Que remarquez-vous au niveau de la qualité d'affichage ?
-
La qualité de l'affichage peut être améliorée en utilisant le double buffer. Expliquez brièvement en quoi consiste cette technique.
Le double buffer est activé en remplaçant dans la fonction glutInitDisplayMode la valeur GLUT_SINGLE par GLUT_DOUBLE. Le "swap" des buffers est alors réalisé à la fin de la fonction de rendu (display) avec la fonction glutSwapBuffers() placée juste avant la fonction glFlush ().
Pourquoi est-il judicieux de placer la fonction glutSwapBuffers() à cet endroit là? Le résultat est-il meilleur que sans le double buffer?
-
Modifiez votre code pour que l'animation commence quand on presse la touche a et qu'elle s'arrête quand on represse la touche a puis qu'elle recommence si on réappuit et ainsi de suite. Modifiez de même les touches w et z.
Fin du TP1