GL Objects can be Pretty !

Herve.Frezza-Buet@supelec.fr

Download

The glop library provide a smart object oriented library for you openGL design. We provide documentation and examples to learn it. The rest of the page is an openGL tutorial in french, that you can also find in english as comments in the library source.
glop-1.05.tar.gz
The core library. This is what you need.
glop-gtk-1.01.tar.gz
This is the wrapper for gtkglext OpenGL with gtk.
glop-glut-1.00.tar.gz
This is the wrapper for glut.
glop-examples-1.01.tar.gz
Here are examples that can be used as a glop tutorial.

Documentation and examples

It's here.



Cours en francais



1 - Qu'est-ce qu'OpenGL ?

1.1 - Les librairies OpenGL

1.2 - Les buffers

Les buffers permettent de stocker des données par pixel, ils sont donc rectangulaires.
Les "Frame buffers"
Ils stockent des images à afficher. FRONT/BACK (double buffering) et parfois LEFT/RIGHT (stéréo-vision).
Le "Depth buffer" ou "z-buffer"
Il donne l'éloignement d'un pixel par rapport au point de vue.
Le "Accumulation buffer"
permet de surrimposer des images, pour des effets de fondu-enchainer ou de flou.
Le "Stencil buffer"
Il permet de créer des masques (ex : le cockpit dans un simulateur de vol).



2 - Démarrer... avec glut

Tout le problème est de posséder un environnement graphique, avec gestion des événements utilisateurs. Le plus standard est glut, car il est livré avec openGL. Néanmoins, on doit attendre de l'interfaçage d'openGL avec le système graphique les points suivants : Voici ce que ça donne pour glut.
BasicGlut.c
Dans les exemples, nous allons plutôt utiliser GTK, et son extension gtkglext pour openGL.



3 - Définition de la scène

La scène est principalement définie par des objets à dessiner, vus par une caméra. Cette caméra correspond au calcul de deux choses : La transformation du monde 3D en 2D peut se faire de différentes façon (perpective isométrique, normale, projection orthogonale comme les vues en dessin industriel,...) ; elle est définie par la matrice PROJECTION. La position de la caméra, elles est figée en openGL ! Une caméra regarde toujours depuis l'origine, en direction des Z négatifs (X,Y,Z est un repère direct). on a alors toujours : Comme on ne peut pas bouger la caméra, on va simuler le déplacement de la caméra en effectuant des déplacements inverse de tous les objets du monde. Il y a justement une matrice MODELVIEW en openGL qui gère les transformations spatiales que l'on peut appliquer aux objets.

3.1 - Matrice PROJECTION

Pour la perspective jolie, on définit un "Frustum" (tronc de pyramide en anglais ?).


En rapprochant le point de vue de l'origine, on augmente l'angle de l'objectif.

3.2 - Matrice MODELVIEW

Quand on demande à openGL de dessiner le point x,y,z (,w), openGL ne le place pas nécessairement à cet endroit dans l'espace 3D. En effet, avant de se placer dans le monde, ce point subit une transformation linéaire, stockée dans la matrice MODELVIEW. Il y a des fonction d'openGL pour multiplier cette matrice par des matrices de rotation, de translation, ou de redimensionnement. Ainsi, si on place l'identité dans la matrice modelview, puis qu'on la multiplie par A, puis B, puis enfin C, le point x,y,z se retrouvera en A(B(C(x,y,z))). Il subira donc d'abord la transformation C, puis B, puis A. C'est inversé ! Sachant ça, déplaçons notre caméra de sa position d'origine, en 0,0,0, regardant les Z négatifs avec Y en haut de l'écran.
La position de la caméra se définit ar 6 valeurs: 3 valeurs x,y,z de position, et 3 valeurs de rotation rx,ry,rz autour des axes X,Y,Z. Pour positionner la caméra en (x,y,z,rx,ry,rz), nous appliquons les transformations suivantes aux objets du monde. On représente à droite la vue obtenue (glop-example 1) et à droite le déplacement correspondant du monde, sachant le frustum irrémédiablement fixe (glop-example 2).

Position initiale
Translation x,y,z
Rotation autour de X
Rotation autour de Y
Rotation autour de Z


