OpenGL est une interface de programmation graphique qui permet de visualiser une scène 2D ou 3D, fixe ou animée. Les objets de cette scène peuvent etre composés de points, de lignes, de polygones, de quadriques, de nurbs. Ils possèdent des attributs graphiques : paramètres de réflexion, couleur, texture.
L'éclairage de la scène est réalisé par des lumières de différents types (spot, lumière à l'infini).
La bibliothèque OpenGL a été créée par Silicon
Graphics et bénéficie dès 1992 sur ces machines de l'accélération matérielle. Une
implémentation libre de droits d'OpenGL a été écrite par Brian
Paul : Mesa. Son code source est
accessible.
OpenGL est indépendante de la plate-forme matérielle, et du système d'exploitation. Du fait de son ouverture, de sa souplesse d'utilisation et de sa disponibilité sur des plate-formes variées, OpenGL est utilisée dans de nombreuses applications scientifiques, industrielles ou artistiques 3D et certaines applications 2D vectorielles. Cette bibliothèque est également populaire dans l'industrie du jeu vidéo où elle est en rivalité avec Direct3D (sous Microsoft Windows).
La spécification OpenGL a été sous la responsabilité d'un consortium appelé OpenGL Architecture Review Board (ARB), de 1992 à 2006. L'ARB se compose d'entreprises ayant un intérêt pour la création d'une API cohérente et largement disponible. Selon le site officiel d'OpenGL, 3Dlabs, Apple, ATI, Dell, Evans & Sutherland, Hewlett-Packard, IBM, Intel, Matrox, nVidia, SGI et Sun Microsystems font partie des membres votants (juin 2002). Microsoft, l'un des membres fondateurs, s'est retiré en mars 2003.
En 2006, l'ARB a transféré le contrôle de la spécification OpenGL au Khronos Group, qui s'occupait déjà de différentes spécifications OpenGL pour les systèmes embarqués et les consoles de jeux vidéo dont OpenGL ES.
En 2007, OpenGL 3.0 introduit de nouvelles caractéristiques, parmi lesquelles :
- la mise à jour du langage de shading GLSL 1.30
- le rendu conditionnel
- un meilleur accès aux Buffer Objects
- un tampon chromatique (framebuffer) dont les pixels sont codés en nombres réels
- des tampons de rendu (renderbuffer)
- le feedback de transformation (transform feedback)
- les objets Tableaux de sommets (vertex-array objects)
- une réflexion en profondeur sur les parties obsolètes du modèle.
Enfin, OpenGL 3.1 introduit également de nouvelles caractéristiques. Citons :
- la mise à jour du langage de shading GLSL 1.40
- le rendu instancié
- les objets tampon texture (texture buffer objects)
En terme de compatibilité, la version 3.0 supporte toutes les versions antérieures, tandis que dans la version 3.1, les fonctions devenues obsolètes ne sont plus accessibles qu'à travers l'extension GL_ARB_compatibility.
Une version d'OpenGL nommée OpenGL ES a été conçue spécifiquement pour les applications embarquées (téléphones portables, agenda de poche...).
Trois versions
d'OpenGL ES sont sorties :
- OpenGL ES 1.0, dérivée d'OpenGL 1.3, fut conçut pour le rendu 3D logiciel. Il s'agit donc en fait d'une spécification de moteur de rendu 3D logiciel multiplate-forme.
- OpenGL ES 1.1, dérivée d'OpenGL 1.5, est sortie par la suite pour adapter la norme à l'arrivée de l'accélération matérielle sur ces plate-formes en ajoutant/étendant certaines fonctionnalités.
- OpenGL ES 2.0, dérivée d'OpenGL 2.0, est arrivée peu avant les prototypes de processeurs embarqués haut de gamme. Elle s'allège de la plupart des ses fonctions précédentes dont toute son API de rendu à cheminement (pipeline) fixe pour laisser la place à un système de shaders basé sur une variation de GLSL.
C 'est le principe général d'OpenGL, en particulier lorsqu'on utilise le pipeline graphique fixe : On positionne un état
interne, et sa valeur est ensuite utilisée comme valeur courante : les
ordres de dessin suivants utiliseront cette valeur-ci. Si ce n'est pas clair
pour vous, prenons un exemple : Pour dessiner un sommet rouge, on positionne
d'abord l'état correspondant à la couleur courante à la
valeur rouge, et ensuite on demande le dessin d'un sommet. Tous les sommets
qui seront ensuite dessinés seront rouges, tant que l'on n'a pas modifié
la couleur courante.
Et ce principe que nous avons illustré à partir de l'état
"couleur" s'applique à tous les états, comme l'épaisseur
des traits, la transformation courante, l'éclairage, etc.
De nombreux états correspondent à des modes, et sont activés ou désactivés à l'aide des commandes glEnable(...) et glDisable(...).
Pour interroger la valeur d'un état, on utilise par exemple la commande glGet*(...) sous une de ses variantes.
Il est également possible de sauvegarder un ensemble de variables d'états avec la commande glPushAttrib(...), et de le restaurer ensuite avec la commande glPopAttrib().
Voici le pipeline complet :

