Ecole Polytechnique Fédérale de Lausanne
Section Sciences de la vie
Projets en Informatique
Tutoriel wxWidgets et OpenGL

Complément: Fonctionnement d'OpenGL

But

Comprendre plus en détails le fonctionnement de base d'OpenGL.

On rappelle que le but d'OpenGL est de créer une représentation à l'écran d'un modèle tridimensionnel spécifié par le développeur.



Capture d'écran tirée du projet de jeu libre Apricot, (c) copyright Blender Foundation | apricot.blender.org.

La base du modèle consiste en

  1. Le modèle mathématique de projection (perspective, orthographique, etc.)
  2. Les caractéristique de la caméra virtuelle, comme position, point visé, angle de vision, etc.
  3. La représentation géométrique de l'objet. Par exemple, dans la cas d'un objet polygonal, les coordonnées des points des faces qui le composent.

Il peut aussi contenir des informations plus complexes telles que:

Dans les sections qui suivent, nous décrivons brièvement le fonctionnement de la représentation des trois premiers points du modèle, du point de vue théorique, et de celui d'OpenGL.

Notons que la création d'une représentation réaliste des deux derniers points constitue tout un domaine, complexe, de recherche en informatique et en mathématiques.

Projections

Pour représenter des objets d'un espace à trois dimensions dans un espace à deux dimensions comme un écran, il faut déterminer une projection .

Perspective centrale

La perspective centrale modélise bien le fonctionnement de la vision humaine ou celui d'un appareil photo.

Dans un cas tout à fait général, elle se caractérise par:

  1. Un centre (caméra)
  2. Un plan de projection (écran).

Pour le dessin sur écran, on rajoute les caractéristiques suivantes:

  1. Une distance maximale de dessin (zFar).
  2. Des dimensions finies au plan de projection (dimensions de la vue l,h).

On préfère généralement caractériser l'écran (2. et 5.) par:

  1. L'angle de vue vertical (field of view, voir dessin). Une valeur de 65° est assez naturelle et convient généralement bien.
  2. Le rapport de ses dimensions l/h (aspect).
  3. Un point visé par la caméra. Le plan sera alors orthogonal à la droite reliant la caméra au point.
  4. La distance de l'écran au centre. Ce sera aussi la distance minimale de dessin (zNear).

Exemple et coordonnées homogènes

Construisons une perspective simple avec une caméra à l'origine et un écran infini à une distance de 1/2, orthogonal à l'axe Oy.

L'application de Thalès donne, en prenant pour le plan un système de deux axes créé par translation de Oxz en (0,1,0):

On ne peut représenter cette fonction sous la forme

avec une matrice classique de type 3x3.

La solution est d'utiliser les coordonnées homogènes (x,y,z,w), ce que fait OpenGL.

Les coordonnées homogènes (x,y,z,w), avec w non nul, correspondent aux coordonnées cartésiennes (x/w,y/w,z/w).

Elles permettent de représenter les transformations usuelles (translations, redimensionnement, rotation, réflexion) à l'aide d'un seul produit matriciel.

Dans notre cas, on peut en effet écrire

Si l'on représente maintenant les images de points à gauche, on obtient, en dessinant encore les arêtes:

(0.317, 6.167, 1)
(0.317, 6.167, -1)
(1.378, 7.863, 1)
(1.378, 7.863, -1)
(-1.378, 7.228, 1)
(-1.378, 7.228, -1)
(-0.317, 8.924, 1)
(-0.317, 8.924, -1)

Projections dans OpenGL et matrices

OpenGL stocke les informations du modèle relativement à la projection dans une matrice 4x4 (voir ci-dessus) GL_PROJECTION.

Toutefois, il sera fait une distinction entre les caractéristiques de la projection et celles de la caméra!

La matrice de projection contiendra seulement une transformation "de base". Dans le cas de la perspective centrale, il s'agira d'une perspective avec un centre à l'origine et un plan perpendiculaire à l'axe (0,0,1), comme nous l'avons fait dans notre exemple.

