Au cas où vous ne l'aviez pas encore remarqué, tout ce qu'on
a fait jusqu'à présent, c'était tout blanc. Mais tout blanc
alors. Tellement qu'en fait on ne pouvait pas distinguer 2 faces entre elles,
ce qui m'a poussé jusqu'ici à dessiner des lignes plutôt
que des faces, et ca faisait un petit peu limité pour ce que peu faire
réellement la bête. Donc maintenant on va pouvoir grâce à
ce tutorial dessiner de beaux objets "solides" et bien visibles, et
pas des petits cubes à la con en mode filaire.
Reperenez donc (comme par hasard) le pogramme du tutorial précédent,
et modifiez Draw() de façon à n'avoir que le strict minimum
:
void Draw() |
{ |
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); |
glMatrixMode(GL_MODELVIEW); |
SwapBuffers(DC)
|
// glutSwapBuffers(); pour glut |
glutPostRedisplay(); |
//Uniquement pour GLUT |
} |
|
Bon là on n'a pas grand chose, mais on va dessiner un cube. Qui dit
cube dit 6 faces rectangulaires. Donc hop c'est parti :
void Draw() |
{ |
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); |
glMatrixMode(GL_MODELVIEW); |
gluLookAt(5,5,5,0,0,0,0,1,0);
|
glBegin(GL_QUADS);
|
glVertex3i(1,1,1);
glVertex3i(1,-1,1);
glVertex3i(-1,-1,1);
glVertex3i(-1,1,1);
|
//1 face |
glVertex3i(1,1,-1);
glVertex3i(1,-1,-1);
glVertex3i(-1,-1,-1);
glVertex3i(-1,1,-1);
|
//2 faces |
glVertex3i(1,1,1);
glVertex3i(1,-1,1);
glVertex3i(1,-1,-1);
glVertex3i(1,1,-1);
|
//3 faces |
glVertex3i(-1,1,1);
glVertex3i(-1,-1,1);
glVertex3i(-1,-1,-1);
glVertex3i(-1,1,-1);
|
//4 faces |
glVertex3i(-1,1,-1);
glVertex3i(-1,1,1);
glVertex3i(1,1,1);
glVertex3i(1,1,-1);
|
//5 faces |
glVertex3i(-1,-1,-1);
glVertex3i(-1,-1,1);
glVertex3i(1,-1,1);
glVertex3i(1,-1,-1);
|
//6 faces |
glEnd(); |
|
SwapBuffers(DC)
|
//glutSwapBuffers(); pour glut |
glutPostRedisplay(); |
//Uniquement pour GLUT |
} |
|
Bon ok c'est lourd mais rien ne vous interdit de tout recopier à la
main, copier/coller ca existe. Et puis de toute façon ça fait
un bon entrainement.
Sinon pour l'instant rien de nouveau, on utilise ce qu'on a vu dans les tuts
précédents. Et qu'est-ce que ça donne, ça ? Et ben
on obtient un truc dans ce genre :
|
C'est vrai qu'on a un peu de mal à faire la distinction entre l'une
ou l'autre face. C'est pour ça que j'ai choisi de mettre des couleurs
aux faces. Nous en venons donc à : "comment qu'on va peinturlurer
ce truc sans s'en foutre plein partout ?" Hé bien grâce
à cette merveilleuse fonction glColor()
! |
Comme pour glVertex() , glColor()
va de glColor3b() (R,G,B sur un octet
signé) à glColor4usv()
(R,G,B,Alpha sur un pointeur sur short non signé) en passant par glColor3d()
(R,G,B sur un double, de 0.0 à 1.0). C'est justement cette dernière
fonction que nous allons utiliser car pouvoir sélectionner l'intensité
de la couleur entre 0 et 1 est bien pratique. Pour les codages sur des valeurs
entières, tout l'intervalle disponible est utilisé (par exemple
en ub - unsigned byte -, les couleurs iront de 0 à 255).
Bien. Comment se sert-on de glColor()
maintenant ? En fait, quand on appelle cette fonction, elle va changer la couleur
des vertices (sommets) que l'on dessinera après l'appel de la
fonction, selon le principe de la machine d'état. Donc puisqu'on veut
une couleur unie par face, on va appeler glColor()
6 fois, une fois avant chaque face :
void Draw() |
{ |
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); |
glMatrixMode(GL_MODELVIEW); |
gluLookAt(5,5,5,0,0,0,0,1,0);
|
glBegin(GL_QUADS);
|
glColor3d(1,0,0);
glVertex3i(1,1,1);
glVertex3i(1,-1,1);
glVertex3i(-1,-1,1);
glVertex3i(-1,1,1);
|
//1 face |
glColor3d(0,1,0);
glVertex3i(1,1,-1);
glVertex3i(1,-1,-1);
glVertex3i(-1,-1,-1);
glVertex3i(-1,1,-1);
|
//2 faces |
glColor3d(0,0,1);
glVertex3i(1,1,1);
glVertex3i(1,-1,1);
glVertex3i(1,-1,-1);
glVertex3i(1,1,-1);
|
//3 faces |
glColor3d(0,1,1);
glVertex3i(-1,1,1);
glVertex3i(-1,-1,1);
glVertex3i(-1,-1,-1);
glVertex3i(-1,1,-1);
|
//4 faces |
glColor3d(1,1,0);
glVertex3i(-1,1,-1);
glVertex3i(-1,1,1);
glVertex3i(1,1,1);
glVertex3i(1,1,-1);
|
//5 faces |
glColor3d(1,0,1);
glVertex3i(-1,-1,-1);
glVertex3i(-1,-1,1);
glVertex3i(1,-1,1);
glVertex3i(1,-1,-1);
|
//6 faces |
glEnd(); |
|
SwapBuffers(DC)
|
//glutSwapBuffers(); pour glut |
glutPostRedisplay(); |
//Uniquement pour GLUT |
} |
|
Et hop c'est fini et voilà le résultat :
Avouez que c'est tout de même plus joli. Bon ok mes couleurs sont
à chier, mais là au moins on voit la différence entre
les faces; et puis de toute façon si vous êtes pas content
vous n'avez qu'à changer les couleurs, c'est vous qui choisissez
après tout.
Remarquez que l'on a appelé glColor()
entre glBegin() et glEnd() ,
et cela n'a posé aucun problème. Certaines fonctions le peuvent
et d'autres non, selon leur action. |
|
Ah non ! J'oubliais ! Si vous lancez comme ça, ça marchera, mais
vous verrez vraiment un cube bizarre. En effet, nous n'avons pas dit à
OpenGL de ne pas afficher les faces cachées. Il va donc tout dessiner
dans l'ordre où on lui a donné les faces, sans se préoccuper
s'il y avait quelque chose devant ou pas. Il faut donc activer le test de profondeur.
Pour cela, tapez
glEnable(GL_DEPTH_TEST);
dans InitGL() . Et rajoutez aussi
glEnable(GL_COLOR_MATERIAL);
tant que vous y êtes, pour être bien sûr que le coloriage
est activé.
Mais au fait, quand on regarde un cube tout blanc (ou un lapin ou un kangourou
si vous préférez) dans la réalité, on voit quand
même bien les arêtes, même si les faces sont immaculées.
Ben oui, parce qu'en général, les faces ne sont pas éclairées
de la même façon. Or ici on utilise l'éclairage par défaut
tout à fait pourri je le conçoit, mais qui au moins nous permet
d'y voir quelque chose. C'est un éclairage dit "ambient", c'est-à-dire
que la lumière est exactement la même en tout point (un peu genre
lumière "ambiente" dans 3DS). C'est pour ça que toutes
les faces ont exactement la même couleur.
Mais on ne va pas aborder les lumières maintenant, plutôt dans
le prochain tutorial. Pourquoi je vous parle de ça alors ? D'abord pour
que vous compreniez mieux (si qq chose vous tracasse encore, n'hésitez
pas à me le dire), et ensuite parce que glColor()
n'est pas sans liens avec l'éclairage. En effet, comme dans 3DS, chaque
objet a plusieurs couleurs : couleur ambiente (celle qu'a l'objet lorsqu'aucune
lumière ne le frappe), couleur diffuse (couleur que renvoie l'objet
lorsqu'il est éclairé), couleur spéculaire (couleur
que renvoie l'objet lorsqu'il est frappé directement par la lumière)
et couleur d'émission (couleur qu'émet l'objet, comme un
trux fluorescent par exemple). Il faut bien faire la différence entre
diffuse et spéculaire : une sphère métallique aura par
exemple une couleur diffuse grise, et une couleur spéculaire très
blanche, qui correspondra au point très lumineux à l'endroit où
la lumière vient se réfléchir. Une image illustre mieux
qu'un long discours :
|
Ici la couleur ambiente est bleutée. Elle ne se voit pas beaucoup,
mais elle est tout de même présente. La couleur diffuse est
grise, mais on voit que l'ambiente influe aussi dessus, ce qui la rend gris-bleu.
Quand à la spéculaire, elle est carrément blanche et
l'ambiente n'a quasiment aucune influence dessus. Cette image a été
réalisée avec 3DS, mais vous verrez qu'on peut en faire d'aussi
belles avec OpenGL dans le prochain tutorial. |
Revenons à nos moutons. Ici nous modifions la couleur par défaut,
qui est GL_AMBIENT_AND_DIFFUSE . Nous
ne changeons donc pas la couleur spéculaire. Pour choisir la couleur
modifiée par glColor() , il
faut appeler d'abord glColorMaterial(face,mode) .
face désigne les
faces qui seront affectées : GL_FRONT
pour les face avant, GL_BACK pour
les faces arrières et GL_FRONT_AND_BACK
pour les 2. Comme nous n'avons pas encore vu l'orientation des faces, choisissez
GL_FRONT_AND_BACK (défaut).
mode définit lui
la couleur à modifier : GL_EMISSION ,
GL_AMBIENT ,
GL_DIFFUSE , GL_SPECULAR ,
et GL_AMBIENT_AND_DIFFUSE (défaut).
Notez que cette fonction ne peut pas être appelée entre
glBegin() et glEnd()
(c'est une source fréquente d'erreurs).
Essayez avant le glBegin() de sélectionner
une couleur différente et vous verrez qu'en fait le résultat est
le même quel que soit la couleur choisie. C'est parce que nous sommes
toujours avec l'éclairage par défaut, qui permet surtout de découvrir
et d'apprendre les fonctions basiques de dessin en étant sûr de
voir qq chose. Nous devrons donc étudier en détail l'éclairage
dans un prochain tutorial.
Mais il a autre chose que je n'ai pas complètement éclairci.
En effet, si vous êtes attentif, vous avez peut-être remarqué
que j'ai dit plus haut que glColor()
définissait la couleur des sommets qui allaient être dessinés
après. Donc a priori, on peut essayer de définir des couleurs
différentes pour chaque sommet d'une face. Qu'est-ce donc que ça
va donner, ça ? Eh ben le meilleur moyen de le savoir, c'est tout simplement
d'essayer...
void Draw() |
{ |
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT); |
glMatrixMode(GL_MODELVIEW); |
gluLookAt(5,5,5,0,0,0,0,1,0);
|
glBegin(GL_QUADS);
|
glColor3d(1,0,0);glVertex3i(1,1,1);
glColor3d(0,1,0);glVertex3i(1,-1,1);
glColor3d(0,0,1);glVertex3i(-1,-1,1);
glColor3d(1,0,1);glVertex3i(-1,1,1);
|
//1 face |
glColor3d(1,1,0);glVertex3i(1,1,-1);
glColor3d(0,1,1);glVertex3i(1,-1,-1);
glColor3d(1,0,0);glVertex3i(-1,-1,-1);
glColor3d(1,1,1);glVertex3i(-1,1,-1);
|
//2 faces |
glColor3d(1,0,0);glVertex3i(1,1,1);
glColor3d(0,1,0);glVertex3i(1,-1,1);
glColor3d(0,1,1);glVertex3i(1,-1,-1);
glColor3d(1,1,0);glVertex3i(1,1,-1);
|
//3 faces |
glColor3d(1,0,1);glVertex3i(-1,1,1);
glColor3d(0,0,1);glVertex3i(-1,-1,1);
glColor3d(1,0,0);glVertex3i(-1,-1,-1);
glColor3d(1,1,1);glVertex3i(-1,1,-1);
|
//4 faces |
glColor3d(1,1,1);glVertex3i(-1,1,-1);
glColor3d(1,0,1);glVertex3i(-1,1,1);
glColor3d(1,0,0);glVertex3i(1,1,1);
glColor3d(1,1,0);glVertex3i(1,1,-1);
|
//5 faces |
glColor3d(1,0,0);glVertex3i(-1,-1,-1);
glColor3d(0,0,1);glVertex3i(-1,-1,1);
glColor3d(0,1,0);glVertex3i(1,-1,1);
glColor3d(0,1,1);glVertex3i(1,-1,-1);
|
//6 faces |
glEnd(); |
|
SwapBuffers(DC)
|
//glutSwapBuffers(); pour glut |
glutPostRedisplay(); |
//Uniquement pour GLUT |
} |
|
Ok c'est peut-être un peu lourd, mais au moins c'est clair : chaque
sommet a une couleur différente (j'ai mis les sommets (1,1,1) et
(-1,-1,-1) tous les deux en rouge pour ne pas utiliser la couleur noire).
Et voilà ce que ça donne. Comme vous pouvez le voir, la couleur
d'un point sur la face est interpolée entre chaque sommet, et ça
donne des résultats plutôt sympas. On voit un peu mieux les
arêtes, on a même l'impression qu'elles sont éclairées,
mais en fait ce n'est qu'une illusion. |
|
Grâce à ce tutorial en tout cas nous avons découvert que
:
- On peut modifier la couleur active avec
glColor();
- On peut choisir la couleur active avec
glColorMaterial();
- On peut activer certaines options (test de profondeur, coloriage...) grâce
à
glEnable() - utilisez l'aide
de votre compilateur pour découvrir tout ce que cette fonction recèle
;
- Un objet est composé de différentes couleurs : émission,
ambiente, diffuse et spéculaire.
- Une face peut avoir des sommets de couleurs différentes
Un "truc" de graphiste (je suis pas graphiste mais bon c'est toujours
un conseil) : évitez le plus possible de modifier la couleur ambiente
d'un objet car elle affecte aussi les autres couleurs, et donc demande des réglages
très subtils, voire impossibles. Laissez-la donc noire et utilisez plutôt
les couleurs diffuse et spéculaire qui sont plus pratiques et rapides
à régler.
Antoche | |