Transformations de visualisation et autres
Par Xavier Michelon


 
 
La pile de matrices :
 

Jusqu'à présent, toutes nos scènes 3D ne comportaient qu'un seul objet. Imaginons maintenant une scène contenant deux cubes placés respectivement en (1,0,2) et (5,0,0), et supposons que nous disposons d'une fonction dessineCube() qui génère un cube centré en l'origine. On pourrait penser que ce qui suit permet de créer la scène :

glLoadIdentity();
glTranslatef(1.0,0.0,2.0);
dessineCube();
glTranslatef(5.0,0.0,0.0);
dessineCube();  

Les plus malins auront vu qu'il y a un problème : le second cube sera mal positionné. Lors du dessin de ce dernier, la matrice de modélisation-visualisation contient une composition des deux translation, et le second cube sera affiché en (6,0,2). Pour y remédier, il suffit de réinitialiser la matrice après le dessin du premier cube, en appelant glLoadIdentity();

A présent, supposons qu'en plus de ces deux transformations, on souhaite appliquer une transformation de visualisation pour déplacer l'observateur :

glLoadIdentity();
gluLookAt(10.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0); 
/* Affichage et positionnement  du premier cube */
glTranslatef(1.0,0.0,2.0);
dessineCube(); 
/* Affichage et positionnement du second cube */
glLoadIdentity();
glTranslatef(5.0,0.0,0.0);
dessineCube();  

Là encore, il y a un problème : la fonction gluLookAt() a pour effet de modifier la matrice de modélisation-visualisation. Etant donné qu'on remet la matrice à zéro après le dessin du premier cube, les transformations de visualisation sont effacées et ne sont pas appliquées au second cube. La première solution qu'on peut envisager consiste à refaire un gluLookAt() après la remise à zéro de la matrice. C'est une solution peu satisfaisante : on spécifie la position de l'observateur à chaque création d’objet. Une seconde solution consiste à utiliser un mécanisme proposé par OpenGL : les piles de matrices.

Les piles:

Une pile est un mécanisme de stockage des données basé sur deux opérateurs "empiler" et "dépiler", et qui fonctionne comme un pile de linge ou de livres : empiler(x) place x au dessus de la pile, et x=dépiler() supprimer l'élément du dessus de la pile et le place dans x. On parle de mécanisme LIFO (Last In First Out, ou Dernier Entré Premier Sorti) car dépiler consiste à récupérer le dernier élément qui a été empilé.

OpenGL propose un mécanisme de pile pour la matrice de modélisation-visualisation. La fonction glPushMatrix() place une copie de la matrice active au dessus de la pile. La fonction glPopMatrix() retire la matrice située au sommet de la pile et la place dans la matrice active (en écrasant l'ancienne matrice active).

Le code qui suit permet de régler le problème que nous avions plus haut :

glLoadIdentity();
gluLookAt(10.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0);
glPushMatrix();
glTranslatef(1.0,0.0,2.0);
dessineCube();
glPopMatrix();
glTranslatef(5.0,0.0,0.0);
dessineCube();  

Les deux premières lignes mettent en place la matrice de visualisation dans la matrice active. On place ensuite une copie de cette matrice dans la pile, puis on généré le premier cube. Une fois ceci fait, on récupère la matrice de visualisation grâce à un glPopMatrix(), et on affiche le second cube.