Les informations codées sont alors:

  1. La distance maximale de dessin (zFar).
  2. Les caractéristiques de l'écran (voir ci-dessus).

Les caractéristiques de la caméra (position et orientation de l'écran) seront stockées dans la matrice GL_MODELVIEW sous la forme d'une nouvelle transformation. La matrice GL_MODELVIEW contiendra:

Note
Ces deux matrices sont combinées puisque les transformations sur la caméra sont équivalentes aux transformations sur la scène (déplacer la caméra vers la gauche revient à déplacer la scène vers la droite)

Les coordonnées finales des objets seront alors (plus ou moins) la composition des deux transformations:

Gestion de la profondeur

Cette question ne se pose pas lors d'un affichage "par points", mais supposons que l'on dessine le cube ci-dessus avec des faces pleines, de couleur. On ne souhaite alors pas afficher les parties de faces cachées par d'autres!

Solution naïve

Une solution très simple est l'algorithme du peintre, qui consiste à dessiner d'abord les objets éloignés, jusqu'aux proches, qui pourront alors recouvrir certaines parties des autres. Elle est toutefois aussi très peu efficace dans des situations à peine plus compliquées que celle du dessin, en plus d'être contraignante à utiliser.

Depth buffer

La solution généralement est un depth buffer (ou Z-buffer) A chaque pixel de la surface de dessin est associé un nombre qui représente la distance de l'objet dessiné à cet endroit. Au moment de dessiner un nouvel objet qui pourrait recouvrir ce pixel, on compare la distance du point de l'objet avec la valeur du depth buffer en ce pixel. Si cette dernière est la plus petite, on ne dessine pas à nouveau.



Illustration du fonctionnement du depth-buffer.

Ce système est généralement inclus directement dans les cartes graphiques.

Sous OpenGL, il s'appelle GL_DEPTH_BUFFER_BIT.

Fonctionnement général d'OpenGL

Machine d'état

Le fonctionnement d'OpenGL est celui d'une machine d'états. Ces états sont par exemple:

Quand un état est changé, il reste activé jusqu'à ce qu'on le modifie à nouveau, et ceci dans toutes les fonctions.

Ainsi, par exemple, pour remplacer la matrice GL_PROJECTION par l'identité, on procédera ainsi:

  1. Changer la matrice courante en GL_PROJECTION.
  2. Appeler la fonction glLoadIdentity(), qui s'appliquera sur la matrice courante.

Gardez à l'esprit qu'OpenGL est spécifié en C, qui n'est pas orienté objet!

Initialisation

On commencera par initialiser la base invariante du modèle (mode de projection et peut-être environnement). Comme OpenGL est une machiné d'état, il n'est nécessaire de faire cela qu'une seule fois, et ces fonctions ne seront donc pas appelées dans la fonction de dessin (voir ci-dessous)!

  1. Activer le depth buffer.
  2. Charger la matrice de perspective voulue dans GL_PROJECTION.
  3. Choisir la couleur de fond de la vue.
  4. Activer/paramétrer d'autres états si besoin.
  5. Choisir la matrice GL_MODELVIEW comme matrice courante pour préparer au dessin.

Rendu des images

OpenGL va stocker l'image résultante (les couleurs des pixels) des commandes envoyées dans un buffer GL_COLOR_BUFFER_BIT.

Ainsi, pour avoir une vue en temps réel du modèle, on procédera ainsi:

  1. Vider le buffer GL_COLOR_BUFFER_BIT en le remplaçant par la couleur de fond (spécifiée dans l'initialisation).
  2. Vider le depth buffer GL_DEPTH_BUFFER_BIT.
  3. Réinitialiser la matrice GL_MODELVIEW en y chargeant l'identité et multiplier par la matrice de caméra voulue.
  4. Appeler les fonctions de dessin.
  5. Envoyer le dessin à la vue.
  6. Recommencer en 1. quand la vue a besoin d'être redessinée, par exemple quand le modèle a changé.

Guide wxWidgets et OpenGL
2011-2012, Corentin Perret, Jamila Sam