Moralité : Les rotations rx,ry,rz sont appliquées dans cet ordre, autour d'axes locaux à la caméra. Les coordonnées dans le monde 3D des vecteurs unitaires W (gauche de l'image), H (haut de l'image) et K (perpendiculaire à l'image, vers le fond) sont fournis par glop, comme si le monde était fixe avec une camera mobile.
Glop fournit également une procédure LookAt, qui permet, une fois la caméra positionnée, de fixer un point, en précisant un vecteur du monde dont l'orientation sera projetée vers le haut de l'image. Cette méthode remplace gluLookAt, car on peut par la suite récupérer le sextuplet (x,y,z,rx,ry,rz) correspondant à ce positionnement, ainsi que les vecteurs W,H,K.

3.3 - Visualisations

Pouvant positionner une caméra facilement, on peut définir des visualisations conviviales. glop-example 3 présente une visualisation "en orbite autour du centre" et une visualisation de type simulateur de vol. Elles sont très facile à calculer disposant de W,H,K et de la fonction LookAt !



4 - Animation

Le pendule vert animé est basé sur la gestion d'un glop::TimeEvent. On voit bien sur glop-example 4 l'effet d'aliasing, en "marches d'escalier".


Notez l'utilisation de la pile de matrice MODELVIEW...



5 - Brouillard

Le brouillard (glop-example 5) est obtenu en mélangeant la couleur du fond avec celle des pixels, et ce d'autant plus que leur valeur dans le z-buffer est grande. Le brouillard peut servir à donner une impression de profondeur.




6 - Objets transparents

Le principe du "blending" (to blend = se fondre) est de mélanger la couleur de l'objet à dessiner avec celle de ce qui est déjà présent dans le frame buffer. on utilise par exemple la composante alpha (RGBA) pour définir le coefficient de ce mélange. Le principe est alors le suivant (glop-example 6) :




6 - Dessin des contours

Il suffit de dessiner la scene, puis les contours un tout petit peu en avant, par rapport à l'observateur (direction calculée par openGL). Voir glop-example 7.

Comme on redessine souvent les memes choses, on a intéret à utiliser des listes pré-compilées.



7 - Textures

Une texture est une image 2D que l'on "plaque" sur une surface 3D, en la déformant. Essayez glop-example 8 et glop-example 9 avec les textures suivantes :
Lena.ppm Rock.ppm
Ce qui donne :

7.1 - Une surface de Gabor : préparation de l'exemple

glop-example 10 montre comment construire une belle surface de gabor, dont nous nous servirons pour la suite.

7.2 - Coordonnées de texture imposées

Seules les coordonnées de texture différencient glop-example 12 de glop-example 13.

7.3 - Coordonnées de texture calculées

OpenGL permet également de calculer automatiquement les coordonnées de texture d'un objet, en fonction de l'angle de sa normale avec l'observateur. On peut ainsi faire une bonne aproximation (pour pas cher) de ce que serait un reflet métallique. Essayez glop-example 14 avec les textures suivantes :
Bistro.ppm Stripes.ppm Gold.ppm
Ce qui donne :



glop-example 15 montre bien les limittes de cette "ruse" quand on cherche à faire un miroir.



8 - Lumière et matière

glop-example 11 montre que sans ombre, on ne peut donner l'impression de relief le long d'une surface. Une première solution serait de faire apparaître le maillage, avec les offset, mais on ne peut bien sur pas s'en contenter (cf. glop-example 16).



8.1 - Matière

Une source de lumière rend visible un objet parce que cet objet ré-émet la lumière qu'il reçoit de cette source. Il y a deux façons de ré-émettre de la lumière : On observe ces deux phénomènes sur glop-example 17 smooth :



La classe glop::Material encapsule les appels à openGL pour définir les propriétés du matériau dont est fait l'objet.

Nota : Il n'y a pas d'ombres portées en openGL, l'effet d'ombre est uniquement dû à des considérations d'orientations de surface.

8.2 - Paramètres communs

Dès qu'une face "tourne le dos" à la source de lumière, elle apparaît complètement noire, ce qui donne un aspect "lunaire" au dessin. OpenGL permet de définir une lumière ambiante pour y remédier, simulant la lumière indirecte provenant des objets du monde. Cette lumière ambiante est une couleur "ajoutée" systématiquement aux couleurs de dessin.

