I. Contributions

Nous recherchons toujours des traducteurs pour finir ce projet de traduction des articles de NeHe. Votre aide serait appréciée ! Vous êtes intéressé ? Alors contactez-nous à l'adresse suivante : nehe@redaction-developpez.com.

II. Tutoriel

Nous réutilisons le code de la leçon 7. Nous y adjoindrons sept variables et modifierons la texture pour faire dans la diversité. :)

 
Sélectionnez
#include <windows.h>                 // Fichier d'entête pour Windows
#include <stdio.h>                     // Fichier d'entête pour les entrées/sorties 
#include <gl\gl.h>                     // Fichier d'entête pour la bibliothèque OpenGL32 
#include <gl\glu.h>                     // Fichier d'entête pour la bibliothèque GLu32 
#include <gl\glaux.h>                 // Fichier d'entête pour la bibliothèque GLaux 
HDC        hDC=NULL;                 // Contexte de périphérique privé GDI 
HGLRC        hRC=NULL;                 // Contexte de rendu permanent 
HWND        hWnd=NULL;                 // Contient notre ID de la fenêtre 
HINSTANCE    hInstance;                 // Contient l'instance de l'application 
bool    keys[256];                     // Tableau utilisé pour la fonction du clavier 
bool    active=TRUE;                     // Drapeau de fenêtre active définie à TRUE par défaut
bool    fullscreen=TRUE;                 // Drapeau de plein écran défini à plein écran par défaut
bool    light;                         // Éclairage allumé/éteint
bool    lp;                         // Touche L appuyée ?    
bool    fp;                         // Touche F appuyée ?
bool sp;                         // Barre d'espace appuyée ?    (AJOUT)
int    part1;                         // Début du disque    (AJOUT)
int    part2;                         // Fin du disque    (AJOUT)
int    p1=0;                         // Incrémentation 1        (AJOUT)
int    p2=1;                         // Incrémentation 2        (AJOUT)
GLfloat    xrot;                         // Rotation selon X
GLfloat    yrot;                         // Rotation selon Y
GLfloat xspeed;                         // Vitesse de rotation selon X 
GLfloat yspeed;                         // Vitesse de rotation selon Y 
GLfloat    z=-5.0f;                 // Profondeur dans l'écran
GLUquadricObj *quadratic;                 // Stockage pour nos objets quadriques (AJOUT)
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };     // Valeurs de lumière ambiante
GLfloat LightDiffuse[]=     { 1.0f, 1.0f, 1.0f, 1.0f };     // Valeurs de lumière diffuse
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };     // Position de la lumière
GLuint    filter;                         // Filtre à utiliser
GLuint    texture[3];                     // Espace de stockage des 3 textures
GLuint object=0;                     // Objet à dessiner    (AJOUT)
LRESULT    CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);     // Déclaration de WndProc

Ceci fait, allons jusqu'à la fonction InitGL(), nous allons ajouter trois variables pour initialiser notre quadrique. Ajoutez ces trois lignes après avoir activé light1, mais avant de retourner true. La première ligne du code initialise la quadrique et crée un pointeur sur la zone mémoire qui le contiendra. S'il ne peut pas être créé, et la zone est non allouée, le pointeur prend la valeur 0. La seconde ligne de code crée un lissage normal sur la quadrique, pour obtenir un bon éclairage. D'autres valeurs possibles sont GLU_NONE et GLU_FLAT. En dernier, activons-le mapping de texture sur notre quadrique. Le mapping de texture est le genre de chose qui ne fait jamais ce que vous aviez explicitement prévu en créant la texture comme vous avez pu le constater avec la texture de la caisse.

 
Sélectionnez
    quadratic=gluNewQuadric();             // Crée un pointeur sur l'objet quadrque (AJOUT)
    gluQuadricNormals(quadratic, GLU_SMOOTH);     // Crée les normales de lissage (AJOUT)
    gluQuadricTexture(quadratic, GL_TRUE);         // Crée les coordonnées de texture (AJOUT)

