OpenGL : les couleurs

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
 


← Les bases↑ Tutoriaux OpenGL ↑Les lumières →