OpenGL fournit de plus un nombre restreint de "slots" de lumière (GL_LIGHT0, GL_LIGHT1...), pour chacuns desquels on peut définir des propriétés d'éclairage.

L'ensemble de ces propriétés est pris en charge par glop::LightModel.

8.3 - Sources de lumière

Définir une source de lumière revient à définir les caractéristiques de position, de couleur, etc... d'une source, dont l'effet sera d'altérer la couleur des objets suivant le matériau dont ils sont faits. C'est glop::Light, avec ses classes filles, qui prend en charge ces paramètres.

Attention ! Vu le nombre de slots limité, on ne pourra avoir qu'un nombre restreint de sources de lumière actives en meme temps, avec la contrainte qu'elles soient associées à des "slots" différents. Dans un jeu vidéo où on se ballade dans un labyrinthe, il faudra bien penser à éteindre les lumières inutiles, pour libérer le slot et le réutiliser pour une autre source. Glop permet de faire ça facilement.

L'exemple glop-example 17, illustré plus haut, montre la définition d'une source de lumière. L'exemple glop-example 18 montre comment ombrer une surface texturée, à partir d'un matériau blanc sur lequel on plaque une texture en mode GL_MODULATE.

8.4 - De beaux exemples

Voici deux beaux exemples, glop-example 19 et 20, basés sur une uilisation rationnée des listes et des surfaces GLU comment ai-je donc fait pour faire briller le cone ?




9 - Une fractale...

On a vu que la matrice GL_MODELVIEW est en fait stockée dans une pile. Or qui dit pile, dit récursivité, et qui dit récursivité, dit fractale. Appréciez la simplicité d'écriture du code correspondant à glop-example 21 :




10 - Plans de clipping

On peut définir, outre les 6 plans de clipping liés au Frustum , d'autres plans. Comme pour les lumières, il y a des "slots" (GL_CLIP_PLANE0, GL_CLIP_PLANE1, ...). C'est la classe glop::Clip qui prend ça en charge (cf. glop-example 22) :




11 - Accumulation buffer

Le buffer d'accumulation permet de surrimposer des images dessinées dans le frame buffer. Si on décale un peu ces images, on peut obtenir un effet de flou, pour faire de l'anti-aliasing par exemple. on peut également, en bougeant le point de vue mais en fixant toujours le meme point, faire un effet de profondeur de champ. La classe glop::DepthOfField prend cet effet en charge (cf. glop-example 23 et 24) :




12 - La sélection

On s'intéresse ici au problème de la sélection d'un objet à la souris (cf. glop-example 25). C'est un problème épineux, car autant openGL nous assure la projection d'un objet 3D sur l'image 2D, autant cette transformation n'est pas inversible...

La solution mise en oeuvre en OpenGL est de dessiner la scène, en plaçant avant le dessin d'un objet son "nom" (un entier"), en sommet de pile. Si le dessin est fait en mode GL_SELECTION openGL va nous rendre, pour chaque rafale de primitives de dessin consécutives ayant le meme nom, les valeus min et max de profondeur concernées.

Pour l'instant, ça ne résout pas le problème de la sélection, car on a juste par objet sa profondeur min et sa profondeur max, et ce indépendamment de la position de la souris !

En fait, une petite ruse finit par faire notre affaire. Il s'agit de multiplier (par la gauche) la matrice GL_PROJECTION de sorte à clipper seulement ce qui est autour du curseur. Ainsi, les informations de profondeurs associées aux objets dessinés ne concernent que ceux qui sont dans un faisceau étroit entre le point de vue et la zone du curseur sur la fitre de la caméra, autrement dit les objets sous le pointeur de la souris.




13 - L'effet miroir

Il s'agit d'un effet obtenu en redessinant deux fois la scène, et en jouant avec le stencil. glop-example 26 permet de décomposer les différentes étapes.




14 - Meshes

La librairie fournit également un utilitaire pour dessiner des surfaces maillées, comme illustré avec glop-example 27.




15 - Anaglyphes

Une scène peut passer en mode anaglyphe pour produire des images tridimensionnelles pouvant être vues avec des lunettes rouges et bleues, comme illustré par glop-example 28.