Maintenant, j'ai décidé de garder ce cube dans ce tutoriel pour que vous puissiez voir comment les textures sont dessinées sur l'objet quadratique. J'ai décidé de bouger le cube à l'intérieur de sa propre fonction donc lorsque nous écrirons la fonction de dessin, il apparaîtra plus clair. Tout le monde devrait reconnaître ce code. =P

 
Sélectionnez
GLvoid glDrawCube()                     // Dessine un cube
{
        glBegin(GL_QUADS);             // Débute le dessin des carrés
         // Face avant
        glNormal3f( 0.0f, 0.0f, 1.0f);         // Normale face avant
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // Bas gauche de la texture et du carré

        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // Bas droit de la texture et du carré 
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // Haut droit de la texture et du carré 
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // Haut gauche de la texture et du carré 
         // Face arrière
        glNormal3f( 0.0f, 0.0f,-1.0f);         // Normale face arrière
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // Bas droit de la texture et du carré 
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // Haut droit de la texture et du carré 
        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // Haut gauche de la texture et du carré 
        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // Bas gauche de la texture et du carré 
         // Face de dessus
        glNormal3f( 0.0f, 1.0f, 0.0f);         // Normale face de dessus 
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // Haut gauche de la texture et du carré 
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // Bas gauche de la texture et du carré 
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // Bas droit de la texture et du carré 
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // Haut droit de la texture et du carré 
         // Face de dessous 
        glNormal3f( 0.0f,-1.0f, 0.0f);         // Normale face de dessous 
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // Haut droit de la texture et du carré 
        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // haut gauche de la texture et du carré 
        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // Haut gauche de la texture et du carré 
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // Bas droit de la texture et du carré 
         // Face droite 
        glNormal3f( 1.0f, 0.0f, 0.0f);         // Normale face droite 
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);     // Bas droit de la texture et du carré 
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);     // Hait droit de la texture et du carré 
        glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);     // Haut gauche de la texture et du carré 
        glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);     // Bas gauche de la texture et du carré 
         // Face gauche 
        glNormal3f(-1.0f, 0.0f, 0.0f);         // Normale face gauche 
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);     // Bas gauche de la texture et du carré 
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);     // Bas droit de la texture et du carré 
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);     // Haut droit de la texture et du carré 
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);     // Haut gauche de la texture et du carré 
    glEnd();                     // Dessin des carrés terminé 
}

La suite concerne la fonction DrawGLScene, ici j'ai juste écrit une simple déclaration pour dessiner les différents objets. J'ai également utilisé une variable statique (une variable locale qui garde sa valeur entre chaque appel) pour un effet sympathique lors de la construction du disque partiel. Je réécrirai en entier la fonction DrawGLScene pour plus de clarté.

Vous remarquez que lorsque je parle des paramètres utilisés, je ne parle pas du premier paramètre (quadratique). Ce paramètre est utilisé pour tous les objets que nous dessinons à côté du cube, donc je l'ignore en parlant des paramètres.

 
Sélectionnez
int DrawGLScene(GLvoid)                         // C'est ici que nous dessinons tout
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     // Efface l'écran et le tampon de profondeur
    glLoadIdentity();                     // Réinitialise la vue
    glTranslatef(0.0f,0.0f,z);                 // Effectue une translation selon l'axe des Z 
    glRotatef(xrot,1.0f,0.0f,0.0f);                 // Effectue une rotation selon l'axe X
    glRotatef(yrot,0.0f,1.0f,0.0f);                 // Effectue une rotation selon l'axe des Y
    glBindTexture(GL_TEXTURE_2D, texture[filter]);         // Sélectionne une texture filtrée
     // Cette section de code est nouvelle (AJOUT)
    switch(object)                         // Vérifie l'objet à dessiner
    {
    case 0:                             // On dessine l'objet 1
        glDrawCube();                     // On dessine notre cube
        break;                         // Terminé

Le second objet que nous créons sera un cylindre. Le premier paramètre (1.0f) est le rayon du cylindre à la base (bottom). Le second paramètre (1.0f) est le rayon du cylindre au sommet. Le troisième paramètre (3.0f) est la hauteur du cylindre (sa longueur). Le quatrième paramètre (32) est le nombre de subdivisions autour de l'axe Z, et finalement, le cinquième paramètre (32) est le nombre de subdivisions le long de l'axe des Z. Plus il y a de subdivisions, plus l'objet est détaillé. En augmentant le nombre de subdivisions, vous ajoutez des polygones à l'objet. Donc vous sacrifiez à la vitesse d'exécution pour avoir une meilleure qualité visuelle. La plupart du temps, on arrive à trouver un juste milieu satisfaisant.

 
Sélectionnez
    case 1:                             // On dessine l'objet 2
        glTranslatef(0.0f,0.0f,-1.5f);             // On centre le cylindre
        gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);     // On dessine notre cylindre
        break;                         // Terminé

Le troisième objet que nous créons sera inspiré d'un disque compact (CD). Le premier paramètre (0.5f) est le rayon intérieur du disque. Cette valeur peut être zéro, signifiant qu'il n'y aura pas de trou au milieu du disque. Plus grand sera ce rayon intérieur, plus grand sera le trou du milieu du disque. Le second paramètre (1.5f) est le rayon extérieur. Cette valeur devra être plus grande que celui du trou central. Si vous donnez à ce paramètre une valeur proche du rayon intérieur, votre CD ressemblera plus à un anneau. Si le rayon « extérieur » est beaucoup plus grand que le rayon « intérieur », ce sera plus un disque troué. Le troisième paramètre (32) est le nombre de tranches qui constituent le disque. Pensez à des tranches de pizza. C'est la même chose, plus le nombre de morceaux sera important, plus le disque sera lissé. Finalement le quatrième paramètre (32) est le nombre d'anneaux constituant le disque. Les anneaux sont similaires à des chansons sur un disque vinyle. Des cercles à l'intérieur des cercles. Ces anneaux subdivisent le disque depuis le rayon intérieur jusqu'au rayon extérieur, élevant le niveau de détail. Comme toujours, plus il y a de subdivisions, plus le programme sera lent.

 
Sélectionnez
    case 2:                             // On dessine l'objet 3
        gluDisk(quadratic,0.5f,1.5f,32,32);         // On dessine un disque (forme de CD)
        break;                         // Terminé

