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

Image du tutoriel

II-A. Introduction

Commençons par le début. Chargez le projet du tutoriel n° 6 dans Visual C++ ou un autre éditeur C++ et ajoutez la ligne suivante, juste après les autres lignes '#include'. Ce '#include' ci-dessous nous permet de travailler avec les fonctions mathématiques comme le sinus et le cosinus.

Inclusion
Sélectionnez
#include <math.h>    // Pour la fonction sin()

II-B. Structure de données

Nous allons utiliser un tableau pour stocker les coordonnées x, y et z de la grille. Cette grille est composée de 45 points sur 45, ce qui par conséquent constitue 44 carrés sur 44. L'entier 'wiggle_count' (comprendre compteur d'ondulation) va stocker le coefficient de rapidité des vagues de la texture. Pour qu'à chaque seconde l'image soit belle, la variable 'hold' va stocker un flottant pour lisser les ondulations du drapeau. Les lignes suivantes peuvent être ajoutées en haut du programme, quelque part en dessous de la dernière ligne '#include' mais avant la ligne 'GLuint texture[1]'.

Variables globales
Sélectionnez
float points[45][45][3];        // Le tableau pour stocker les coordonnées de la "vague"
int wiggle_count = 0;            // Le compteur utilisé pour contrôler la vitesse des ondulations
GLfloat hold;                    // Le flottant pour lisser les ondulations

II-C. La fonction LoadGLTextures

Allez à la fonction 'LoadGLTextures()', plus bas dans le code. Nous voulons utiliser la texture appelée 'Tim.bmp'. Trouvez la ligne 'LoadBMP("Data/NeHe.bmp")' et remplacez-la par 'LoadBMP("Data/Tim.bmp")'.

Appel à LoadBMP
Sélectionnez
if (TextureImage[0]=LoadBMP("Data/Tim.bmp"))    // Charge le bitmap

II-D. La fonction InitGL

Maintenant, ajoutez le code suivant à la fin de la fonction InitGL() avant le return TRUE.

Mise en place de glPolygonMode
Sélectionnez
glPolygonMode( GL_BACK, GL_FILL );    // La face de derrière est dessinée pleine
glPolygonMode( GL_FRONT, GL_LINE );    // La face de devant n'est dessinée qu'en mode fil de fer

Ces lignes indiquent que nous voulons que les faces arrière des polygones soient complètement remplies et que les faces avant soient juste dessinées avec des lignes. C'est principalement un point de vue personnel. Cela a un rapport avec l'orientation des polygones ou la direction des sommets. Allez voir le 'Red Book' pour plus de précisions là-dessus. Tant que j'y suis, laissez-moi vous dire que ce livre est un atout majeur qui m'a aidé à apprendre OpenGL, sans oublier le site de NeHe ! Merci NeHe. Achetez le 'Red Book' écrit par Addison-Wesley. C'est une ressource incontournable selon moi. OK, retour au tutoriel. Juste en dessous du code ci-dessus, et avant la ligne 'return TRUE', ajoutez les lignes suivantes.

II-E. La boucle

Mis en place des points
Sélectionnez
// Boucle sur le plan des X
for (int x = 0; x < 45; x++)
{
    // Boucle sur le plan des Y
    for (int y = 0; y < 45; y++)
    {
        // On applique la forme d'une vague à notre grille
        points[x][y][0] = float((x / 5.0f) - 4.5f);
        points[x][y][1] = float((y / 5.0f) - 4.5f);
        points[x][y][2] = float(sin((((x / 5.0f) * 40.0f) / 360.0f) * 3.141592654 * 2.0f));
    }
}

