top of page

​​

Vous souhaitez découvrir l'univers de la 3D et du jeu vidéo, alors ce site est fait pour vous !

Pour cela, il vous faudra de bonnes notions en C et C++, et de bonnes connaissances en mathématiques.

OpenGL est une API graphique bas-niveau destinée à créer des images de synthèse temps réel en 3D.

Cette bibliothèque offre de nombreuses fonctions prêtes à l'emploi.

Nous étudierons une série d'exemples progressifs aboutissant à la réalisation de jeux complets avec OpenGL 2.0 (dit aussi l'ancien OpenGL).

D'autres extensions telles que SDL, GLUT, GLEE, Freetype peuvent s'ajouter à OpenGL en vue obtenir plus de fonctionnalités graphiques.

Cette section traitera de la géométrie algorithmique, c'est à dire le développement d'un composant logiciel qui gérera l'animation, la physique ainsi que le traitement d'images de synthèse en temps-réel.

Nous verrons à travers ces quelques exemples les bases de la programmation graphique.

Il ne vous reste donc plus qu'à lire les pages du tutoriel que j'ai écrit moi-même pour vous.

A vous de jouer...

Bonne lecture !!!

Démo qui montre les possibilités offertes par OpenGL !!!

1 - Initialiser OpenGL  avec GLUT

Exemple 1:

Dans cet exemple, nous verrons comment initialiser une fenêtre avec GLUT,

ce qui constituera notre première fenêtre de rendu à savoir notre point de démarrage.

Les étapes à suivre sont les suivantes:

//inclusions des librairies windows, openGL, glu et GLUT #include <windows.h>  #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h>

prototype de fonction servant à afficher le dessin (ici il est vide pour l'instant!) void dessiner(); 

int main(int argc, char ** argv)//fonction principal  {    

 glutInit(&argc,argv);//initilisation de l'api glut     glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode d'affichage de glut qui gere plusieurs types de tampons    

 glutInitWindowSize(960,540);// taille de la fenetre     glutCreateWindow("tuto01");// création d'une fenetre avec un titre de l'application     glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'ecran qui prend en paramètre une fonction dessiner()     glutMainLoop();// fonction d'appel en continu d'affichage dans main()     return 0; 

}

void dessiner() {     

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// effacement de la fenêtre et vidage des tampons        

 glutSwapBuffers();// échange de tampons pour achever l'affichage glut     glutPostRedisplay();// rafraîchissement de la scène en continu    

  }

2 - Affichage d'un triangle et d'un pentagone à l’écran

Exemple 2:

Après avoir vu l’initialisation en GLUT, il faut maintenant comprendre comment afficher un pixel à l’écran donc comprendre le processus de restitution d'une image à l’écran car pour l'instant notre tampon est vide, le rendu n'affiche rien.

Quand on parle d'image, il faut d'abord apprendre à afficher un pixel à l'écran.

Un pixel est un point dans un espace 2D ou 3D. L'ensemble de ces points forme une série de pixels, donc une image 2D.

Au sein d'un pixel, on peut faire des opérations, on parle de manipuler des pixels.

On peut effectuer des opérations sur les objets graphiques dites opérations de transformations dans un espace 2D ou 3D (rotations, changements d’échelle, translation).

Un pixel constitué de 3 points liés à 3 segments peut former une surface pleine ou vide.

Cette surface contient deux faces (dites aussi normales):

une normale intérieure et une normale extérieure.

Sur un pixel, on peut émettre une couleur qui peut être de type RGB ou RGBA. 

Sur l'ordinateur, on dit qu'on lit des valeurs comprises entre 0 et 1. Chacune de ces valeurs correspond à une couleur; plus on est proche de l'indice 1 plus la couleur est claire, plus on est proche de 0 plus la couleur est assombrie.

On verra dans les chapitres d'après que l'on peut stocker d'autres composantes que les couleurs au sein d'un pixel.

Lorsqu'on dessine en Opengl, on commence d'abord par vider les tampons (buffers).

Cela signifie qu'on doit effacer la fenêtre (fenêtre noire) et ensuite commencer à dessiner, ce qui est l'inverse du dessin traditionnel car la feuille au départ est toute blanche.

En fait, on dit que les pixels dans le processus de restitution d'image sont stockés dans des tampons, il en existe plusieurs types (tampons chromatiques....).

Ensuite, il faut définir un mode de projection c'est-à-dire sur quel mode doit se projeter le pixel sur l'écran.

