Bien le bonjour à tous. Pour ceux qui souhaitent voir ce que nous allons faire ici, vous pouvez dorénavant télécharger ma démo à la fin de ce tutoriel ! Je suis 'Bosco' et je vais faire de mon mieux pour vous apprendre à créer une image animée d'un effet de vague. Ce tutoriel est basé sur le code et les connaissances requises du tutoriel n° 6 de NeHe. Vous pouvez télécharger les sources du tutoriel et placer le fichier bitmap que j'ai inclus dans le dossier 'data' avec le code source. Sinon vous pouvez utiliser votre propre texture si elle est appropriée à l'usage des textures avec OpenGL.

- Titre : Effet de drapeau

- Auteurs : Bosco et Jeff Molofee (NeHe), Alexandre Laurent

- Parution : 19 décembre 2012

- Licence : Les sources présentés sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2010 Nehe Gamedev.net. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée à la SACD.

Sommaire

- I. Contributions

- II. Tutoriel

- II-A. Introduction

- II-B. Structure de données

- II-C. La fonction LoadGLTextures

- II-D. La fonction InitGL

- II-E. La boucle

- II-F. DrawGLScene

- II-G. Rendu

- II-H. Conclusion

- III. Téléchargements

- IV. Remerciements

- V. Liens

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

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

#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

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

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

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

// 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

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

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

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

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

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 ?

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

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

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 :

- Borland C++ Builder 6 (Conversion par Christian Kindahl) ;

- C# (Conversion par Brian Holley) ;

- Code Warrior 5.3 (Conversion par Scott Lupton) ;

- CygWin (Conversion par Stephan Ferraro) ;

- Delphi (Conversion par Michal Tucek) ;

- Dev C++ (Conversion par Dan) ;

- Euphoria (Conversion par Evan Marshall) ;

- Game GLUT (Conversion par Milikas Anastasios) ;

- Irix (Conversion par Rob Fletcher) ;

- Java (Conversion par Jeff Kirby) ;

- Jedi-SDL (Conversion par Dominique Louis) ;

- JOGL (Conversion par Nicholas Campbell) ;

- LCC Win32 (Conversion par Robert Wishlaw) ;

- Linux (Conversion par Richard Campbell) ;

- Linux GLX (Conversion par Mihael Vrbanec) ;

- Linux SDL (Conversion par Ti Leggett) ;

- LWJGL (Conversion par Mark Bernard) ;

- Mac OS (Conversion par Anthony Parker) ;

- Mac OS X/Cocoa (Conversion par Bryan Blackburn) ;

- MASM (Conversion par Nico (Scalp)) ;

- VC++/OpenIL (Conversion par Denton Woods) ;

- Pelles C (Conversion par Pelle Orinius) ;

- Power Basic (Conversion par Angus Law) ;

- Visual Basic (Conversion par Ross Dawson) ;

- Visual Studio ;

- Visual Studio NET (Conversion par Grant James).

IV - Remerciements

Merci à Freddec_2010, LittleWhite, mabu, Winjerome, fearyourself et ClaudeLELOUP pour leur relecture.

V - Liens

Sommaire.

Tutoriel précédent : Chargement d'un monde 3D.

Tutoriel suivant : liste d'affichage.

Effet de drapeau

Auteurs

| Bosco et Jeff Molofee (NeHe) | Alexandre Laurent |