Je remercie Graham Gibbons de m'avoir suggéré d'utiliser une boucle sur un entier afin d'éliminer les pointes sur l'ondulation. Les deux boucles ci-dessus initialisent les coordonnées de notre grille. J'initialise les compteurs dans les boucles elles-mêmes pour garder à l'esprit que ce sont de simples variables de boucle. Nous utilisons des boucles avec des entiers pour prévenir d'étranges bogues graphiques faisant apparaître des pointes lorsqu'on utilise des flottants. Nous divisons les variables x et y par 5 (exemple : 45 / 5 = 9) et enlevons 4.5 pour chacun d'entre eux pour centrer la "vague" (on passe de l'intervalle [0, 45) à [-4.5, 4.5)). Le même effet pourrait être réalisé avec une translation, mais je préfère cette méthode. La valeur finale 'points[x][y][2]' est notre valeur sinusoïdale. La fonction 'sin()' prend en entrée des radians. Nous prenons notre valeur en degré, qui est notre 'float_x' multiplié par '40.0f'. Une fois que nous avons fait ça, pour convertir les degrés en radians : on divise par 360.0f, on multiplie par PI, ou une approximation, et on multiplie par 2.0f.

II-F. DrawGLScene

Je vais réécrire la fonction 'DrawGLScene' depuis le début pour nettoyer un peu le code et le remplacer par le suivant.

