Quadriques

GB Schmick (TipTup) et Jeff Molofee (NeHe)

Traducteur

kromartien

Les Quadriques sont une manière de représenter des objets composés complexes qui nécessiteraient autrement beaucoup de calculs trigonométriques et d'itérations successives. ♪

- Titre : Quadriques

- Auteur : GB Schmick (TipTup) et Jeff Molofee (NeHe)

- Traducteur : kromartien

- Parution : 19 décembre 2012

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2006 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'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Contributions

- II. Tutoriel

- 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

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

#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.

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

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.

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.

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.

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 habitué 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.

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.

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 !

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.

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.

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 :

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

- C# (Conversion by Brian Holley) ;

- Code Warrior 5.3 (Conversion by Scott Lupton) ;

- Cygwin (Conversion by Stephan Ferraro) ;

- Delphi (Conversion by Michal Tucek) ;

- Dev C++ (Conversion by Dan) ;

- Euphoria (Conversion by Evan Marshall) ;

- Game GLUT (Conversion by Milikas Anastasios) ;

- Irix/GLUT (Conversion by Rob Fletcher) ;

- Java (Conversion by Jeff Kirby) ;

- JoGL (Conversion by Abdul Bezrati) ;

- LCC Win32 (Conversion by Robert Wishlaw) ;

- Linux (Conversion by Simon Werner) ;

- Linux/GLX (Conversion by Mihael Vrbanec) ;

- Linux/SDL (Conversion by Ti Leggett) ;

- LWJGL (Conversion by Mark Bernard) ;

- Mac OS (Conversion by Anthony Parker) ;

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

- MASM (Conversion by Christophe) ;

- Visual C++ / OpenIL (Conversion by Denton Woods) ;

- Pelles C (Conversion by Pelle Orinius) ;

- SDL (Conversion by Ken Rockot) ;

- Visual Basic (Conversion by The Gilb) ;

- Visual C++ ;

- Visual Studio .NET (Conversion by Grant James).

IV - Remerciements

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

V - Liens

Sommaire.

Tutoriel précédent : Texture 2D de police

Tutoriel suivant : Moteur de particules utilisant les chaînes de triangles