Ce troisi�me volet s'inscrit directement dans la continuit� du
second, et il sera le m�me que vous utilisiez glut ou non. Nous allons
�tudier les primitives et les matrices en nous appuyant sur le tutorial
pr�c�dent. Reprenez donc le projet que nous avions commenc�,
et qui affichait un magnifique triangle blanc.
Bon, on va commencer par le dessin en OpenGL. Pour dessiner, c'est hyper simple,
et on peut faire n'importe quoi. Comme vous le savez s�rement si vous
avez l�g�rement touch� � la 3D, TOUS les objet sont
en fait une association d'�lements de base : ce sont des faces orgranis�es
dans un certain ordre dans l'espace, qui repr�sentent l'objet. Chaque
face peut �tre d�conpos�e en une s�rie de facettes
triangulaires.
Ainsi, un rectangle est en fait constitu� de deux triangles
cons�cutifs : |
 |
Ces triangles sont eux-m�me compos�s de 3 cot�s, ou 3 lignes,
et de 3 points (ou vertex) qui d�finissent les extr�mit�s
de ces segments. Ces �l�ments (points, lignes, triangles) sont
aussi appel�s primitives. OpenGL est bas� sur le principe des
primitives, c'est-�-dire que pour dessiner un objet, il faut dessiner
toutes ses primitives (ca parait logique). Et pour cela, on utilise des fonctions
tr�s simples d'utilistation et permettant des dessins tr�s pouss�s,
puisque gr�ce � ces fonctions, on peut dessiner quasiment tout.
Passons maintenant � la pratique : comment dessiner un �l�ment
primitif ? H� bien vous l'aurez s�rement devin� en lisant
le code d'exemple du triangle : on appelle glBegin()
avec comme param�tre l'�l�ment, on lui envoie les coordonn�es
des vecteurs-cl�s via glVertex() ,
et on tremine avec glEnd() . Ultra
simple, non ?
Notez que vous ne verrez rien si vous n'applez pas SwapBuffers(DC) .
Pourquoi ? Parce qu'on utilise une technique appel�e double-buffering,
qui consiste � afficher une image pendant que l'on calcule l'autre, et
lorsque celle-ci est termin�e, on �change les deux. Donc si on
enl�ve SwapBuffers(DC) , on
verra toujours un �cran vide, tandis qu'on dessinera dans un �cran
non visible. Si vous travaillez en mode simple-buffering (changez l'option dans
SetupPixelFormat() pour les windows-lover,
et dans glutInit() pour les glut-lover),
il faut remplacer SwapBuffers() par
glFlush() . Mais c'est stupide de n'utiliser
qu'un seul buffer, car la construction de l'image est alors visible, ce qui
provoque un effet de scintillement.
Voyons maintenant ce que l'on peut dessiner � part des triangles :
Param�tre transmis � glBegin |
Description |
Exemple |
GL_POINTS |
Dessine un point pour chaque vertex transmis. |
 |
GL_LINES |
Dessine des lignes. Le point n d�fini le d�but d'une ligne
et le point n+1 la fin de la ligne. |
 |
GL_LINE_STRIP |
Dessine un groupe de lignes connect�es, formant une chaine partant
du premier vertex et s'arr�tant au deriner. |
 |
GL_LINE_LOOP |
M�me chose que GL_LINE_STRIP, mais en revenant au premier vertex
� la fin. |
 |
GL_TRIANGLES |
Chaque triplet de vertex constitue un triangle |
 |
GL_TRIANGLE_STRIP |
Un triangle est d�fini pour chaque vertex pr�sent�
apr�s les deux premiers |
 |
GL_TRIANGLE_FAN |
M�me chose que GL_TRIANGLE_STRIP, sauf que le premier vertex de
chaque triangle est toujours le n�1 |
 |
GL_QUADS |
Chaque quadruplet de vertex d�finit un quadrilat�re (compos�
de 2 triangles) |
 |
