Travaux Pratiques OpenGL
TPs 2 et 3
-
Le but de ce TP est d'apprendre à utiliser les matrices de transformation pour placer/modéliser des objets et les animer. 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 construit le modèle suivant :
-
Le TP se décompose en 4 parties:
-
Mise en place de la projection:
-
Tout d'abord, l'image doit être effacée en noir.
-
La fenêtre de projection fait la taille de la fenêtre d'affichage.
-
La projection se fait en perspective avec un angle d'ouverture de 60 degrés, un rapport d'aspect évitant les distortions, un plan avant à 2 et un plan arrière à 20.
-
Crétion d'un objet composé:
-
Rappelez la différence qu'il y a entre la pile de matrice GL_PROJECTION et la pile de matrice GL_MODELVIEW.
-
Voici quelques fonctions permettant de créer des primitives 3D directement: glutSolidCone(...), glutSolidCube(...), glutSolidSphere(...), glutSolidTorus(...), etc.
Une documentation sur la glut peut être trouvée sur le site suivant:
http://openglut.sourceforge.net/
et la documentation sur les primitives 3D est à l'adresse:
http://openglut.sourceforge.net/group__geometry.html
-
Tracez un cube vert de taille 1 à une profondeur de 5 puis une sphère bleue de rayon 0.5 dont le centre est le centre de la face supérieure du cube.
Maintenant tracez d'abord la sphére (à la même position) puis le cube. Que ce passe-t-il? Pourquoi?
-
Restaurez l'ordre de tracé : cube puis sphère avant de continuer.
-
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 partie inférieure de la sphère doit maintenant être cachée par le cube.
-
Pour vous assurer que Z-Buffer fonctionne correctement, faites tourner l'ensemble "cube + sphère" de 45 degrés vers l'avant. Vous devez alors obtenir le résultat suivant:
-
Puis amenez l'ensemble dans la position suivante:
-
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().
Utilisez ces fonctions autour du positionnement/tracé de la sphère de manière à positionner et tracer par rapport au repère du cube un cône jaune de rayon 0.5 et de hauteur 1, dans la position suivante :
-
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 une variable globale statique static float _rotY = 0.;, utilisez la fonction noEvent pour faire tourner en continu l'objet complet (cube + sphère + cône) autour de l'axe Y centré au centre du cube.
Aide: la variable "_rotY" est incrémentée dans la fonction "noEvent" et la rotation d'angle "_rotY" est effectuée dans le "display".
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?
-
En utilisant une variable globale statique static int _rot = 0;, on souhaite maintenant 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.
-
Modélisation et animation d'un objet complexe (continuez avec le programme que vous venez d'écrire en enlevant juste les rotations de 45 degrés autour de X et Y, le tracé du cube, de la sphère et du cône) :
-
Dans un premier temps, ajustez la taille de la fenêtre à une taille de 800×800 pixels. Puis créez la fonction void traceAxeSpheres(float longAxe, float rayonAxe, float rayonSphere, float redAxe, float greenAxe, float bleuAxe, float redSphere, float greenSphere, float bleuSphere) {...} qui trace un axe cylindrique centré à l'origine, le long de l'axe des Z et entouré de deux sphères. Expliquez pourquoi il est préférable d'entourer les fonctions de positionnement et de tracé de cet ensemble (cylindre + sphères) par un PushMatrix() au début et un PopMatrix() à la fin.
Pour tracer un cylindre :
-
Déclarez une variable globale statique static GLUquadricObj* _quad.
-
Construisez l'objet (allocation mémoire) au début de la fonction main (par exemple) avec la fonction _quad = gluNewQuadric().
-
Vous maintenant pouvez tracer un cylindre (ou un cône) ouvert avec la fonction gluCylinder (_quad, rayonInitial, rayonFinal, longueur, 30,10).
Voici le résultat obtenu aprè avoir translaté le modèle dans les z négatifs et avoir effectué une rotation de 90 degrés autour de l'axe des Y :
...
glMatrixMode(GL_MODELVIEW); //Activation de la pile de matrice de placement
glLoadIdentity(); //Initialisation de la pile de matrice
glTranslatef (0.,0.,-5.); //Translation dans les Z negatifs
glRotatef(90.,0.,1.,0.); //Rotation de 90 degrés autour de l'axe Y
traceAxeSpheres (2., 0.2, 0.5, 0.5,.5,0.5, 0.,0.,1.);
...
-
A l'aide de cette fonction, modélisez et animez le robo. Il est conseillé d'utiliser des variables locales (éventuellement globales) pour la taille du cube (coteCube), la hauteur du cône (hautCone), son rayon, etc. Cela permettra de simplifier l'écriture des matrices de transformation ainsi que la "modification/mise au point" du modèle.
-
Toujours avec la touche a, le robo "tourne/arrête de tourner" autour de de son axe vertical.
-
Avec la touche t, l'hélice du robo "commence/arrête" de tourner autour d'un axe incliné vers l'arrière (comme illustré ci-dessous).
-
En laissant appuyé sur la touche +, l'hélice tourne de plus en plus vite.
-
En laissant appuyé sur la touche -, l'hélice ralentit, puis s'arrête jusqu'à tourner de plus en plus vite dans l'autre sens.
-
La touche i pourra être utilisée pour arrêter toutes les animations et remettre le robo dans sa position initiale.
Fin des TPs 2 et 3