Il existe deux types de vues, soit une vue de type orthographique (projection 2D),  soit une vue de type  perspective (l'objet est projeté en 3D).

Ensuite, il faut vider la matrice avant de commencer à dessiner. 

Une matrice se définit par un ensemble de transformations (transformations de modélisation, transformations de projection, transformation de visualisation) qui sont exécutées les unes après les autres. Toutes les opérations de transformations sont stockées dans des matrices.

Dans la 3D on dit qu'on travaille avec des matrices 4*4. (w,x,y,z). Chacune de ces composantes doit se comporter de manière homogène. 

Pour séparer deux transformations, on fait appel à 2 matrices, une entrée et une sortie. 

On parle de piles matricielles lorsque le nombre de matrices s'accumule. 

Avant de dessiner des objets graphiques (dit aussi transformation de modélisation), on doit faire appel à la transformation de visualisation  c'est-à-dire définir un point de vue dans notre scène 3D.

Ensuite on restitue l'objet à l’écran.

Pour se faire, on commence par dire quel type de forme on souhaite afficher (polygone, triangle, quadrilatère).

Ensuite, on affiche chacun des sommets qui constituera notre future forme.

Exemple de méthode d'affichage d'un sommet à l'écran:

matrice()

transformation rotation

transformation échelle

affichage des sommets

fin de la matrice

etc... 

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h>

void dessiner(); void reshape(int width,int height);

int main(int argc, char ** argv) {  

   glutInit(&argc,argv);//initilisation de glut     glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode d'affichage de glut     glutInitWindowSize(960,540);// taille de la fenêtre

     glutCreateWindow("tuto01");// titre de l'application

     glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l’écran     glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l’écran 

    glutMainLoop();// fonction d'appel en continue d'affichage dans main()     return 0; 

}

void dessiner() {    

 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// effacement de la fenêtre et vidage des tampons      

glMatrixMode(GL_MODELVIEW);// choix du mode d'affichage en modelview  

  glLoadIdentity();// initialisation de la matrice     gluLookAt(0.8,0.3,10.0,0,0,0,0,1,0);// affichage de la camera à lécran    

glBegin(GL_TRIANGLES);// fonction pour commencer à dessiner un triangle à l’écran     glColor3d(0.2f,0.2f,0.2f);// application d'une couleur sur un sommet du triangle     glVertex3d(2.0,2.5,-1.0);// application d'un sommet à afficher dans la fenetre     glColor3d(0.2,0.3,0.4);     glVertex3d(-3.5,-2.5,-1.0);     glColor3d(0.5,0.8,0.5);     glVertex3d(2.0,-4.0,-1.0);     glEnd();     glBegin(GL_TRIANGLE_FAN);// fonction pour commencer à dessiner un pentagone     glColor3d(0.2,0.5,0.2);     glVertex3d(-1,2,0);         glColor3d(0.8,0.5,0.2);     glVertex3d(-3,-0.5,0);         glColor3d(0.6,0.5,0.2);     glVertex3d(-1.5,-3.0,0);         glColor3d(0.5,0.8,0.1);     glVertex3d(1,-2,0);         glColor3d(0.3,0.2,0.4);     glVertex3d(1,1,0);     glEnd();     glutSwapBuffers();// échange de tampons pour achever l'affichage glut     glutPostRedisplay();// rafraîchissement de la scène en continue      } void reshape(int width,int height) {     glViewport(0,0,width,height);// définition de la taille d'affichage de l'angle de la camera     glMatrixMode(GL_PROJECTION);// on choisit le mode projection de la matrice      glLoadIdentity();// on initialise la matrice     gluPerspective(45,float (width)/float (height),0.1f,5000); // on dit qu'on travaille en mode perspective avec une focale et un point de vue     glMatrixMode(GL_MODELVIEW);// on change de mode d'affichage, on recharge une nouvelle matrice de transformation de modélisation    

 }

Capture.PNG

3 - Animer un objet en GLUT

Exemple 3:

L'animation de manière générale se définit par un ensemble d'images qui les unes après les autres constituent un mouvement. En jeux vidéo (temps-réel), on travaille sur du 60 frames par seconde en moyenne et au cinéma, 25 frames par seconde. (soit 1 seconde = 25 frames)

En opengl, il faut mettre à jour constamment la scène, c'est à dire qu'a chaque nouvel état, on rafraîchit la scène.

Ensuite, il faut incrémenter de 1 unité ou plus la position de notre objet graphique.

x++ // ici, on fait varier de 1 unité la position en X de notre objet

En fait, x, y, et z sont des composantes de la transformation de modélisation.

Ce sont ces composantes dans lesquelles nous pouvons effectuer des transformations de translation.

Ainsi nous pourrons déplacer notre mesh selon la postion x, y ou z.

Pour simplifier les choses, on aurait la possibilité de stocker notre transformation dans un vecteur qui contiendrait chacune des composantes de notre transformation.

soit V(x,y,z);

Il est important de noter qu'à chaque fois que l'on déplace un objet il est important de rafraichir la scène.

Pour se faire appeler la procédure: glutPostRedisplay();

Juste, dans notre exemple, l'objet subira  x rotation à chaque frame.

Voyons un exemple:

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h>

void dessiner(); void reshape(int width,int height); int anim; int anim2;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode d'affichage de glut glutInitWindowSize(960,540);// taille de la fenêtre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l’écran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l’écran glutMainLoop();// fonction d'appel en continue d'affichage dans main() return 0; }

void dessiner() {     anim+=1;// on incrémente une variable de 1 unité.     anim2+=4.0;on incrémente une variable de 4 unité. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// effacement de la fenêtre et vidage des tampons  glMatrixMode(GL_MODELVIEW);// choix du mode d'affichage en modelview glLoadIdentity();// initialisation de la matrice gluLookAt(0.8,0.3,10.0,0,0,0,0,1,0);// affichage de la camera à l'écran glPushMatrix();//debut de la matrice glRotated(anim2,0,0,0.5);//rotation de l'objet triangles glBegin(GL_TRIANGLES);// fonction pour commencer à dessiner un triangle à l’écran glColor3d(0.2f,0.2f,0.2f);// application d'une couleur sur un sommet du triangle glVertex3d(2.0,2.5,-1.0);// application d'un sommet à afficher dans la fenêtre glColor3d(0.2,0.3,0.4); glVertex3d(-3.5,-2.5,-1.0); glColor3d(0.5,0.8,0.5); glVertex3d(2.0,-4.0,-1.0); glEnd(); glPopMatrix();//fin de la matrice glPushMatrix();// début de la matrice glRotated(anim,0,0.5,0);//rotation de l'objet pentagone glBegin(GL_TRIANGLE_FAN);// fonction pour commencer à dessiner un pentagone glColor3d(0.2,0.5,0.2); glVertex3d(-1,2,0); glColor3d(0.8,0.5,0.2); glVertex3d(-3,-0.5,0); glColor3d(0.6,0.5,0.2); glVertex3d(-1.5,-3.0,0); glColor3d(0.5,0.8,0.1); glVertex3d(1,-2,0); glColor3d(0.3,0.2,0.4); glVertex3d(1,1,0); glEnd(); glPopMatrix();//fin de la matrice glutPostRedisplay();// rafraîchissement automatique de la scène à chaque image calculées glutSwapBuffers();// échange de tampons pour achever l'affichage glut glutPostRedisplay();// rafraîchissement de la scène en continue  } void reshape(int width,int height) { glViewport(0,0,width,height);// définition de la taille d'affichage de l'angle de la camera glMatrixMode(GL_PROJECTION);// on choisit le mode projection de la matrice  glLoadIdentity();// on initialise la matrice gluPerspective(45,float (width)/float (height),0.1f,5000); // on dit qu'on travaille en mode perspective avec une focale et un point de vue glMatrixMode(GL_MODELVIEW);// on change de mode d'affichage, on recharge une nouvelle matrice de transformation de modélisation }

4 - Les primitives en GLUT et les modes d'affichage

exemple 4:

Dans la 3D il existe plusieurs types de primitives, à savoir les objets de base c'est à dire un cube, une sphère, un cylindre, une ligne, une courbe de bézier, des objets procéduraux déjà définis au sein de la librairie OpenGL.

On peut afficher ces objets dans différents modes soit en mode normal c'est à dire que les normales sont remplis de gris, soit en mode texturer, les normales sont affectés d'une texture dite soit procédurale soit d'un certain type (jpg,png,bmp...), soit en mode fil de fer (ideal pour voir la constitution d'un mesh), soit en mode bouding box c'est à dire que les objets ne sont visibles que par l'intermédiaire d'un cube en mode filaire qui l'entoure.

En fait, les primitives sont faites pour montrer qu'il existe déjà des formes prêtes à l'emploi. Ensuite, on pourra modifier ces formes basiques pour créer des formes plus complexes (véhicules, architectures, humains...).

Vous vous souvenez que dans le premier exemple, j'avais montrer comment dessiner un triangle avec 3 sommets dédiés à être affichés dans une scène.

On pourrait techniquement faire des formes très complexes en créant des séries de triangles qui formeront un mesh complet et pour éviter de répéter les opérations se servir de tableaux de sommets. Pour un véhicule low-poly on pourra compter plusieurs centaines d'appels de fonctions les unes après les autres destinées à afficher notre futur objet.

Vous verrez quelques primitives s'afficher selon certains modes dans l'exemple ci-après.

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h>

void dessiner(); void reshape(int width,int height); int anim; int anim2;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode addfichage de glut glutInitWindowSize(960,540);// taille de la fenetre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l'ecran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'ecran glutMainLoop();// fonction d'appel en continue d'affichage dans main() return 0; }

void dessiner() { 

    anim+=1;     anim2+=4.0; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// effacement de la fenêtre et vidage des tampons  glMatrixMode(GL_MODELVIEW);// choix du mode d'affichage en modelview glLoadIdentity();// initialisation de la matrice gluLookAt(0.4,0.3,4.0,0,0,0,0,1,0);// afichage de la camera à lecran

glPushMatrix();//début de la matrice glRotated(anim,0,0,0.5);//rotation de l'objet triangles glColor3d(0.8,0.9,0.9); glutSolidCube(0.5f);//affichage d'un cube en mode normal glPopMatrix(); glPushMatrix(); glTranslated(2,0,0); glRotated(anim,0,0,0.5);//rotation de l'objet triangles glColor3d(0.5,0.5,0.1); glutSolidSphere(0.4,20,20);//affichage d'une sphère en mode normal glPopMatrix(); glPushMatrix(); glTranslated(1,0,0); glRotated(anim,0,0,0.5);//rotation de l'objet triangles glColor3d(0.7,0.4,0.2); glutWireSphere(0.4,20,20);//affichage d'une sphere en mode fil de fer glPopMatrix(); glPushMatrix(); glTranslated(-1,0,0); glRotated(anim,0,0,0.5);//rotation de l'objet triangles glColor3d(0.7,0.4,0.2); glutWireCube(0.8);//afichage d'un cube en mode fil de fer

glEnd(); glPopMatrix();//fin de la matrice glutPostRedisplay();// rafraichissement automatique de la scène à chaque image calculée glutSwapBuffers();// échange de tampons pour ahever l'affichage glut glutPostRedisplay();// rafraichissement de la scène en continue  } void reshape(int width,int height) { glViewport(0,0,width,height);// définition de la taille d'affichage de l'angle de la camera glMatrixMode(GL_PROJECTION);// on choisit le mode projection de la matrice  glLoadIdentity();// on initialise la matrice gluPerspective(45,float (width)/float (height),0.1f,5000); // on dit qu'on travaille en mode perspective avec une focale et un point de vue glMatrixMode(GL_MODELVIEW);// on change de mode d'affichage, on reload une nouvelle matrice de transformation de modélisation

 }

5 - Animation d'un robot

exemple 5:

La création d'un robot est un excellent excercice pour comprendre l'exercice sur l'accumulation des piles matricielles.

Il faut tout d'abord comprendre comment est constitué un robot.

En fait, on parle de hiérarchisation et de relation de dépendance entre les membres au sein d'un objet de type robot.

exemple: lorsque le robot bouge son bras, c'est le bras qui entraine un mouvement de l'avant bras puis fait bouger les mains et chaque doigt d'une main.

Cela constitue une chaine et donc une dépendance entre les membres.

pour modéliser cette situation d'un point de vue informatique, on peut dire que l'objet bras contient un avant-bras, un bras, une main et des doigts qui sont stockés au sein d'une même pile matricielle.

lorsqu'on bouge la tête, l'objet bras étant indépendant de l'objet tête, on peut créer une pile pour la tête, une pile pour le bras et viennent ensuite les autres membres qui seront traités de la même façon que l'objet bras.

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h> #include<math.h> #define pi 3.14159265359 // on definit un nombre pi

void dessinerdecor(); void dessiner(); void reshape(int width,int height); void gestionSpecial(int key,int x,int y); void passive(int key,int x,int y); void clavier();     bool up,down,right,left=false;

typedef struct robot robot; // on definit la structure de notre robot

struct robot { void dessin(); void tete(); void corps(); void bras(); void avantbras(); void jambe(); void avantjambe(); float animbras1; float animbras2; float animjambe1; float animjambe2; float anim; float animtete; float avancerX; float avancerZ; float Yrot; };

robot r;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode addfichage de glut glutInitWindowSize(960,540);// taille de la fenetre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l'ecran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'ecran glutSpecialFunc(gestionSpecial);// fonctions de gestion d'appuie des touches du clavier glutSpecialUpFunc(passive);// fonctions de relachement d'une touche du clavier glutMainLoop();// fonction d'appel en continue d'affichage dans main() return 0; }

void dessiner() {      glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// effacement de la fenetre et vidage des tampons  glMatrixMode(GL_MODELVIEW);// choix du mode d'affichage en modelview glLoadIdentity();// initialisation de la matrice gluLookAt(0.4,0.3,15.0,0,0,0,0,1,0);// afichage de la camera à lecran clavier(); glPushMatrix(); dessinerdecor();// on dessiner notre decor (ici un simple plan) glPopMatrix(); glPushMatrix();//debut de la matrice glTranslated(r.avancerX,0,r.avancerZ);// on fait une transformation de translation glRotated(r.Yrot,0,0.5,0);// puis on fait une transformation de rotation r.dessin();//enfin on affiche notre robot glPopMatrix();//fin de la matrice glutPostRedisplay();// reafraichissement automatique de la scene à chaque image calculées glutSwapBuffers();// echange de tampons pour ahever laffichage glut glutPostRedisplay();// rafraichissement de la scene en continue  } void reshape(int width,int height) { glViewport(0,0,width,height);// definition de la taille d'affichage de l'angle de la camera glMatrixMode(GL_PROJECTION);// on chosit le mode projection de la matrice  glLoadIdentity();// on initialise la matrice gluPerspective(45,float (width)/float (height),0.1f,5000); // on dit qu'on travaille en mode perspective avec une focale et un point de vue glMatrixMode(GL_MODELVIEW);// on change de mode d'affichage, on reload une nouvelle matrice de transformation de modelisation } void robot::dessin() { tete();// on affiche la tete corps();// on affiche le corps } void robot::tete() { glPushMatrix(); glColor3d(0.2,0.2,0.1);// chargement d'une couleur glRotated(animtete,0.5,0,0); glutSolidCube(1); glPopMatrix(); } void robot::corps() { glPushMatrix(); glColor3d(0.8,0.8,0.4); glTranslated(0,-1.5,0); glutSolidCube(2); glPopMatrix(); glPushMatrix(); glRotated(animbras1,0.5,0,0); bras(); glPopMatrix(); glPushMatrix(); glTranslated(-3.8,0,0); glRotated(animbras2,0.5,0,0); bras(); glPopMatrix(); glPushMatrix(); glRotated(animjambe1,0.5,0,0); jambe(); glPopMatrix(); glPushMatrix(); glTranslated(1.7,0,0); glRotated(animjambe2,0.5,0,0); jambe(); glPopMatrix(); } void robot::bras() { glPushMatrix(); glColor3d(0.4,0.2,0.4); glTranslated(1.8,-1.5,0); glScaled(1,2,1); glutSolidCube(1); avantbras(); glPopMatrix(); } void robot::avantbras() { glPushMatrix(); glColor3d(0.1,0.3,0.9); glTranslated(0,-1.2,0); glutSolidCube(1); glPopMatrix(); } void robot::jambe() { glPushMatrix(); glColor3d(0.9,0.9,0.9); glTranslated(-0.8,-3.5,0); glScaled(1,2,1); glutSolidCube(1); avantjambe(); glPopMatrix();     } void robot::avantjambe() { glPushMatrix(); glColor3d(0.5,0.4,0.5); glTranslated(0,-1.2,0); glutSolidCube(1); glPopMatrix(); } void dessinerdecor() {     glPushMatrix();     glColor3d(0.1,0.1,0.2);     glTranslated(0,-0.2,0);         glScaled(100,1,100);     glutSolidCube(1);     glPopMatrix(); } void gestionSpecial(int key,int x,int y) {     switch(key)     {         case GLUT_KEY_UP:             up=true;             glutPostRedisplay();             break;             case GLUT_KEY_DOWN:                 down=true;                     glutPostRedisplay();                     break;                     case GLUT_KEY_RIGHT:                         right=true;                             glutPostRedisplay();                         break;                         case GLUT_KEY_LEFT:                         left=true;                             glutPostRedisplay();                         break;                              } } void passive(int key,int x,int y) {     switch(key)     {         case GLUT_KEY_UP:             up=false;             glutPostRedisplay();             break;             case GLUT_KEY_DOWN:                 down=false;                     glutPostRedisplay();                     break;                         case GLUT_KEY_RIGHT:                 right=false;                     glutPostRedisplay();                     break;                             case GLUT_KEY_LEFT:                 left=false;                     glutPostRedisplay();                     break;     }         if(down==false)     {             r.animbras1=0;         r.animbras2=0;         r.animjambe1=0;             r.animjambe2=0;     }         if(up==false)     {             r.animbras1=0;         r.animbras2=0;         r.animjambe1=0;             r.animjambe2=0;             r.animtete=0;     } }

void clavier() {         if(up)     {         r.avancerZ+=0.5f*cos(r.Yrot*pi/180);         r.avancerX+=0.5f*sin(r.Yrot*pi/180);                     r.animtete+=1.5f;             r.animbras1+=2.5f;         r.animbras2-=2.5f;             r.animjambe1+=2.5f;             r.animjambe2-=2.5f;         if(r.animbras1>60)         {             r.animbras1=-60;                      }             if(r.animjambe1>40)         {             r.animjambe1=-40;                      }     if(r.animbras2<-60)         {             r.animbras2=60;                      }     if(r.animjambe2<-40)         {             r.animjambe2=40;                      }         if(r.animtete>30)         {             r.animtete=-30;         }     } if(down)     {         r.avancerZ-=0.5f*cos(r.Yrot*pi/180);         r.avancerX-=0.5f*sin(r.Yrot*pi/180);             r.animbras1+=2.5f;         r.animbras2-=2.5f;         r.animjambe1+=2.5f;             r.animjambe2-=2.5f;             r.animtete+=1.5f;         if(r.animbras1>60)         {             r.animbras1=-60;                      }             if(r.animjambe1>40)         {             r.animjambe1=-40;                      }     if(r.animbras2<-60)         {             r.animbras2=60;                      }     if(r.animjambe2<-40)         {             r.animjambe2=40;                      }         if(r.animtete>30)         {             r.animtete=-30;         }     } if(right)     {         r.Yrot-=4.5f;     }      if(left)     {         r.Yrot+=4.5f;     }     

}

6 - Les textures

Exemple 6: (avec un damier)

Les textures sont un élément assez crucial dans le jeu video car imaginez-vous un monde sans texture.

Une texture permet de donner plus de réalisme au jeu, et puis lorsqu'on travaille sur du low poly, on ne peut pas se permettre de modéliser chaque détail d'un objet, la texture nous fait le travail.

Imaginer un mur de briques où il faudrait redessiner chaque petite fissure, chaque morceau de brique, et si le mur est constitué d'une centaine voir d'un millier de briques il faudrait répéter ces opérations cent voir 1000 fois, cela est impossible à faire tourner sur un jeu à 60 fps. Donc pour optimiser tout cela, on collera une texture sur  l'objet à l'issue de laquelle on pourra rajouter d'autres textures sur l'objet. Ces autres textures peuvent être des normalmap, des bumpmap, des displace map, des height map, des volumeteric map ou des maps détaillés et il en existe encore...

Tout cela bien évidemment renforcera le réalisme du jeu. Quand on parle de texture, il faut déjà parler de matériaux.

Sur une surface d'un objet (normale) on affecte un matériau qui peut être soit une couleur soit une texture.

Si c'est une texture elle peut être procédurale comme dans l'exemple montré ci-dessous avec un damier.

C'est à dire que les objets dans la scène contiennent des surfaces entièrement remplies de damiers noir et blanc qui forment des carrés et qui ont une taille. Pour que ce damier soit correctement bien posé sur l'objet, on doit déplier les coordonnées de texture afin que les coordonnées des sommets de l'objet coincident avec les uv de la texture.

On appelle cela le mapping. Plus la taille de la map est petite, plus la texture sera pixelisée et inversement.

Dans le jeu video, on travaillera avec des maps de 512*512 en moyenne pour avoir des qualités de rendus optimales dans le jeu. Au cinéma 3D, on peut se permettre de faire des maps de 2048*2048 voire encore plus grandes.

En fait, lorsqu'on fait un jeu video, il y a des contraintes à respecter, plus il y a de polygones au sein d'un même objet, plus il y a d'animation longue sur les objets, plus les textures sont lourdes, plus les performances du jeu seront diminuées. On parle de contrainte d'optimisation. Après, selon les modèles de carte graphique, le fps peut varier d'un pc à un autre.

Dans le deuxième exemple, j'ai chargé une texture de brique de type bmp. D'autres formats d'image peuvent être utilisés tels que le jpg, le targa, ou le png (utile pour la transparence).

Les règles à suivre pour intégrer une texture sur un objet dans opengl sont les suivantes:

activer le tampon de profondeur, activer la texture, créer un loader de texture pour gérer un format de texture, associer la texture aux coordonnées des sommets de l'objet puis désactiver la texture et répéter ce processus autant de fois que nécessaire pour charger à nouveau d'autres textures.

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<C:\freeglut\include\GL\freeglut.h> #include<C:\freeImage\x32\FreeImage.h> #include<math.h> #define pi 3.14159265359 // on definit un nombre pi

void dessinerdecor(); void dessiner(); void reshape(int width,int height); void gestionSpecial(int key,int x,int y); void passive(int key,int x,int y); void clavier();     bool up,down,right,left=false; void InitGL(); GLuint Nom;

GLubyte Texture[16] = { 0,0,0,0, 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF, 0,0,0,0 };

typedef struct robot robot; // on definit la structure de notre robot

struct robot { void dessin(); void tete(); void corps(); void bras(); void avantbras(); void jambe(); void avantjambe(); float animbras1; float animbras2; float animjambe1; float animjambe2; float anim; float animtete; float avancerX; float avancerY; float avancerZ; float Yrot; };

robot r;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode addfichage de glut glutInitWindowSize(960,540);// taille de la fenêtre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l'ecran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'écran glutSpecialFunc(gestionSpecial);// fonctions de gestion d'appuie des touches du clavier glutSpecialUpFunc(passive);// fonctions de relachement d'une touche du clavier InitGL(); glutMainLoop();// fonction d'appel en continu d'affichage dans main() return 0; }

     void InitGL() {     glClearColor(.9,.9,.9,0);    //Change la couleur du fond glEnable(GL_DEPTH_TEST);    //Active le depth test

glGenTextures(1,&Nom);    //Génère un n° de texture glBindTexture(GL_TEXTURE_2D,Nom);    //Sélectionne ce n° glTexImage2D ( GL_TEXTURE_2D,    //Type : texture 2D 0,    //Mipmap : aucun 4,    //Couleurs : 4 2,    //Largeur : 2 2,    //Hauteur : 2 0,    //Largeur du bord : 0 GL_RGBA,    //Format : RGBA GL_UNSIGNED_BYTE,    //Type des couleurs Texture    //Addresse de l'image );     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

}    

7 - exemple 7: (avec la texture)

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<stdio.h> #include<C:\freeglut\include\GL\freeglut.h> #include<math.h> #define pi 3.14159265359 // on definit un nombre pi

void dessinerdecor(); void dessiner(); void reshape(int width,int height); void gestionSpecial(int key,int x,int y); void passive(int key,int x,int y); void clavier();     bool up,down,right,left=false; void InitGL(); unsigned int Nom; BITMAPFILEHEADER bfh; BITMAPINFOHEADER bih; int iWidth; int iHeight; unsigned char * textureData; typedef struct robot robot; // on définit la structure de notre robot

struct robot { void dessin(); void tete(); void corps(); void bras(); void avantbras(); void jambe(); void avantjambe(); float animbras1; float animbras2; float animjambe1; float animjambe2; float anim; float animtete; float avancerX; float avancerY; float avancerZ; float Yrot; };

robot r;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode addfichage de glut glutInitWindowSize(960,540);// taille de la fenêtre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l'ecran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'écran glutSpecialFunc(gestionSpecial);// fonctions de gestion d'appui des touches du clavier glutSpecialUpFunc(passive);// fonctions de relachement d'une touche du clavier InitGL(); glutMainLoop();// fonction d'appel en continue d'affichage dans main() return 0; }

void bmpLoader(const char * name) {     FILE * file=0;     file=fopen(name,"rb");     if(!file)     {         printf("file not open");     }     fread(&bfh,sizeof(BITMAPFILEHEADER),1,file);     if(bfh.bfType!=0x4D42)     {         printf("erreur bitmap");     }     fread(&bih,sizeof(BITMAPINFOHEADER),1,file);     if(bih.biSizeImage==0)     {         bih.biSizeImage=bih.biHeight*bih.biWidth*3;     }     textureData=new unsigned char[bih.biSizeImage];     fseek(file,bfh.bfOffBits,SEEK_SET);     fread(textureData,1,bih.biSizeImage,file);     unsigned char temp;     for(int i=0;i<bih.biSizeImage;i+=3)     {         temp=textureData[i];         textureData[i]=textureData[i+2];         textureData[i+2]=temp;     }     iWidth=bih.biWidth;     iHeight=bih.biHeight;     fclose(file); } void loadTexture(const char * name) { bmpLoader(name); glGenTextures(1,&Nom);    //Génère un n° de texture glBindTexture(GL_TEXTURE_2D,Nom);    //Sélectionne ce n° glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB,iWidth,iHeight,GL_RGB,GL_UNSIGNED_BYTE,textureData);

    }     void InitGL() {     glClearColor(.9,.9,.9,0);    //Change la couleur du fond glEnable(GL_DEPTH_TEST);    //Active le depth test glEnable(GL_TEXTURE_2D);//active la texture loadTexture("data/mur.bmp");//charge la texture de type bmp

}    

8 - Les lumières

exemple 8:

Tout d'abord, les lumières sont un aspect important dans un jeu, sans lumière aucune forme ni volume ne pourrait être dessiné. C'est elle qui se charge d'assombrir ou d’éclaircir une couleur, on parle de valeur (nuance de gris).

Plus on est proche de 0, plus l'objet est sombre, la lumière n'éclaire pas, plus on est proche de l'indice 1, plus la lumière  éclaire, l'éclairage est alors au maximum.

Il existe plusieurs éclairages en opengl, on trouve notamment le système de point, le soleil, et les spots lumineux.

On peut placer en opengl une lumière de différentes façons. elle peut être placée à un endroit précis mais n'éclairera que cet endroit de manière exclusive. elle peut être également en mouvement c'est à dire tourner autour de la scène. on peut imaginer qu'a 5h de l'après-midi, le soleil diffusera une quantité de lumière sur le nord de la scène et qu' à minuit, le soleil diffusera une quantité de lumière dans le sud de la scène par exemple. Et enfin la lumière peut être placée en fonction du point de vue de la caméra, c'est à dire que peut importe l'endroit où on est dans la scène la lumière se déplace en même temps que la caméra.

En opengl, les étapes à suivre sont les suivantes, il faut activer l'éclairage (opengl est une librairie basée sur des états tout s'active tout se désactive), il faut ensuite spécifier quelle lumière utiliser (on peut jusqu'à 9 avec opengl). et ensuite dessiner une lumière dans la scène puis désactiver l'éclairage à la fin.

L'exemple qui nous est montré ci-dessous montre un éclairage basé sur le point de vue de la caméra.

 

#include <windows.h> #include <gl/gl.h> #include<gl/glu.h> #include<stdio.h> #include<C:\freeglut\include\GL\freeglut.h> #include<math.h> #define pi 3.14159265359 // on definit un nombre pi

void dessinerdecor(); void dessiner(); void reshape(int width,int height); void gestionSpecial(int key,int x,int y); void passive(int key,int x,int y); void clavier();     bool up,down,right,left=false; void InitGL(); unsigned int Nom; BITMAPFILEHEADER bfh; BITMAPINFOHEADER bih; int iWidth; int iHeight; unsigned char * textureData; typedef struct robot robot; // on définit la structure de notre robot

struct robot { void dessin(); void tete(); void corps(); void bras(); void avantbras(); void jambe(); void avantjambe(); float animbras1; float animbras2; float animjambe1; float animjambe2; float anim; float animtete; float avancerX; float avancerY; float avancerZ; float Yrot; };

robot r;

int main(int argc,char ** argv) {

glutInit(&argc,argv);//initilisation de glut glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);//mode addfichage de glut glutInitWindowSize(960,540);// taille de la fenetre glutCreateWindow("tuto01");// titre de l'application glutReshapeFunc(reshape);// configuration du mode de projection du pixel à l'ecran glutDisplayFunc(dessiner);// fonction d'affichage du dessin à l'ecran glutSpecialFunc(gestionSpecial);// fonctions de gestion d'appui des touches du clavier glutSpecialUpFunc(passive);// fonctions de relachement d'une touche du clavier InitGL(); glutMainLoop();// fonction d'appel en continue d'affichage dans main() return 0; }

void bmpLoader(const char * name) {     FILE * file=0;     file=fopen(name,"rb");     if(!file)     {         printf("file not open");     }     fread(&bfh,sizeof(BITMAPFILEHEADER),1,file);     if(bfh.bfType!=0x4D42)     {         printf("erreur bitmap");     }     fread(&bih,sizeof(BITMAPINFOHEADER),1,file);     if(bih.biSizeImage==0)     {         bih.biSizeImage=bih.biHeight*bih.biWidth*3;     }     textureData=new unsigned char[bih.biSizeImage];     fseek(file,bfh.bfOffBits,SEEK_SET);     fread(textureData,1,bih.biSizeImage,file);     unsigned char temp;     for(int i=0;i<bih.biSizeImage;i+=3)     {         temp=textureData[i];         textureData[i]=textureData[i+2];         textureData[i+2]=temp;     }     iWidth=bih.biWidth;     iHeight=bih.biHeight;     fclose(file); } void loadTexture(const char * name) { bmpLoader(name); glGenTextures(1,&Nom);    //Génère un n° de texture glBindTexture(GL_TEXTURE_2D,Nom);    //Sélectionne ce n° glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGB,iWidth,iHeight,GL_RGB,GL_UNSIGNED_BYTE,textureData);

    }     void InitGL() {     glClearColor(.1,.1,.1,0.1);    //Change la couleur du fond glEnable(GL_DEPTH_TEST);    //Active le depth test glEnable(GL_LIGHTING);//active la lumiere glEnable(GL_LIGHT0);//active la limiere n°1 glEnable(GL_TEXTURE_2D);//active la texture loadTexture("data/mur.bmp");//charge la texture de type bmp

}    

En vous remerciant d'avoir pris le temps de lire mon tutoriel!

Ancre 1
Ancre 2
Ancre 3
Ancre 4
Ancre 5
Ancre 6
Ancre 7
Ancre 8
bottom of page