La fonction DrawGLScene
Sélectionnez
int DrawGLScene(GLvoid)                            // Dessine notre scène OpenGL
{
    int x, y;                                    // Variables de boucle
    float float_x, float_y, float_xb, float_yb;    // Utilisé pour casser le drapeau en petits carrés

Différentes variables sont utilisées pour contrôler les boucles. Regardez le code ci-dessous, la plupart d'entre elles ne servent pas à autre chose qu'au contrôle des boucles et à la sauvegarde de valeurs temporaires.

Initialisation OpenGL
Sélectionnez
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // Efface la scène et le tampon de profondeur
glLoadIdentity();                                    // Réinitialise la matrice courante

glTranslatef(0.0f,0.0f,-12.0f);                        // Déplace de 12 unités dans l'écran

glRotatef(xrot,1.0f,0.0f,0.0f);                        // Rotation sur l'axe des X
glRotatef(yrot,0.0f,1.0f,0.0f);                        // Rotation sur l'axe des Y
glRotatef(zrot,0.0f,0.0f,1.0f);                        // Rotation sur l'axe des Z

glBindTexture(GL_TEXTURE_2D, texture[0]);            // Sélection de notre texture

Vous avez déjà vu ce code, bien entendu. C'est le même qu'au tutoriel n° 6 sauf que j'ai un petit peu éloigné la scène de la caméra.

Boucle externe
Sélectionnez
glBegin(GL_QUADS);                // Commence à dessiner les carrés
for( x = 0; x < 44; x++ )        // Boucle sur le plan sur l'axe des X (44 Points)
{
    for( y = 0; y < 44; y++ )    // Boucle sur le plan de l'axe des Y (44 Points)
    {

II-G. Rendu

C'est simplement le lancement de la boucle qui dessine nos polygones. J'utilise des entiers ici, pour éviter d'utiliser la fonction 'int()' comme je l'avais fait avant pour récupérer la référence du tableau qui est retournée comme un entier.

Valeurs flottantes pour le drapeau
Sélectionnez
float_x = float(x)/44.0f;        // Crée un point en virgule flottante pour la valeur X
float_y = float(y)/44.0f;        // Crée un point en virgule flottante pour la valeur Y
float_xb = float(x+1)/44.0f;    // Crée un point en virgule flottante pour la valeur X + 0.0227f
float_yb = float(y+1)/44.0f;    // Crée un point en virgule flottante pour la valeur Y + 0.0227f

Nous utilisons quatre variables pour les coordonnées de texture, ci-dessus. Chaque polygone (un carré de notre grille) est rattaché à une section de 1/44 par 1/44 de la texture. La boucle va spécifier le sommet en bas à gauche en premier et ensuite nous ajoutons les trois autres sommets (exemple : x + 1 ou y + 1).

Fonction GL
Sélectionnez
        glTexCoord2f( float_x, float_y);    // Première coordonnée de texture (bas gauche)
        glVertex3f( points[x][y][0], points[x][y][1], points[x][y][2] );

        glTexCoord2f( float_x, float_yb );    // Seconde coordonnée de texture (haut gauche)
        glVertex3f( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );

        glTexCoord2f( float_xb, float_yb );    // Troisième coordonnée de texture (haut droit)
        glVertex3f( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );

        glTexCoord2f( float_xb, float_y );    // Quatrième coordonnée de texture (bas droit)
        glVertex3f( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
    }
}
glEnd();                                    // Fin de dessin des carrés

Les lignes ci-dessus sont simplement les appels aux fonctions OpenGL pour traiter les données dont nous venons de parler. Quatre appels différents à 'glTexCoord2f()' et 'glVertex3f()'. Remarquez que les carrés sont dessinés dans le sens horaire. Cela signifie que la face que vous voyez en premier est la face arrière. Cette face est remplie. L'autre face est dessinée en fil de fer. Si vous dessinez dans le sens antihoraire, vous verrez en premier la face avant, cela signifie que vous verrez une texture en fil de fer à la place d'une texture pleine.

Est-ce que nous voulons ralentir le drapeau ?
Sélectionnez
if( wiggle_count == 2 )    // Ralentit la vague (toutes les deux images seulement)
{

Si nous avions dessiné deux scènes, alors nous aurions voulu boucler nos valeurs sinusoïdales pour donner un effet de "mouvement".

Gérer la mise à jour
Sélectionnez
    for( y = 0; y < 45; y++ )        // Boucle sur les axes des Y
    {
        hold=points[0][y][2];        // Sauvegarde la valeur courante de la partie gauche de la vague
        for( x = 0; x < 44; x++)    // Boucle sur les axes des X
        {
            // Valeurs de la vague équivalent à celle sur la droite
            points[x][y][2] = points[x+1][y][2];
        }
        points[44][y][2]=hold;        // Dernière valeur qui devient la valeur de l’extrémité gauche
    }
    wiggle_count = 0;                // Remise du compteur à zéro 
}
wiggle_count++;                        // Incrémentation du zéro

Ce que nous faisons ici, c'est sauvegarder la première valeur de chaque ligne et nous déplacer sur la gauche d'un cran, pour obtenir l'effet d'ondulation. La valeur que nous avons sauvegardée est alors ajoutée à la fin pour créer un effet sans fin à travers la texture. Finalement nous remettons à zéro le compteur 'wiggle_count' pour garder un effet correct. Le code ci-dessus a été modifié par NeHe (février 2000) pour enlever un défaut sur l'ondulation de la surface de la texture. Maintenant, l'ondulation est douce.

Gère la rotation
Sélectionnez
xrot+=0.3f;        // Incrémentation de la variable de rotation de l'axe des X
yrot+=0.2f;        // Incrémentation de la variable de rotation de l'axe des Y
zrot+=0.4f;        // Incrémentation de la variable de rotation de l'axe des Z

return TRUE;    // Retour

II-H. Conclusion

Les valeurs de rotation standards de NeHe. :) Et c'est fini. Compilez et vous devriez avoir un joli effet de "vague" texturée. Je ne sais quoi dire de plus sauf, whaouh... c'était long ! Mais j'espère que vous pourrez comprendre et en retirer quelque chose. Si vous avez des questions, ou si vous avez des points que vous voulez que j'éclaircisse ou me dire à quel point je code divinement bien, ;) alors envoyez-moi un message. C'était compliqué mais vraiment prenant. Maintenant, j'apprécie beaucoup plus les gens comme Nehe, merci à tous.

Bosco (bosco4@home.com) 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 à Freddec_2010, LittleWhite, mabu, Winjerome, fearyourself et ClaudeLELOUP pour leur relecture.

V. Liens