GL_QUAD_STRIP |
Chaque couple de vertex pr�sent� apr�s la premi�re
paire d�finit un quadrilat�re (attention � l'ordre
des points) |
 |
GL_POLYGON |
Dessine un polygone convexe |
 |
Remarque : les lignes rouges et les num�ros sur les exemples servent
seulement � montrer comment sont dessin�s les primitives, mais
ne sont pas visibles en r�alit�.
Tout-�-l'heure, j'ai parl� de glVertex() ,
et pourtant dans mon exemple il y a �crit glVertex2d() .
Pourquoi ? H� bien parce qu'en fait il y a une multitude de fonctions
pour dessiner des sommets. En fait, on appelle toujours la fonction glVertexxy[v]() ,
o� :
- x d�finit le nombre de dimension, de 2 � 4. Lorsqu'il y a
2 dimensions, on d�finit x et y, et z est par d�faut �
0. Pourquoi aller jusqu'� 4 dimensions alors qu'on fait de la 3D ? C'est � cause des coordonn�es homog�nes.
C'est un concept math�matique qui permet d'effectuer toutes les transformations 3D n�cessaires simplement avec
des matrices 4x4 et des vecteurs 4D. En pratique, vous n'avez pas � toucher � cette 4e dimension, elle prend
normalement toujours la valeur de 1. Si vous voulez en savoir plus, allez faire un tour dans le redbook ou sur
des sites de maths.
- y d�finit le type des param�tres : 'i' pour int, 's' pour
short, 'f' pour float, et 'd' pour double.
- Lorsque l'on rajoute 'v', on passe comme param�tre un pointeur sur
les coordonn�es plut�t que les coordonn�es elles-m�me
Vous vous servirez en fait principalement de GL_TRIANGLES et GL_QUADS .
Mais l� nous allons nous servir de GL_LINES . En effet, maintenant
que vous savez dessiner les primitives (donc que vous savez tout dessiner),
nous allons �tudier les transformations de base en OpenGL. Et pour cela,
le plus simple est de dessiner un rep�re tridimensionnel. Votre fonction
Draw() doit donc �tre :
void Draw() |
{ |
|
|
|
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); |
glMatrixMode(GL_MODELVIEW); |
glBegin(GL_LINES);
|
glVertex2i(0,0);glVertex2i(0,1);
|
glVertex2i(0,0);glVertex2i(1,0);
|
glVertex2i(0,0);glVertex3i(0,0,1);
|
glEnd();
|
SwapBuffers(DC);
|
// glutSwapBuffers();
pour glut |
glutPostRedisplay(); |
// Uniquement pour GLUT |
} |
|
Mais si vous lancez le programme tel quel, vous ne verrez rien. Pourquoi ?
Parce qu'au d�part, nous sommes plac� en (0,0,0) et nous regardons
vers le point (0,0,-1). Or notre objet est situ� en (0,0,0), donc nous
ne verrons pas grand chose. Pour changer cela, il suffit d'ins�rer avant
glBegin() :
gluLookAt(3,2,3,0,0,0,0,1,0);
gluLookAt() est une fonction tr�s
simple et puissante permettant de d�finir un point de vue. Les 3 premiers
param�tres d�finissent les coordonn�es du point de vue,
les 3 suivant l'endroit o� il regarde, et les 3 derniers un vecteur qui
dit o� est le haut de la cam�ra. gluLookAt()
effectue les op�rations n�cessaires sur la matrice active afin
que le rep�re soit bien orient�. Nous devons donc activer nous-m�me
la matrice ModelView gr�ce � glMatrixMode() .
Vous pouvez maintenant lancer votre programme, et vous verrez une fen�tre
de ce genre (sans les textes, bien s�r) :
Nous allons maintenant utiliser ce rep�re pour �tudier les transformations,
au nombre de 3. D�clarez d'abord une variable globale double
a=0; et commencons.
Les prinicpes fondamentaux :
- Lorsque vous avez effectu� une transformation, tous les objets dessin�s
apr�s cette transformation sont affect�s, tant que
glLoadIdentity()
n'est pas appel� (auquel cas les objets ne seront plus transform�s)
;
- Les modifications affectent directement le rep�re de coordonn�es
et se basent sur le rep�re de coordonn�es. Le axes utilis�s
sont donc toujours les axes locaux. C'est-�-dire que si vous
avez fait une rotation autour de l'axe X, et que vous voulez faire une rotation
autour de l'axe Y, cette rotation s'effectuera autour de l'axe modifi�
par la premi�re rotation (vous verrez un exemple concret tout-�-l'heure)
;
- Un objet dessin� ne peut plus �tre modifi�.
L'homot�tie ( glScalef / glScaled ) :
Il s'agit d'un agrandissement ou une r�duction par rapport au centre
du rep�re de coordonn�es. Si vous �tes un habitu�
de 3DS, cette fonction revient � faire un Non-Uniform Scaling sur tous
les objets dessin�s apr�s. Exemple : ins�rez avant le glBegin()
de Draw() les lignes suivantes (sans oublier d'inclure math.h
pour les fonctions trigo) :
glScaled(1.-cos(a)/3.,1.+cos(a)/3.,1.+cos(a)/3.);
a+=.1;
Et vous verrez une belle animation dans ce genre :

Le rep�re est agrandi ou r�duit selon certains axes. Comme je
l'ai dit pr�c�demment, toutes les transformations qui suivent
seront bas�es sur le nouveau rep�re, tant que celui-ci n'aura
pas �t� r�initialis� par glLoadIdentity(). Donc
vous translatez un objet apr�s avoir effectu� une r�duction
par glScale(), le d�placement sera plus court, puisque le rep�re
aura diminu�.
la translation ( glTranslated / glTranslatef ) :
C'est en fait un d�placement selon le vecteur pass� en param�tre.
Le meilleur moyen de l'expliquer est de fournir un exemple. � la place
du glScaled, �crivez :
glTranslated(cos(a),0,sin(a));
Et ca donne :
Je ne le r�p�terais jamais assez : les transformations affectent
aussi le syst�me de coordonn�es. Donc si vous avez effectu�
une translation, et qu'ensuite vous vouliez faire une homot�tie, le centre
de cette homot�tie aura lui aussi �t� d�plac�.
la rotation ( glRotated / glRotatef ) :
Elle permet d'effectuer une rotation autour de n'importe quel axe. On lui passe
comme param�tre l'angle en degr� et les coordonn�es x,y
et z du vecteur de rotation. La rotation fait tout tourner, y compri le rep�re
lui-m�me (comme les autres transformations d'ailleurs). Donc si vous faites
une premi�re rotation selon un vecteur v1, et que vous voulez faire une
deuxi�me rotation selon un autre vecteur v2, n'oubliez pas que v2 a lui
aussi subi la premi�re rotation ! Un petit exemple ?
glRotated(a*180/3.14,1,1,1);
donne :
Vous pouvez bien s�r combiner les transformations. Essayez par exemple
les 3 en m�me temps, c'est assez sympa.
Et voil� ! Vous savez tout sur le dessin et les transformation et OpenGL.
Vous pouvez donc maintenant tout dessiner ! Bon, OK, c'est lourd de dessiner
une mobylette � la mano, mais en fait glu vous permet d'y arriver plus
facilement : elle fournit des primitives moins primitives, avec gluSphere, gluDisk,
gluCylinder, gluPartialDisk... Etudiez ces fonctions avec F1, et amusez-vous
� dessiner de petits objets et � tourner autour. Je vous rapelle
que le meilleur moyen d'apprendre est encore d'apprendre par soi-m�me.
Donc entra�nez-vous � manier les transformations et les primitives
jusqu'� ce que vous vous soyez bien familiaris�s avec.
La prochaine fois, nous verrons le coloriage, alors pr�parez vos crayons
de couleurs ;-)
Antoche | |