You want to discover the world of 3D and video games, then this site is for you!
To do this, you will need a good knowledge of C and C++, and a good knowledge of mathematics.
OpenGL is a low-level graphics API for creating real-time 3D computer graphics.
This library offers many out-of-the-box functions.
We will study a series of progressive examples leading to the realization of complete games with OpenGL 2.0 (also known as the old OpenGL).
(also known as the old OpenGL).
Other extensions such as SDL, GLUT, GLEE, Freetype can be added to OpenGL in order to get more graphical features.
This section will deal with algorithmic geometry, i.e. the development of a software component that will manage animation, physics and real-time CGI processing.
Through these few examples, we will see the basics of graphical programming.
It's up to you...
Happy reading!!
Demo which shows the possibilities offered by OpenGL!!!
Summary:
- Initialization of the game engine with the GLUT library (creation of a window)
1 - Initialize OpenGL with GLUT
Example 1:
In this example, we'll see how to initialize a window with GLUT,
This is going to be our first render window, which is our start point.
The steps to follow are as follows:
//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
Example 2:
After having seen the initialization in GLUT, we must now understand how to display a pixel on the screen and therefore understand the process of rendering an image on the screen because for the moment our buffer is empty, the rendering does not display Nothing. When we talk about images, we must first learn how to display a pixel on the screen. A pixel is a point in 2D or 3D space. All of these points form a series of pixels, therefore a 2D image. Within a pixel, we can carry out operations, we talk about manipulating pixels. We can perform operations on graphic objects called transformation operations in a 2D or 3D space (rotations, changes of scale, translation).
A pixel made up of 3 points linked to 3 segments can form a full or empty surface. This surface contains two faces (also called normal): an interior normal and an exterior normal. On a pixel, we can emit a color which can be of RGB or RGBA type. On the computer, we say that we read values between 0 and 1. Each of these values corresponds to a color; the closer we are to index 1, the lighter the color, the closer we are to 0, the darker the color. We will see in the following chapters that we can store components other than colors within a pixel. When drawing in Opengl, we first start by emptying the buffers. This means that we must erase the window (black window) and then start drawing, which is the opposite of traditional drawing because the sheet initially is completely white. In fact, it is said that the pixels in the image restitution process are stored in buffers, there are several types (chromatic buffers....).
Then, you must define a projection mode, that is to say in which mode the pixel should be projected on the screen. There are two types of views, either an orthographic type view (2D projection), or a perspective type view (the object is projected in 3D). Then, you have to empty the matrix before starting to draw. A matrix is defined by a set of transformations (modeling transformations, projection transformations, visualization transformation) which are executed one after the other. All transformation operations are stored in matrices. In 3D we say that we work with 4*4 matrices. (W x Y Z). Each of these components must behave homogeneously. To separate two transformations, we use 2 matrices, an input and an output. We speak of matrix stacks when the number of matrices accumulates. Before drawing graphic objects (also known as modeling transformation), we must use the visualization transformation, i.e. define a point of view in our 3D scene. Then we return the object to the screen.
To do this, we start by saying what type of shape we want to display (polygon, triangle, quadrilateral). Then, we display each of the vertices which will constitute our future shape. Example method of displaying a vertex on the screen: matrix() rotation transformation scale transformation vertex display end of matrix 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
}
3 - Animate an object in GLUT
Example 3:
Animation in general is defined by a set of images which one after the other constitute a movement. In video games (real-time), we work on 60 frames per second on average and in cinema, 25 frames per second. (i.e. 1 second = 25 frames) In opengl, you have to constantly update the scene, that is to say that with each new state, you refresh the scene. Then, we must increment the position of our graphic object by 1 unit or more. x++ // here, we vary the position in X of our object by 1 unit In fact, x, y, and z are components of the modeling transformation. These are the components in which we can perform translation transformations. So we can move our mesh according to position x, y or z. To simplify things, we would have the possibility of storing our transformation in a vector which would contain each of the components of our transformation. let V(x,y,z);
It is important to note that each time we move an object it is important to refresh the scene. To call the procedure: glutPostRedisplay(); Just, in our example, the object will undergo x rotation every frame. Let's see an example:
#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 - GLUT primitives and display modes
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
}
Thanking you for taking the time to read my tutorial!