Intéressons-nous au devenir des données géométriques :
[Données]->[Evaluateurs]->[Opérations sur les sommets et assemblage de
primitives]->[Discrétisation]->[Opérations sur les fragments]->[Image]
- Les Evaluateurs produisent une description des objets à
l'aide de sommets et de facettes.
- Les Opérations sur les sommets sont les transformations
spatiales (rotations et translations) qui sont appliquées aux sommets, les calculs d'éclairage et de coordonnées de texture.
- L' assemblage de primitive regroupe les opérations de
clipping : élimination des primitives qui sont en dehors
d'un certain espace et de transformation de projection .
- La discrétisation (Rasterization) est la transformation des primitives
géométriques en fragments correspondant aux pixels de l'image.
- Les Opérations sur les fragments vont calculer chaque
pixel de l'image en combinants les fragments qui se trouvent à l'emplacement du pixel. On
trouve entre autres la gestion de la transparence, et le Z-buffer (pour l'élimination des
surfaces cachées).
OpenGL ne gère pas les opérations de bas niveau. Pour celà, on utilise la programmation de shaders, ou la bibliothèque GLU :
- GLU : OpenGL Utility Library contient les routines de bas niveau pour gérer les matrices
de transformation et de projection, la facettisation des polygones et le rendu de surface.
certaines des fonctions glu sont maintenant atteintes d'obsolescence.
OpenGL ne gère pas non plus le fenêtrage, et les entrées/sorties avec le clavier ou la souris. Pour celà, on utilise une bibliothèque complémentaire :
- GLX pour X Windows (fonctions ayant pour préfixe glX) et de WGL
pour Microsoft Windows (fonctions ayant pour préfixe wgl) ou mieux,
- GLUT : OpenGL Utility Toolkit, une boite à outils indépendante du système de
fenêtrage, écrite par Mark Kilgard pour simplifier la tâche d'utiliser des systèmes
différents (fonctions ayant pour préfixe glut).
la version la plus à jour est l'implémentation open-source de l'interface GLUT. Elle s'appelle freeGLUT.
- D'autres toolkits complets existent, comme Qt, ou les MFC.
OpenGL ne propose pas de commandes de haut niveau pour décrire la manière dont les objets 3D sont organisés dans la scène. On pourra faire appel à un gestionnaire de scène, comme Open inventor, ou Ogre 3D.
Les couleurs sont définies en OpenGL de deux manières :
- Couleurs indexées : une table de couleurs permet d'accéder à 2^n couleurs (par exemple 2^8 = 256), et on se réfère
au numéro de la couleur (son index). C'est un mode qui est
intéressant lorsque l'écran est limité dans le nombre de couleurs qu'il peut afficher simultanément.
- Couleurs RVBA : une couleur est définie par son intensité
sur 3 composantes Rouge, Vert, Bleu. La quatrième composante est appelée
canal Alpha, et code l'opacité.
La couleur d'un objet est spécifiée par l'appel à glColor(...).
Les commandes OpenGL commencent par le préfixe gl, et la première lettre de chaque mot est en majuscules.
Le suffixe est composé d'un chiffre qui indique le nombre d'arguments, et d'une lettre qui indique le type des arguments.
De plus, certaines commandes peuvent se terminer par la lettre v, pour indiquer l'emploi d'un tableau en paramètre.
OpenGL permet de manipuler les types de données suivants :
Suffixe |
Type |
Nom OpenGL |
b |
entier 8 bits |
GLbyte |
s |
entier 16 bits |
GLshort |
i |
entier 32 bits |
GLint, GLsizei |
f |
virgule flottante 32 bits |
GLfloat, GLclampf |
d |
virgule flottante 64 bits |
GLdouble, GLclampd |
ub |
entier non signé 8 bits |
GLubyte, GLboolean |
us |
entier non signé 16 bits |
GLushort |
ui |
entier non signé 32 bits |
GLuint, GLenum, GLbitfield |
Déclaration
- glBegin(GLenum mode) ouvre la déclaration
des sommets de la primitive
- glEnd(void) termine cette déclaration
- Il y a dix types de primitives différents, qui correspondent à des points,
des lignes, des triangles, des quadrilatères, et des polygones convexes.
GL_POINTS |
|
|
GL_LINES |
GL_LINE_STRIP |
GL_LINE_LOOP |
GL_TRIANGLES |
GL_TRIANGLE_STRIP |
GL_TRIANGLE_FAN |
GL_QUADS |
GL_QUAD_STRIP |
GL_POLYGON |
Affichage des points
La
commande glPointSize(GLfloat taille) permet de définir la taille en pixels des points. Sa valeur par défaut est 1.0.
Affichage des lignes
Sous OpenGL, les lignes désignent des segments de droites. La
commande glLineWidth(GLfloat largeur) permet de définir la largeur en pixels des lignes. Sa valeur par défaut est 1.0.
Pour dessiner des lignes en pointillés, on utilise la commande glLineStipple(GLint facteur, GLushort motif) pour définir le motif des pointillés, et on active le mode pointillés avec glEnable(GL_LINE_STIPPLE).
Le motif est codé sur 16 bits, dans lequel un 0 ne trace rien, et un 1 dessine un point. Le facteur est un entier entre 1 et 256, qui multiplie chaque sous-série de 0 ou de 1 consécutifs.
Les pointillés peuvent être testés à l'aide du programme lines.c.
Affichage des polygones
Un polygone est une zone délimitée par une succession fermée de segments de droites. Les polygones admis par OpenGL sont des polygones simples convexes : ils sont plans, leurs arêtes ne doivent pas se couper, et ils ne peuvent pas contenir de trous ni d'angles rentrants.
Remplissage : mode plein, ligne ou point
Les polygones sont généralement affichés par remplissage de tous les pixels qui sont à l'intérieur du contour. On peut également n'afficher que les arêtes ou les sommets, en appelant la fonction glPolygonMode(GLenum face, GLenum mode).
Le paramètre face indique quelle face des polygones sont concernées : GL_FRONT, GL_BACK, ou GL_FRONT_AND_BACK. Le paramètre mode prend les valeurs GL_POINT, GL_LINE ou GL_FILL.
Face avant ou arrière ?
Par convention, la face avant d'un polygone est celle qui s'affiche à l'écran dans le sens contraire des aiguilles d'une montre. (Counter ClockWise). La fonction glFrontFace(GLenum mode) permet de changer de mode, pour choisir le sens horaire (ClockWise). On emploiera alors la valeur GL_CW pour le paramètre mode, qui vaut GL_CCW par défaut.
OpenGL permet de choisir si à la fois les faces avant et arrière sont affichées, ou si certaines sont élimiées. C'est le mécanisme du Culling.
Lorsqu'il est activé avec glEnable(GL_CULL_FACE), la fonction glCullFace(GLenum mode) permet déterminer les faces qui sont éliminées : GL_FRONT, GL_BACK, ou GL_FRONT_AND_BACK.
On a la garantie que les instructions OpenGL sont effectivement effectuées en appelant une fonction de finalisation du rendu.
glFlush() force les commandes OpenGL à s'exécuter. La commande glFinish() fait la même chose, et de plus, elle attend que l'exécution des commandes soit terminée pour retourner.
La commande glutSwapBuffers(void), en plus d'échanger les buffers d'image, force également les commandes OpenGL à s'exécuter.
Pour la compilation sous linux, copiez le Makefile et tapez make
Pour la compilation sous Windows, sous Dev-Cpp , utilisez les projets hello.zip et double.zip.
- Examinez et compilez le programme hello.c
Comprenez l'utilité des différentes procédures.
- faites de même pour double.c.
Exemple
Partez du programme hello.c.
- Lisez-le attentivement, et comprenez la définition et les effets de chacune des fonctions OpenGL qui le composent.
C'est LE programme de base. Pour construire des scènes complexes, il est important que les bases soient solides.
- Modifiez-le pour afficher un triangle dont les couleurs des 3 sommets sont Rouge, Vert, et Bleu.
- Reprenez les deux points précédents à partir du programme double.c.
Les fonctions de gestion d'une fenêtre
- glutInit(int * argc, char **argv) initialise GLUT et traite les arguments de la ligne de commande.
- glutInitDisplayMode(unsigned int mode) permet de choisir entre couleurs RVB et couleurs indexées, et de déclarer les buffers utilisés.
- glutInitWindowPosition(int x, int y) spécifie la localisation dans l'écran du coin haut gauche de la fenêtre.
- glutInitWindowSize(ind width, int size) spécifie la taille en pixels de la fenêtre.
- int glutCreateWindow(char * string) crée une fenêtre contenant un contexte OpenGL et renvoie l'identificateur de la fenêtre.
La fenêtre ne sera affichée que lors du premier glutMainLoop()
La fonction d'affichage
- glutDisplayFunc(void (*func)(void)) spécifie la fonction à appeler pour l'affichage
- glutPostRedisplay(void) permet de forcer le réaffichage de la fenêtre.
Lancement de la boucle d'événements
- Attente d'un événement
- Traitement de l'événement reçu
- Retour en 1.
- glutMainLoop(void) lance la boucle principale qui tourne pendant tout le programme, attend et appelle les fonctions spécifiques pour traiter les événements.
Traitement des événements
- glutReshapeFunc(void (*func)(int w, int h)) spécifie la fonction à appeler lorsque la fenêtre est retaillée.
- glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)) spécifie la fonction à appeler lorsqu'une touche est pressée
- glutSpecialFunc(void (*func)(int key, int x, int y)) spécifie la fonction à appeler lorsqu'une touche spéciale (caractère non-ASCII) est pressée : les flèches, les touches de fonction, etc...
- glutMouseFunc(void (*func)(int button, int state, int x, int y)) spécifie la fonction à appeler lorsqu'un bouton de la souris est pressé.
- glutMotionFunc(void (*func)(int x, int y)) spécifie la fonction à appeler lorsque la souris est déplacée tout en gardant un bouton appuyé.
Exécution en tâche de fond
- glutIdleFunc(void (*func)(void)) spécifie la fonction à appeler lorsqu'il n'y a pas d'autre événement.
Dessin d'objets Tridimensionnels
GLUT possède des routines pour afficher les objets suivants :
- cone
- cube
- tetraèdre
- octaèdre
- icosaèdre
- dodécaèdre
- sphère
- tore
- théière (!)
Animation
Une animation peut se réaliser simplement en utilisant la technique du double buffer : montrer à l'écran une image correspondant à une première zone mémoire (buffer) et dessiner les objets dans une deuxième zone mémoire qui n'est pas encore à l'écran, et qui sera affiché lorsque la scène entière y sera calculée, et à une fréquence régulière. L'échange des buffers peut se faire par la commande glutSwapBuffers(void).
Exercices
- Créez une scène dans laquelle un triangle vert se déplace de gauche à droite le long d'une ligne pointillée horizontale blanche. Lorsqu'il atteint le bord droit de l'écran, il repart à partir du bord gauche.
- Etudiez si le temps d'affichage entre deux images successives varie en fonction de la taille de la fenêtre. Pour cela, utilisez glutGet(GLUT_ELAPSED_TIME).
- Implémentez l'utilisation des flèches haut et bas pour ajouter un déplacement vertical au triangle.
OpenGL utilise la technique du Z buffer (ou buffer de profondeur) pour éviter l'affichage des surfaces cachées.
On ne voit d'un objet que les parties qui sont devant et pas celles qui se trouvent derrière. Pour chaque élément de la scène la contribution qu'il aurait à l'image s'il était visible est calculée, et est stockée dans le Z buffer avec la distance de cet élément à la caméra (c'est cette distance qui est la profondeur).
Chaque pixel de l'image garde donc la couleur de l'élément qui est le plus proche de la caméra. Dans le cas plus complexe d'un objet transparent, il y a une combinaison des couleurs de plusieurs éléments.
Fonctions utilisées
- Dans main(): glutInitDisplayMode(GLUT_DEPTH | ... )
- Dans init(): glEnable(GL_DEPTH_TEST)
- Dans display(): glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) Avant l'affichage d'une scène.
17 décembre 2012