Notre quatrième objet est un objet difficile à représenter sur un écran, que je sais beaucoup d'entre vous meurent d'envie de savoir. La sphère ! C'est en réalité très simple. Le premier paramètre est le rayon de la sphère. Dans le cas où vous ne seriez pas habituer aux notions de rayon, diamètre, etc., le rayon est la distance depuis le centre de la sphère jusqu'à la surface de la sphère. Dans l'exemple, notre rayon est de 1.3f. Ensuite nous avons nos subdivisions autour de l'axe Z (32), et nos divisions le long de l'axe Z (32). De la même manière, plus vous avez de subdivisions, plus la sphère a un aspect lissé, mais toujours au détriment de la vitesse d'exécution du programme. Généralement, les sphères ont besoin de peu de subdivisions pour avoir un aspect lisse.

 
Sélectionnez
    case 3:                         // On dessine l'objet 4
        gluSphere(quadratic,1.3f,32,32);         // On dessine une sphère
        break;                         // Terminé

Notre cinquième objet créé utilise la même commande que celle du cylindre. Si vous vous rappelez bien, en créant le cylindre nous passions deux rayons de base, un pour la base supérieure et l'autre pour le socle. Pour faire un cône, il suffit qu'un des deux rayons passés en argument soit égal à zéro. Ceci va créer un point à une des deux extrémités et la figure résultante est un cône.

 
Sélectionnez
    case 4:                             // On dessine l'objet 5
        glTranslatef(0.0f,0.0f,-1.5f);             // On centre le cône
        gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);     // Un cône de rayon base 0.5 et hauteur 2
        break;                         // Terminé

Notre sixième objet est créé par gluPartialDisc(). L'objet que nous créons aura la même apparence que le disque que nous avons créé précédemment mais la commande gluPartialDisc() prend deux paramètres supplémentaires. Le cinquième paramètre (part1) est l'angle à partir duquel nous voulons dessiner le disque. Le sixième paramètre est l'angle de balayage, qui est l'arc parcouru depuis l'angle courant passé en cinquième paramètre. Nous allons incrémenter cet angle de balayage, ce qui fera se dessiner le disque dans le sens des aiguilles d'une montre. Une fois atteint 360 degrés, nous augmenterons l'angle de départ, faisant ainsi disparaître le disque, et ainsi de suite !

 
Sélectionnez
    case 5:                         // On dessine l'objet 6
        part1+=p1;                     // On augmente l'angle de départ
        part2+=p2;                     // On augmente l'angle de balayage
        if(part1>359)                     // 360 degrés
        {
            p1=0;                     // On arrête d'augmenter l'angle de départ
            part1=0;                 // On met l'angle de départ à zéro
            p2=1;                     // On commence à augmenter l'angle de balayage
            part2=0;                 // On met l'angle de balayage à zéro
        }
        if(part2>359)                     // 360 degrés
        {
            p1=1;                     // On commence à augmenter l'angle de départ
            p2=0;                     // On arrête d'augmenter l'angle de balayage
        }
        gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1);     // Un disque comme le précédent 
        break;                         // Terminé
    };
    xrot+=xspeed;                     // Augmente la rotation selon l'axe X
    yrot+=yspeed;                     // Augmente la rotation selon l'axe Y
    return TRUE;                         // Continuer
}

Dans la section de code de KillGLWindow(), nous avons besoin de supprimer la quadrique pour libérer des ressources systèmes. Ceci est réalisé par la commande gluDeleteQuadratic.

 
Sélectionnez
GLvoid KillGLWindow(GLvoid)                     // 
{
    gluDeleteQuadric(quadratic);                 // Détruit la quadrique  libère les ressources

Maintenant pour la partie finale, nous entrons la clé. Ajoutez seulement ceci là où nous vérifions le reste des touches.

 
Sélectionnez
                if (keys[' '] && !sp)         // La barre d'espace est-elle enfoncée ?
                {
                    sp=TRUE;         // Si oui, mettre sp à TRUE
                    object++;         // Parcours des objets 
                    if(object>5)         // objet est-il plus grand que 5 ?
                        object=0;     // Si oui, le remettre à zéro
                }
                if (!keys[' '])             // La barre d'espace a-t-elle été relâchée ?
                {
                    sp=FALSE;         // Si oui, mettre sp à FALSE
                }

C'est tout ! Maintenant vous pouvez dessiner des quadriques avec OpenGL. Quelques objets impressionnants peuvent être réalisés avec le morphing et les quadriques.

Le disque animé est un exemple simple de morphing.

À tout le monde, si vous avez le temps, visitez mon site web, TipTup.com 2000.

GB Schmick (TipTup)

Jeff Molofee (NeHe)

III. Téléchargements

Compte tenu du nombre de versions de codes sources pour les tutoriels NeHe, nous les laissons en anglais. En principe, si vous avez compris le code présenté dans ce tutoriel (et les tutoriels antérieurs), vous n'aurez pas de mal à les comprendre :

IV. Remerciements

Merci Winjerome pour sa relecture ainsi que zoom61 pour ses corrections.

V. Liens