Dessiner des lignes
La derni�re fois nous avions parl� des rudiments de la construction de polygones avec OpenGL. OpenGL ne supporte qu'un petit nombre de primitives g�om�triques : points, lignes, polygones et surfaces d�crites par un tableau de petit quadrilat�res ou triangles.
L'id�e derri�re cette simplicit� est de laisser toute libert� au programmeur pour d�velopper des objets complexes � partir de ces objets simples. OpenGL contient un certain nombre de commandes pour contr�ler le d�tail des points, lignes et polygones.
Par exemple la taille d'un point peut-�tre sp�cifi� en pixels en utilisant glPointSize:
void glPointSize(GLfloat size)
Par d�faut la taille d'un point est de 1.0 et elle est toujours sup�rieure � z�ro. Vous remarquerez que la taille d'un point est donn�e par un nombre r�el; les portions de point et de ligne sont autoris�es. OpenGL interpr�te les portions de point en fonction du contexte de rendu. Si l'anti-cr�nelage est actif alors OpenGL modifie les pixels voisins de la ligne pour lui donner l'apparence de la largeur sp�cifi�e. L'anti-cr�nelage est une technique visant � �liminer les gros carr�s que l'on voit lorsque l'on dessine des lignes � basse r�solution. Si l'anti-cr�nelage n'est pas actif, glPointSize arrondira la taille � l'entier le plus proche.
La taille physique d'un pixel est en fait d�pendante du mat�riel. Par exemple � basse r�solution un pixel appara�t tr�s large. Respectivement � haute r�solution la ligne de largeur 1.0 (valeur par d�faut) peut �tre quasiment invisible (ph�nom�ne que l'on rencontre aussi sur certaines imprimantes) . Pour estimer la taille r�elle de vos pixels il vous faut conna�tre les dimensions d'un pixel sur votre mat�riel.
La largeur des lignes est sp�cifi�e par la fonction glLineWidth qui doit �tre appel�e avant le bloc glBegin() - glEnd()qui dessine la (les) ligne(s). Voici la syntaxe compl�te de la fonction :
void glLineWidth(GLfloat width)
Il se peut que l'impl�mentation d'OpenGL limite la largeur des lignes sans anti-cr�nelage � la valeur maximale de la largeur avec anti-cr�nelage (arrondi � l'entier le plus proche). Gardez �galement en m�moire que la largeur d'une ligne n'est pas mesur�e perpendiculairement � celle-ci, mais dans la direction des Y si la valeur absolue de la pente est inf�rieure � 1, dans la direction des X dans le cas contraire.
Ce mois-ci nous avons pr�par� une autre animation 2D simple, mais je l'esp�re utile, qui montre comment utiliser diff�rentes largeurs de lignes dans votre application OpenGL (../../common/March1998/example2.c, ../../common/March1998/Makefile). J'ai choisi un exemple tir� de la physique quantique�: une particule pi�g�e dans un double puits de potentiel. Pourquoi�? � dire vrai,..., j'ai oubli�. Quoiqu'il en soit je pense qu'il peut-�tre utile pour un �tudiant en sciences physiques ou en �cole d'ing�nieurs de voir l'int�gration de l'�quation temporelle de Shroedinger, les autres pourront tout de m�me appr�cier et contempler les ph�nom�nes inhabituel de la physique quantique. Une particule en m�canique quantique n'est pas repr�sent�e par une position et une vitesse, mais par une onde, une onde quantique (la ligne en trait plein de couleur violette sur notre animation) dont la valeur absolue au carr� repr�sente la probabilit� de pr�sence � une position donn�e (ligne blanche en pointill�s)�:
Figure 1. Simulation Quantique
Pour ce qui ont eu des cours sur les �quations diff�rentielles j'ajouterai que l'�quation est int�gr�e par une Transformation de Fourier Rapide avec s�paration d'op�rateur (FFT en anglais), cette m�thode est bien plus pr�cise et rapide que n'importe quelle m�thode born�e. Elle est applicable � des �quations de propagation non lin�aire. L'op�rateur temporel est diff�renci� en deux op�rateurs au deuxi�me ordre (et plus) en deux op�rateurs plus simple d�pendant respectivement de la fr�quence et de la position. On �value l'�volution temporelle de l'�quation en appliquant successivement les deux op�rateurs � +delta et -delta autour des valeurs des espaces de fr�quence et de position.
Le corps du programme peut-�tre utilis� pour d'autres applications. Vous pouvez remplacer ma simulation quantique par n'importe qu'elle autre fonction temporelle et voir l'�volution de votre syst�me. Vous pouvez �galement �crire une version OpenGL simplifi�e de gnuplot pour tracer fonctions et graphiques.
Si le lecteur a suivi les articles pr�c�dents sur GLUT et OpenGL, le code de ce programme appara�tra tr�s simple et facile �
comprendre (mis � part la physique quantique peut-�tre).
Il n'y a rien d'extraordinaire ici.
Dans la fonction main() nous ouvrons une seule fen�tre un mode double-buffer
(double tampon m�moire peut en �tre une traduction fran�aise),
ensuite nous d�finissons deux fonctions callback display et
idle qui prennent en charge respectivement l'affichage et
l'int�gration de l'�quation. Je vous rassure, il n'est pas n�cessaire
de comprendre tout ce qui se passe dans la fonction idle(), bien que ce soit une jolie application,
ce n'est pas indispensable pour comprendre le sujet de l'article.
Les choses nouvelles pour nous aujourd'hui sur OpenGL se trouve dans la fonction callback d'affichage (display())�:
void
display (void)
{
static char label[100];
float xtmp;
/* Clean drawing board */
glClear (GL_COLOR_BUFFER_BIT);
/* Write Footnote */
glColor3f (0.0F, 1.0F, 1.0F);
sprintf (label, "(c)Miguel Angel Sepulveda 1998");
glRasterPos2f (-1.1, -1.1);
drawString (label);
/* Draw fine grid */
glLineWidth (0.5);
glColor3f (0.5F, 0.5F, 0.5F);
glBegin (GL_LINES);
for (xtmp = -1.0F; xtmp < 1.0F; xtmp += 0.05)
{
glVertex2f (xtmp, -1.0);
glVertex2f (xtmp, 1.0);
glVertex2f (-1.0, xtmp);
glVertex2f (1.0, xtmp);
};
glEnd ();
/* Draw Outsite box */
glColor3f (0.1F, 0.80F, 0.1F);
glLineWidth (3);
glBegin (GL_LINE_LOOP);
glVertex2f (-1.0F, -1.0F);
glVertex2f (1.0F, -1.0F);
glVertex2f (1.0F, 1.0F);
glVertex2f (-1.0F, 1.0F);
glEnd ();
/* Draw Grid */
glLineWidth (1);
glColor3f (1.0F, 1.0F, 1.0F);
glBegin (GL_LINES);
for (xtmp = -0.5; xtmp < 1.0; xtmp += 0.50)
{
glVertex2f (xtmp, -1.0);
glVertex2f (xtmp, 1.0);
glVertex2f (-1.0, xtmp);
glVertex2f (1.0, xtmp);
};
glEnd ();
/* Draw Coordinate Axis */
glLineWidth (2);
glBegin (GL_LINES);
glVertex2f (-1.0, 0.0);
glVertex2f (1.0, 0.0);
glVertex2f (0.0, -1.0);
glVertex2f (0.0, 1.0);
glEnd ();
/* Axis Labels */
glColor3f (1.0F, 1.0F, 1.0F);
sprintf (label, "Position");
glRasterPos2f (0.80F, 0.025F);
drawString (label);
glColor3f (1.0F, 0.0F, 1.0F);
sprintf (label, " Quantum Probability ");
glRasterPos2f (0.025F, 0.90F);
drawString (label);
glColor3f (1.0F, 1.0F, 1.0F);
sprintf (label, " Real(Psi) ");
glRasterPos2f (0.025F, 0.85F);
drawString (label);
/* Draw Wavefunction */
psiDraw (NR_POINTS, psi, x);
/* Draw potential Function */
potentialDraw (NR_POINTS, potential, x);
glutSwapBuffers ();
};
La premi�re chose � faire est de mettre � z�ro le bit codant la couleur de la zone m�moire (buffer color bit), ce qui a pour effet d'effacer la zone d'affichage et nous donne un fond de fen�tre noir. Ensuite nous ajoutons une note en bas de la fen�tre en utilisant glRastePos et glutBitmapCharacter (drawstring n'est rien d'autre qu'une fonction englobant l'appel de plusieurs fonctions OpenGL pour dessiner une cha�ne de caract�res). Dans de futures le�ons glRastePos appara�tra de nouveau comme une fonction auxiliaire pour placer des textures. Ni OpenGl ni GLUT n'offre la possibilit� de dessiner facilement du texte dans une fen�tre. La fonction glutBitmapCharacter affiche uniquement une image 2D repr�sentant un caract�re dans la zone m�moire.
Apr�s la note il y a une s�rie de lignes de code�: le contour, la grille de fond,
les axes de coordonn�es et bien s�r la courbe courante dessin�e par
psiDraw et potentialDraw.
Avant chaque dessin de ligne, il y a une commande glLineWidth qui sp�cifie sa largeur en pixels.
La figure 1 montre la sortie sur un syst�me Xwindow (r�alis� sous Linux pour Alpha).
Pour des raisons qui me sont inconnues, le m�me programme sous Windows95 donne un affichage affreux,
il semble que l'anti-cr�nelage n'est pas bien support� par le driver OpenGL de SGI�;
il est alors difficile de diff�rencier les diff�rentes lignes qui en principe devraient
avoir des largeurs diff�rentes, les lignes de la grille � l'arri�re plan sont elles aussi mal rendues.
Ces d�fauts apparaissent en haute r�solution donc ce n'est pas un effet parasite d� � une trop basse r�solution.
Je suis heureux de proclamer qu'une fois de plus le syst�me Xwindows de Linux surpasse largement win95/NT.
Il y a deux types de lignes dessin�s par la fonction display(), le type GL_LINES qui cr�e une ligne en joignant les diff�rents points mais ne clos pas la courbe, et GL_LINE_LOOP qui ferme le contour.
Des Lignes avec anti-cr�nelage
J'ai activ� l'anti-cr�nelage pour les lignes dans la fonction callback reshape(),
void
reshape (int w, int h)
{
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (-1.2, 1.2, -1.2, 1.2);
glEnable (GL_LINE_SMOOTH); /* Enable Antialiased lines */
glEnable (GL_LINE_STIPPLE);
};
Qu'est ce que ce GL_LINE_STIPPLE�? OpenGL ne permet pas uniquement de contr�ler la largeur d'une ligne, il permet �galement de fixer un motif. En activant GL_LINE_STIPPLE nous pouvons dessiner des lignes en pointill� ou tout autre motif. La seule ligne ayant un motif se trouve dans psiDraw()�:
glLineWidth (1);
glPushAttrib (GL_LINE_BIT);
glLineStipple (3, 0xAAAA);
glBegin (GL_LINE_STRIP);
for (i = 0; i < nx; i++)
{
xs = ratio1 * (x[i] - XMIN) - 1.0;
ys = ratio2 * (psi[2 * i] - YMIN) - 1.0;
glVertex2d (xs, ys);
};
glEnd ();
glPopAttrib ();
Des Motifs pour les lignes
La fonction glLineStipple permet de sp�cifier le type de motif utilis�. Dans notre exemple, nous utilisons le motif 0xAAAAA. En binaire ce nombre se lit 0000100010001000 et OpenGL interpr�te cela en dessinant 3 points �teints 1 point allum�, 3 points �teints 1 point allum�, 3 points �teints 1 point allum�, et finalement 4 points �teints. Le motif est lu de droite � gauche car les bits de poids faible sont lus en premier. Vous remarquerez que glLineStipple prend deux param�tres, le motif qui est un nombre hexad�cimal et un entier qui sert de facteur d'�chelle � notre motif. Aussi avec un facteur de 3 notre ligne sera compos� de 9 points �teints 3 points allum�s, 9 points �teints 3 points allum�s, 9 points �teints 3 points allum�s, et finalement 12 points �teints. En jouant sur le motif et le facteur d'�chelle, on peut dessiner toute sorte de lignes compliqu�es.
Encore un d�tail�: j'ai encadr� les directives de dessin de ligne par des ordres glPushAttrib et glPopAttrib . Vous rappelez vous que dans le tout premier article sur OpenGL, je vous disais qu'OpenGL �tait une machine � �tat�? Dans nos futurs articles nous verrons plus en d�tail ces ordres push et pop, mais bri�vement, ce que nous faisons avec le premier ordre glPushAttrib(GL_LINE_BIT) c'est de mettre dans une pile la valeur courante de la variable d'�tat GL_LINE_BIT (C'est cette variable qui fixe le motif), ensuite nous modifions cette variable apr�s nos appels � glLineStipple et quand nous avons fini nous restaurons l'ancienne valeur en la d�pilant par un appel � glPopAttrib. Ce m�canisme constitue un moyen efficace de modifier les valeur des variables d'�tat d'OpenGL. Si nous n'avions pas fait cela, toutes les lignes dessin�es apr�s l'appel � glLineStippleauraient eu le m�me motif et nous aurions �t� forc� de d�clarer un motif pour chaque ligne dessin�e par notre programme. Push et Pop nous �vitent ce travail fastidieux
La prochaine fois ....
OpenGL est connu pour sa fantastique API de rendu 3D. Jusqu'� maintenant nous avons explor� quelques possibilit�s de rendu 2D, La prochaine fois nous nous int�resserons aux sc�nes 3D, comment d�finir une perspective, le syst�me de coordonn�es, les horizons, les matrices de projections.
D'ici l� amusez vous avec OpenGL...
|