Un petit peu de théorie
1. Dessin en trois dimension : les bases requises
Cette partie s’adresse aux
débutants, qui ne connaissent rien, ou très peu du dessin en 3 dimension.
Je ne parle pas de savoir utiliser un logiciel de dessin tel que 3DSMax,
mais vraiment de savoir comment on représente une scène, comment on effectue
les calculs, comment on translate un objet, le fait tourner…
Si vous n’y connaissez rien,
je vous conseille d’aller sur le site que j’ai réalisé l’année dernière
pour mon ancien TPFH : SDIN
(Secret Des Images Numériques, les bases de l'infographie). Tout y est
expliqué, il y a même un super programme en pascal, qui détaille tous les calculs et fait tourner
une maison en mode filiaire sur votre écran tout en éliminant les faces
cachées etc.
J'ai porté ce programme en java
(cliquez ici). Il dessine n’importe quel objet, il suffit
de lui donner le fichier texte contenant les différents segments de l’objet
dans un fichier que vous lui spécifiez dans le source HTML (voir le source
de la page).
L'intéret de ce programme, c'est qu'il effectue tous les calculs lui_même à partir de la matrice de projection identique à celle utilisée dans l'OpenGL. Remarquez qu'il ne s'agit pas de Java3D.
2. Les matrices de l’OpenGL : un élément de base
En OpenGL, toutes les transformations géométriques sont entrées sous forme de matrice, la vue est définie par la position de la caméra (matrice de changement de repère) et par la matrice de projection.
La matrice de projection s’appelle GL_PROJECTION. Il n’est possible d’accéder qu’à une matrice à la fois, donc pour modifier une matrice, il faut d’abord l’activer avec glMatrixMode(mode). La matrice choisie devient la « matrice courante ». Il reste à définir la matrice de projection, mais inutile de se revoir le cours de prépa, car heureusement des fonctions de glu permettent de spécifier les matrices les plus courantes. La fonction
void gluOrtho2D( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top )
permet dans l’exemple de mettre une matrice de projection 2D de la dimension voulue. GlLoadIdentity() initialise la matrice à l’identité.
La matrice GL_MODELVIEW est en quelque sorte la matrice de positionnement de la vue. C’est le plus souvent une matrice de changement de repère. Il faut la considérer comme une matrice qui positionne les objets dans le repère du monde, et éviter de la considérer comme la position de la caméra, même si c’est aussi son rôle.
Il existe une troisième matrice, GL_TEXTURE, mais celle-ci n’est jamais utilisée directement.
Toutes sont des matrices 4x4 de float.
3. Exemple d’initialisation de l’écran pour un rendu 3D
L’exemple qui va suivre utilise la fonction AuxReshapeFunc() qui à pour but de redimensionner correctement la scène lorsqu'on agrandit la fenêtre d'éxécution. Elle est exécutée au moins une fois, au début du programme.
void CALLBACK Reshape(GLsizei w, GLsizei h) //changement de taille de la fenetre ...
{
GLfloat aspect;
if (h == 0) h = 1;
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
switch (PERSPECTIVE_ON) //si ce n’est pas une vue en perspective que l’on veut,
{ //alors c’est une vue orthogonale
case 0 : if (w<=h)
{
clipWidth = (GLfloat)LARGEUR * h/w;
clipHeight = (GLfloat)HAUTEUR;
}
else
{
clipWidth = (GLfloat)LARGEUR;
clipHeight = (GLfloat)HAUTEUR * w/h;
}
glOrtho( -clipWidth/2, clipWidth/2, -clipHeight/2, clipHeight/2, ZMIN, ZMAX);
break;
case 1 : aspect = (GLfloat) w / (GLfloat) h;
gluPerspective(angle_of_view, aspect, ZMIN, ZMAX);
break;
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
4. Les buffers : bien comprendre ce qui se passe
Il existe dans OpenGL des « buffers »,
qui d’une manière générale ne sont que des espaces mémoires contenant des
données propres à l’OpenGL.
Le principal est le « color_buffer »,
qui correspond à ce que l’on voit sur l’écran. La fonction glClear permet
de remplir tout un buffer avec la même valeur. La valeur par défaut est
0. Un appel à glClear sur le color_buffer
rempli l’écran de noir. GlClearColor permet
de changer la couleur de remplissage.
Un autre buffer, le back-buffer, fonctionne différemment : pour ne pas voir se dessiner la scène à l’écran, on utilise la technique du « double-buffering ». Le COLOR_BUFFER est en fait dédoublé : l’un est affiché (front-buffer), l’autre est celui sur lequel on travaille (back-buffer). A chaque fois qu’une image est calculée, on inverse (swap) les buffers avec la commande auxSwapBuffers(). Pour le programmeur, tout marche comme s’il dessinait toujours sur le même buffer. L’avantage est que l’utilisateur ne vois pas se dessiner l’image.
Les autres buffers standards sont le Depth-buffer, le Stencil-buffer, l’Accumulation-buffer. Chaque buffer joue un rôle précis, mais ils ne seront présentés que lorsque nous en aurons besoin. D’autres sont des extensions propriétaires (T-Buffer, W-Buffer, …).
On initialise un ou plusieurs buffers au début du programme avec la commande auxInitDisplayMode(buffer1 | buffer2 | buffer3 | …). Les noms des buffers sont les suivants :
- Double buffering : AUX_DOUBLE
- Color Buffer (image de l’écran) : AUX_RGBA
- Depth Buffer : AUX_DEPTH
- Stencil buffer : AUX_STENCIL
De même, pour effacer ces buffers, on untilise la commande glClear( buffer1 | buffer2 | buffer 3 | …) avec, cette fois-ci, comme nom pour les buffers :
- Color Buffer (image de l’écran) : GL_COLOR_BUFFER_BIT
- Depth Buffer : GL_DEPTH_BUFFER_BIT
- Stencil buffer : GL_STENCIL_BUFFER_BIT