Programmation 3D avec OpenGL 4

Dimension: px
Commencer à balayer dès la page:

Download "Programmation 3D avec OpenGL 4"

Transcription

1 Programmation 3D avec OpenGL 4 Rémy Malgouyres LIMOS UMR 6158, IUT département info Université Clermont 1, B.P AUBIERE cedex. http ://

2 Une version PDF de ce document est téléchargeable sur mon site web, ansi que la version html. 2

3 Table des matières I Le mode de compatibilité 5 1 Interface SDL Mon premier affichage OpenGL avec la SDL Gestion des touches du clavier Événements souris Dessiner des formes de base Les primitives géométriques Variantes de glvertex*() et représentations des sommets Modes d affichage de polygones Représentation d un maillage Positioner caméras et objets Gérer la caméra et la perspective Coordonnées homogènes Changements de repère et coordonnées homogènes Caméras et projections Positionnement quelconque d une caméra Transformation de visualisation dans OpenGL Positionner un objet dans une scène Rotation, translation et changement d échelle Pile de matrices Éclairage Élimination des parties cachées Sources de lumière et matériaux Vecteurs normaux Éclairement plat et lissage de Gouraud Gérer la position et direction des sources lumineuses Textures Plaquage de textures avec OpenGL II Programmation par shaders et VBO 68 6 Initiation à GLSL Création d un programme OpenGL avec ses deux shaders

4 TABLE DES MATIÈRES 6.2 Mes premiers Shaders Interpolation des couleurs aux sommets Variables uniform Variables varying Matrices avec GLM 88 8 Vertex Buffer Objects (VBO) Vertex Buffer Objects avec attributs prédéfinis Attributs génériques Éclairement avec shaders et VBO Sources dans le repère de la caméra Sources dans le repère du monde Exemple d application : la bille, la goutte, la bulle Frame Buffer Objects Rendu dans une texture Exemple d application : post-processing Cartoon

5 Première partie Le mode de compatibilité 5

6 Chapitre 1 Interface SDL 1.1 Mon premier affichage OpenGL avec la SDL Le makefile permettant de compiler le premier programme exemple init_sdl.c ci-dessous contient le code suivant : init_sdl: init_sdl.c g++ init_sdl.c -o init_sdl -g -I /usr/local/include/sdl2/ \ -D_REENTRANT -L /usr/local/lib/ -lsdl2 -lgl -lglu -lglew Voici maintenant le code source de l exemple qui crée une fenêtre SDL et affiche un fond rouge. sdl/progc/init_sdl.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 10 GLushort l a r g e u r _ f e n e t r e =600 ; 11 GLushort hauteur_fenetre =600 ; brief Fonction d a f f i c h a g e a p p e l é e périodiquement */ 14 void A f f i c h a g e ( ) { 15 /* Couleur de fond rouge */ 16 /* c o e f f i c i e n t s RGB + A de l a c o u l e u r de fond : */ 17 g l C l e a r C o l o r ( 1. 0, 0. 0, 0. 0, 1. 0 ) ; 18 /* On e f f a c e l e contenu de l a f e n ê t r e */ 19 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 20 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 26 */ 6

7 Chapitre 1 : Interface SDL 27 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 28 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 29 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 30 SDL_Init (SDL_INIT_VIDEO) ; 31 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 32 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 33 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 34 return window ; 35 } int main ( int argc, char** argv ) 38 { 39 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 40 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 41 Premier programme OpenGL avec l a SDL ) ; 42 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 43 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 46 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 47 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* *****************************************************************\ 50 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 51 \***************************************************************** */ 52 bool terminer=f a l s e ; 53 SDL_Event evenements ; /* union contenant un évennement */ 54 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 57 while (! terminer ) 58 { 59 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 60 { 61 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 62 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 63 terminer = true ; 64 break ; 65 } 66 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 69 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 72 { 73 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 74 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 75 nbframes++ ; /* On incrémente l e compteur de frames */ 76 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 77 } 78 } 79 7

8 Rémy Malgouyres, Programmation 3D avec OpenGL 80 // L i b é r a t i o n des r e s s o u r c e s SDL 81 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 82 SDL_DestroyWindow ( window ) ; 83 SDL_Quit ( ) ; 84 return 0 ; 85 } La documentation complète sur les évennements SDL peut être consultée sur : Nous allons étudier ci-dessous quelques uns de ces évennements. 1.2 Gestion des touches du clavier Les événements liés aux touches du clavier peuvent être récupérés grace au type d évennement SDL_KEYDOWN. Exemple. Dans le programme suivant, la couleur du fond est grise de plus en plus claire lorsqu on appuie sur la flèche droite au clavier, et de plus en plus foncée lorsqu on appuie sur la flèche gauche. Le programme se termine lorsqu on appuie sur la touche 'q'. sdl/progc/sdlkey.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 10 GLushort l a r g e u r _ f e n e t r e =600 ; 11 GLushort hauteur_fenetre =600 ; void A f f i c h a g e ( GLfloat niveau_de_gris ) 14 { 15 /* c o e f f i c i e n t s RGB + A de l a c o u l e u r de fond : */ 16 g l C l e a r C o l o r ( niveau_de_gris, niveau_de_gris, niveau_de_gris, 0 ) ; 17 g l C l e a r (GL_COLOR_BUFFER_BIT) ; /* On e f f a c e */ 18 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 24 */ 25 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 26 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 27 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 28 SDL_Init (SDL_INIT_VIDEO) ; 29 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 30 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 8

9 Chapitre 1 : Interface SDL 31 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 32 return window ; 33 } int main ( int argc, char** argv ) 36 { 37 GLfloat niveau_de_gris =0.5 ; /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 40 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 41 Touches c l a v i e r avec l a SDL ) ; 42 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 43 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 46 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 47 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* *****************************************************************\ 50 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 51 \***************************************************************** */ 52 bool terminer=f a l s e ; 53 SDL_Event evenements ; 54 GLint currenttime, nextdueframedate = 0 ; int nbframes=0 ; 57 while (! terminer ) 58 { 59 while ( SDL_PollEvent(& evenements ) ) 60 { 61 switch ( evenements. type ) { 62 case SDL_KEYDOWN : /* Enfoncement d une touche */ 63 p r i n t f ( La touche %s a é t é enfoncée \n, 64 SDL_GetKeyName( evenements. key. keysym. sym) ) ; 65 switch ( evenements. key. keysym. sym) { 66 case SDLK_LEFT : /* touche f l è c h e à gauche */ 67 niveau_de_gris = ; 68 i f ( niveau_de_gris < 0) 69 niveau_ de_ gris = 0 ; 70 break ; 71 case SDLK_RIGHT : /* touche f l è c h e à d r o i t e */ 72 niveau_de_gris += ; 73 i f ( niveau_de_gris > 1) 74 niveau_ de_ gris = 1 ; 75 break ; 76 case SDLK_q : /* touche q, on q u i t t e */ 77 terminer = true ; 78 break ; 79 } 80 break ; 81 case SDL_QUIT : 82 terminer = true ; 83 break ; 84 } 9

10 Rémy Malgouyres, Programmation 3D avec OpenGL 85 } 86 currenttime = SDL_GetTicks ( ) ; i f ( currenttime > nextdueframedate ) 89 { 90 nextdueframedate = currenttime ; 91 A f f i c h a g e ( niveau_de_gris ) ; 92 nbframes++ ; 93 SDL_GL_SwapWindow( window ) ; 94 } 95 } // L i b é r a t i o n des r e s s o u r c e s SDL 98 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 99 SDL_DestroyWindow ( window ) ; 100 SDL_Quit ( ) ; 101 return 0 ; 102 } La liste complète des constantes symboliques représentant les touches du clavier sous SDL peut être trouvée sur : Événements souris Les événements souris sont de type MouseButtonEvent pour l enfoncement et le relachement d un bouton et MouseMotionEvent pour le mouvement de la souris. Exemple. Dans le programme suivant, lorsqu on déplace la souris vers la droite, la couleur du fond devient plus bleue. Lorsqu on déplace la souris vers la gauche la couleur du fond devient moins bleue. Lorsqu on déplace la souris vers le haut, la couleur du fond devient plus verte. Lorsqu on déplace la souris vers le bas, la couleur du fond devient moins verte. sdl/progc/sdlmouse.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 11 GLushort l a r g e u r _ f e n e t r e =600 ; 12 GLushort hauteur_fenetre =600 ; void A f f i c h a g e ( GLfloat coef_g, GLfloat coef_b ) 15 { 16 /* c o e f f i c i e n t s RGB + A de l a c o u l e u r de fond : */ 17 g l C l e a r C o l o r ( 0. 0, coef_g, coef_b, 0. 0 ) ; 18 g l C l e a r (GL_COLOR_BUFFER_BIT) ; /* On e f f a c e */ 19 } 20 10

11 Chapitre 1 : Interface SDL 21 brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 25 */ 26 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 27 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 28 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 29 SDL_Init (SDL_INIT_VIDEO) ; 30 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 31 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 32 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 33 return window ; 34 } int main ( int argc, char** argv ) 37 { GLfloat coef_g =0.5, coef_b =0.5 ; /* c o e f f i c i e n t s G,B de l a c o u l e u r */ 40 GLushort mousex, mousey ; /* permet de mémoriser l a d e r n i è r e p o s i t i o n */ 41 /* de l a s o u r i s */ 42 bool l e f t B u t t o n P r e s s e d = f a l s e ; 43 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 44 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 45 Gestion de l a s o u r i s avec l a SDL ) ; 46 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 47 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 50 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 51 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* *****************************************************************\ 55 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 56 \***************************************************************** */ 57 bool terminer=f a l s e ; 58 SDL_Event evenements ; 59 GLint currenttime, nextdueframedate = 0 ; int nbframes=0 ; 62 while (! terminer ) 63 { 64 while ( SDL_PollEvent(& evenements ) ) 65 { 66 switch ( evenements. type ) { 67 case SDL_MOUSEBUTTONDOWN : /* Enfoncement d un bouton s o u r i s */ 68 switch ( evenements. button. button ) { 69 case SDL_BUTTON_LEFT : /* Bouton gauche */ 70 l e f t B u t t o n P r e s s e d=true ; 71 mousex = evenements. button. x ; /* mémorisation coordonnées de l a s o u r i s */ 72 mousey = evenements. button. y ; /* mémorisation coordonnées de l a s o u r i s 11

12 Rémy Malgouyres, Programmation 3D avec OpenGL */ 73 break ; 74 } 75 break ; 76 case SDL_MOUSEBUTTONUP : /* Relachement d un bouton s o u r i s */ 77 switch ( evenements. button. button ) { 78 case SDL_BUTTON_LEFT : /* Bouton gauche */ 79 l e f t B u t t o n P r e s s e d=f a l s e ; 80 break ; 81 } 82 break ; 83 case SDL_MOUSEMOTION : /* Mouvement de l a s o u r i s */ 84 i f ( l e f t B u t t o n P r e s s e d ) { 85 coef_b += * ( evenements. motion. x mousex ) ; 86 i f ( coef_b > 1) 87 coef_ b = 1 ; 88 i f ( coef_b < 0) 89 coef_ b = 0 ; 90 coef_g += * ( evenements. motion. y mousey ) ; 91 i f ( coef_g > 1) 92 coef_ g = 1 ; 93 i f ( coef_g < 0) 94 coef_ g = 0 ; 95 mousex = evenements. motion. x ; /* e n r e g i s t r e m e n t des n o u v e l l e s */ 96 mousey = evenements. motion. y ; /* coordonnées de l a s o u r i s */ 97 } 98 break ; 99 case SDL_QUIT : 100 terminer = true ; 101 break ; 102 } 103 } 104 currenttime = SDL_GetTicks ( ) ; i f ( currenttime > nextdueframedate ) 107 { 108 nextdueframedate = currenttime ; 109 A f f i c h a g e ( coef_g, coef_b ) ; 110 nbframes++ ; 111 SDL_GL_SwapWindow( window ) ; 112 } 113 } // L i b é r a t i o n des r e s s o u r c e s SDL 116 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 117 SDL_DestroyWindow ( window ) ; 118 SDL_Quit ( ) ; 119 return 0 ; 120 } 12

13 Chapitre 2 Dessiner des formes de base La principale opération d affichage est le dessin d un polygone (triangle, quadrilatère,...) à l écran. En effet, lorsqu on souhaite représenter une surface autre qu un polygone, on doit approcher cette surface par un maillage composé de polygones (voir la figure 2.1 et la figure 2.2). (a) Exemple de surface (b) Aproximation par un maillage Figure 2.1 : L approximation d une surface par des polygones (maillage de surface). Le code présenté ici est accessible dans OpenGL 4 via le mode de compatibilité. Cette manière de coder avec OpenGL avait été supprimée dans OpenGL 3 car jugée trop lente mais a été réintroduite dans OpenGL 4 sous forme de mode de compatibilité car l abord direct d OpenGL par les shaders et VBO est trop ardu. Nous présentons d ailleurs en premier le mode de compatibilité pour des raisons pédagogiques. Par contre, les différents primitives géométriques (aussi appelées éléments) sont les mêmes dans la programmation par VBO et dans le mode de compatibilité. 2.1 Les primitives géométriques Lorsqu on décrit un polygone, on doit mettre les sommets du polygone entre un appel à la fonction glbegin() et un appel à glend(). Plusieurs primitives géométriques peuvent être 13

14 Rémy Malgouyres, Programmation 3D avec OpenGL Figure 2.2 : Exemple de maillage : reconstruction du Stanford Bunny. dessinées, suivant l argument passé à glbegin() (voir la figure 2.3). 14

15 Chapitre 2 : Dessiner des formes de base Exemple 1. Pour dessiner un triangle rempli, on peut faire : glbegin(gl_triangles); glvertex2f(0.0, 0.0); glvertex2f(1.0, 0.0); glvertex2f(0.0, 1.0); glend(); Exemple 2. Pour dessiner un hexagone régulier rempli, on peut faire (en incluant la bibliothèque math.h) : GLint i; glbegin(gl_polygon); for (i=0 ; i<6 ; i++) glvertex2f(cos(2*i*m_pi/6), sin(2*i*m_pi/6)); glend(); 15

16 Rémy Malgouyres, Programmation 3D avec OpenGL V 1 V 3 V 5 V 0 V 2 (a) GL_POINTS V 4 V 1 V 2 V 1 V 3 V 5 V 1 V 3 V 5 V 3 V 0 V 4 V 0 V 2 V 4 V 0 V 2 V 4 V 5 (b) GL_LINES (c) GL_LINE_STRIP (d) GL_LINE_LOOP V 1 V 2 V 3 V 1 V 3 V 5 V 1 V 3 V 5 V 0 V 4 V 0 V 2 V 4 V 0 V 2 V 4 V 5 (e) GL_TRIANGLES (f) GL_TRIANGLE_STRIP (g) GL_TRIANGLE_FAN V 2 V 1 V 3 V 3 V 2 V 5 V 6 V 3 V 5 V 1 V 7 V 0 V 0 V 1 V 4 V 7 V 0 V2 V 4 V 6 V 5 V 4 (h) GL_QUADS (i) GL_QUAD_STRIP (j) GL_POLYGON Figure 2.3 : Types de primitives géométrique. Le polygone doit être convexe. 16

17 Chapitre 2 : Dessiner des formes de base Les arguments possibles pour la fonction glbegin(), qui correspondent à différentes primitives géométriques, sont : GL_POINTS : seuls des points sont dessinés. (L épaisseur des points peut être réglée avec la fonction glpointsize()). GL_LINES : Des segments de droites sont dessinées entre V 0 et V 1, entre V 2 et V 3, etc., les V i étant les sommets successifs définis par des appels à glvertex*(). (L épaisseur des droites peut être réglée avec la fonction gllinewidth). GL_LINE_STRIP : Une ligne polygonale est tracée. GL_LINE_LOOP : Une ligne polygonale fermée est tracée. GL_TRIANGLES : des triangles sont dessinés entre les trois premiers sommets, entre les trois suivants, etc... Si le nombre de sommets n est pas multiple de 3, les 1 ou 2 derniers sommets sont ignorés. GL_TRIANGLE_STRIP : Des triangles sont dessinés entre V 0, V 1, V 2, puis entre V 1, V 2, V 3, entre V 2, V 3, V 4, etc. GL_TRIANGLE_FAN : Un éventail est dessiné formé des triangles V 0, V 1, V 2, puis V 0, V 2, V 3, etc. GL_QUADS : Un quadrilatère est un polygone à 4 sommets. Des quadrilatères sont dessinés entre les quatre premiers sommets, puis entre les 4 suivants, etc. GL_QUAD_STRIP : Une série de quadrilatères sont dessinés entre V 0, V 1, V 3, V 2, puis, V 2, V 3, V 5, V 4, puis V 4, V 5, V 7, V 6, etc. GL_POLYGON : Un polygone fermé rempli est déssiné. Le polygone doit être convexe faute de quoi le comportement est indéfini (dépend de l implémentation). 2.2 Variantes de glvertex*() et représentations des sommets Lorsqu on spécifie un sommet, celui-ci est toujours dans l espace à trois dimensions R 3. On peut spécifier, 2, 3, ou même 4 coordonnées pour un point. Lorsqu on ne spécifie que 2 des coordonnées, la troisième coordonnée est considérée comme valant 0 (point situé dans le plan xoy). Lorsqu on spécifie 4 coordonnées, il s agit de la représentation du point en coordonnées homogènes (voir la partie 3.2). De plus, on peut spécifier les coordonnées soit par une liste de paramètres, soit par un tableau (vecteur) de coordonnées. Enfin, les coordonnées peuvent être de différents types (GLint, GLfloat, GLdouble, etc.) À chacune de ces options correspond une fonction glvertex*() : glvertex2f : deux paramètres flottants en simple précision de type GLfloat (la troisième coordonnée vaut 0) ; glvertex3f : trois paramètres flottants en simple précision (la troisième coordonnée vaut 0) 17

18 Rémy Malgouyres, Programmation 3D avec OpenGL V 0 V 4 V 0 V 1 V 3 V 2 V 1 V 2 (a) Sens GL_CCW (counterclockwise) V 4 V 3 (b) Sens GL_CW (clockwise) Figure 2.4 : Orientation d un polygone. Par défaut, la vue de face correspond au cas GL_CCW glvertex2fv : un paramètre de type tableau de 2 GLfloats. glvertex3fv : un paramètre de type tableau de d GLfloats. glvertex2d, glvertex3d, glvertex2dv, glvertex3dv : similaires aux précédents mais avec des floats en double précision de type GLdouble. glvertex2i, glvertex3i, glvertex2di, glvertex3di : similaires aux précédents mais avec des entiers 32 bits de type GLint. 2.3 Modes d affichage de polygones Les polygones en 3D ont deux cotés : le devant et le derière. Par défaut, un polygone est vu de face (voir la figure 2.4) si sa projection dans la fenêtre graphique voit la liste de se sommets dans l odre positif trigonométrique (on peut changer ce comportement avec la fonction glfrontface). On peut spécifier un mode d affichage différents pour les polygones vus de face et pour les polygones vus de dos par la fonction glpolygonmode. \void glpolygonmode(glenum face, GLenum mode); face peut être GL_FRONT, GL_BACK ou GL_FRONT_AND_BACK ; mode peut être GL_POINT (dessin uniquement des sommets du polygone), GL_LINE (dessin des contours du polygone) ou GL_FILL (dessin du polygone avec remplissage). Enfin, on peut éliminer les faces (par exemple) qui sont vues de dos pour accélérer l affichage, (si l objet est fermé et vu de l extérieur, on sait qu aucune face vue de dos ne sera visible car elles seront cachées par d autres faces. Pour cela, il faut activer le culling par glenable(gl_cull_face); et indiquer le type de polygones à éliminer par l usage de la fonction void glcullface(glenum mode). face peut être GL_FRONT, GL_BACK ou GL_FRONT_AND_BACK. 18

19 Chapitre 2 : Dessiner des formes de base 2.4 Représentation d un maillage Définition d un maillage Un maillage P dans l espace tridimensionnel R 3 est la donnée de : 1. Une suite de points P 0, P 1,..., P n 1 de R 3 appelés sommets du maillage ; 2. Un ensemble de faces, chaque face étant une suite de numéros de sommets dans {0,..., n 1} Exemple Figure 2.5 : Exemple de maillage : un tétraèdre. Par exemple, considérons le tétraèdre construit sur les quatre points A = (400, 400, 10), B = (700, 700, 10), C = (0, 500, 10) et D = (500, 0, 500) (voir figure 2.5). Le maillage correspondant est la donnée de : 1. Les sommets P 0 = A, P 1 = B, P 2 = C, et P 3 = D ; 2. Les quatre faces qui sont : La face numéro 0 représentant le triangle OAB : (0, 1, 2) ; La face numéro 1 représentant le triangle OAC : (0, 1, 3) ; La face numéro 2 représentant le triangle OBC : (0, 2, 3) ; La face numéro 3 représentant le triangle ABC : (1, 2, 3). Voici un programme affichant le tétraèdre comme représenté sur la figure 2.5 : 1 #include <s t d l i b. h> 2 #include <SDL2/SDL. h> 3 #include <SDL2/ SDL_opengl. h> polygon/progc/exmaillage.c 19

20 Rémy Malgouyres, Programmation 3D avec OpenGL 4 #include <GLES3/ g l 3. h> 5 #include <s t d i o. h> 6 7 /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 8 GLushort l a r g e u r _ f e n e t r e =700 ; 9 GLushort hauteur_fenetre =700 ; 10 GLint n v e r t i c e s =4, n f a c e s =4 ; GLfloat v e r t i c e s [ ] [ 3 ] = { 13 { , , 10.0}, 14 { , , 10.0}, 15 { 0. 0, , 10.0}, 16 { , 0. 0, 500.0} 17 } ; GLuint f a c e s [ ] [ 3 ] = { 20 {0, 1, 2}, 21 {0, 1, 3}, 22 {0, 2, 3}, 23 {1, 2, 3} 24 } ; void A f f i c h a g e ( void ) 27 { 28 int i, j ; 29 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 30 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 31 g l C o l o r 3 f ( 0. 0, 0. 0, 0. 0 ) ; 32 gllinewidth ( 2 ) ; 33 glbegin (GL_TRIANGLES) ; 34 for ( i =0 ; i<n f a c e s ; i++) 35 for ( j=0 ; j <3 ; j++) 36 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 37 glend ( ) ; 38 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 44 */ 45 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 46 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 47 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 48 SDL_Init (SDL_INIT_VIDEO) ; 49 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 50 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 51 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 52 return window ; 53 } int main ( int argc, char** argv ) 56 { 20

21 Chapitre 2 : Dessiner des formes de base 57 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 58 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 59 Dessin d un t é t r a è d r e ) ; 60 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 61 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 64 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 65 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; glpolygonmode (GL_FRONT_AND_BACK, GL_LINE) ; /* D é f i n i t i o n du volume v i s i b l e */ 70 /* Nécessaire pour a f f i c h e r des o b j e t s géométriques */ 71 /* v o i r Chapitre s u i v a n t pour p e r s o n a l i s e r */ 72 glmatrixmode (GL_PROJECTION) ; 73 g l L o a d I d e n t i t y ( ) ; 74 glortho ( 0, l a r g e u r _ f e n e t r e, 0, hauteur_fenetre, 1, 600) ; 75 glmatrixmode (GL_MODELVIEW) ; 76 g l L o a d I d e n t i t y ( ) ; /* *****************************************************************\ 79 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 80 \***************************************************************** */ 81 bool terminer=f a l s e ; 82 SDL_Event evenements ; /* union contenant un évennement */ 83 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 86 while (! terminer ) 87 { 88 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 89 { 90 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 91 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 92 terminer = true ; 93 break ; 94 } 95 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 98 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 101 { 102 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 103 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 104 nbframes++ ; /* On incrémente l e compteur de frames */ 105 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 106 } 107 } // L i b é r a t i o n des r e s s o u r c e s SDL 110 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 111 SDL_DestroyWindow ( window ) ; 112 SDL_Quit ( ) ; 21

22 Rémy Malgouyres, Programmation 3D avec OpenGL 113 return 0 ; 114 } 22

23 Chapitre 3 Positioner caméras et objets 3.1 Gérer la caméra et la perspective 3.2 Coordonnées homogènes Définition des coordonnées homogènes On introduit un système de coordonnées différent des coordonnées cartésiennes pour repérer les points dans l espace 3D. Pour celà, on ajoute une composante W non nulle aux trois composantes (x, y, z). Ainsi, un point M de l espace 3D sera repéré en coordonnées homogènes par un quadruplet : M(x, y, z, W ) Les coordonnées de M ne sont pas uniques, mais deux quadruplets (x, y, z, W ) et (x, y, z, W ) représentent le même point si ces quadruplets sont multiples l un de l autre (liés dans R 3 ). Connaissant les coordonnées cartésiennes (x, y, z) d un point M, on peut obtenir un représentant de M en coordonnées homogènes par (x, y, z, 1) (c est à dire que W = 1). Connaissant un représentant (x, y, z, W ) de M en coordonnées homogènes, on peut obtenir les coordonnées cartésiennes de M par M = ( x W, y W, z W ). L intérêt de représenter les points par des coordonnées homogènes est de pouvoir représenter toute application affine par une seule matrice, comprenant la partie linéaire et la translation Coordonnées homogènes et applications affines Pour effectuer une translation T de vecteur v = (x v, y v, z v ) en coordonnées homogènes, il suffit de faire une multiplication matricielle : x x v x x + x v y T z = y v z v. y z = y + y v z + z v Pour appliquer une application linéaire f dont la matrice en coordonnées cartésienne est : a 1,1 a 1,2 a 1,3 M f = a 2,1 a 2,2 a 2,3 a 3,1 a 3,2 a 3,3 23

24 Rémy Malgouyres, Programmation 3D avec OpenGL il suffit de faire en coordonnées homogènes la multiplication matricielle par la matrice M f = a 1,1 a 1,2 a 1,3 0 a 2,1 a 2,2 a 2,3 0 a 3,1 a 3,2 a 3, N importe quelle application affine, composée d une application linéaire et d une translation, peut être obtenue en coordonnées homogènes par la multiplication par une matrice : M = a 1,1 a 1,2 a 1,3 x v a 2,1 a 2,2 a 2,3 y v a 3,1 a 3,2 a 3,3 z v La matrice en coordonnées homogènes M f g de la composée de deux application affines f et g est le produit M f.m g des matrices associées aux applications affines en coordonnées homogènes. De même, la matrice M f 1 en coordonnées homogènes de l inverse d une application affine bijective est l inverse M 1 f de la matrice de cette application affine. 3.3 Changements de repère et coordonnées homogènes Si l on se donne deux repères affines (O, ı, ȷ, k ) et (O, ı 1, ȷ 1, k 1 ) tels que ı1 = a 1,1 ı + a2,1 ȷ + a3,1 k ȷ1 = a 1,2 ı + a2,2 ȷ + a3,2 k, k1 = a 1,3 ı + a2,3 ȷ + a3,3 k On peut calculer les coordonnées X, Y et Z du point P dans le deuxième repère à partir des coordonnées x, y et z dans le premier repère. En notant M = a 1,1 a 1,2 a 1,3 a 2,1 a 2,2 a 2,3 a 3,1 a 3,2 a 3,3 la matrice de passage du changement de base, la matrice de passage M est automatiquement inversible. En notant (O x, O y, O z) les coordonnées du point O dans le repère (O, ı, ȷ, k ), on a : X Y Z = M 1. x y z En inversant les formules, on peut aussi calculer les coordonnées x, y et z dans le premier repère en fonction des coordonnées X, Y et Z dans le second repère : x y z = M. X Y Z O x O y O z O x O y O z.

25 Chapitre 3 : Positioner caméras et objets A B C A B C A A C B C B Plan de projection Plan de projection (a) La projection parallèle Centre de projection (b) La projection en perspective Figure 3.1 : Les deux principaux types de projection. Ces formules sont des formules de transformations affines qui s écrivent en coordonnées homogènes x y z 1 = a 1,1 a 1,2 a 1,3 O x a 2,1 a 2,2 a 2,3 O y a 3,1 a 3,2 a 3,3 O z Un changement de repère affine consiste donc en une multiplication matricielle en coordonnées homogènes. 3.4 Caméras et projections Nous voyons ici comment projeter des données 3D sur un plan dans le but de visualiser ces données. Nous considérons ici des projections très particulières, le plan sur lequel on projette étant perpendiculaire au troisième axe de coordonnées Oz. Ceci correspondra au point de vue très particulier d un observateur placé sur l origine O et regardant dans la direction de l axe des z. Par des changements de repères appropriés, on remène le cas d un point de vue quelconque de l observateur au cas particulier traité ici Projection parallèle La projection parallèle est la projection sur un plan parallèlement à une direction (voir figure 3.1a). Cette projection correspond à un observateur placé à l infini. Elle est simple, mais n est pas très réaliste. Plaçons nous dans un repère (O, ı, ȷ, k ) tel que le plan de projection soit le plan z = 0 et la direction de projection soit parallèle au vecteur k. Pour obtenir le projeté d un point (x, y, z), il suffit d oublier la coordonnée z : Le projeté a pour coordonnées : x p = x, y p = y, z p = 0. Les formules de cette projection sont donc particulièrement simples Projection en perspective Dans le modèle de caméra Pinhole, il y a un centre de projection (voir figure 3.1b), qui correspond à la position de l observateur. Ce modèle de caméra est plus réaliste que le modèle avec 25 X Y Z 1

26 Rémy Malgouyres, Programmation 3D avec OpenGL Figure 3.2 : Le modèle de caméra pinhole projection parallèle. Par contre, les formules donnant les coordonnées du projeté (x p, y p, z p ) d un point en fonction des coordonnées (x, y, z) du point sont un peu plus compliquées Calcul des coordonnées du projeté d un point Plaçons nous dans un repère (O, ı, ȷ, k ) lié à la caméra, tel que le plan de projection soit le plan d équation z = d et tel que le centre de projection ait pour coordonnées (0, 0, 0) (voir figure 3.2). La troisième coordonnée z p du projeté sera évidemment égale à d de part la définition du plan de projection. D après le théorème de Thalès (voir figure 3.3), on a : (x,y,z) (x p,y p,d) C = (0,0,0) z Plan de l écran d Figure 3.3 : Calcul des coordonnées du projeté. 26

27 Chapitre 3 : Positioner caméras et objets d = x et z En multipliant ces égalités par d, on obtient : x p y p d = y z x p = x d et y p = y d z z En coordonnées homogènes, ces formules s écrivent : x p y p z p 1 = x d z y d z d 1 x y z z d D où, x p y p z p 1 = M. x y z 1 avec M = d 0 La projection en perspective s exprime donc par la multiplication par une matrice en coordonnées homogènes Caméra Pinhole Une caméra Pinhole est une spécification d un point de vue de l observateur avec projection en perspective. L idée est celle d un observateur regardant une scène à travers un trou d épingle (pin hole en anglais), qui est le centre de projection. Cela correspond à l un des tout premiers modèles historiques d appareil photo. On se place ici dans le cas où la caméra est placé sur le point O = (0, 0, 0), la direction de visée étant l axe des z. Nous avons vu dans la partie comment calculer les coordonnées du projeté d un point en fonction du paramètre d donnant l équation z = d du plan de projection. Cependant, dans une application graphique 3D, le paramètre d n est pas donné directement, mais doit être déterminé à partir de l angle d ouverture θ c de la caméra et la largeur dim x de l image à calculer. L angle d ouverture θ c est l angle sous lequel l observateur placé en O = (0, 0, 0) doit voir le rectangle de largeur dim x constitué par l image à calculer, ce rectangle étant placé dans le plan z = d centré au point A = (0, 0, d) (voir la figure 3.4). On peut calculer comme suit la valeur de d à partir de θ c et dim x. Soit B = ( dim x, 0, d) le point de l image à calculer situé le plus à droite par rapport à 2 l observateur. Le triangle OAB est rectangle en A, et l angle en O de ce triangle est égal à θc. 2 On a donc d = OA = AB tan( θc ) = dim x 2 tan( θc )

28 Rémy Malgouyres, Programmation 3D avec OpenGL dim x A B θ c d O Figure 3.4 : Calcul de la profondeur d du plan de l écran j1 k O k k1 ı1 ı O C j Figure 3.5 : Le repère lié à la caméra 3.5 Positionnement quelconque d une caméra Repère lié à une caméra En synthèse d images, on considère des caméras, qui définissent le point de vue à partir duquel l observateur voit la scène. Chaque modèle de caméra correspond à un type de projection dans l espace. Nous avons vu dans la partie 3.4 qu il existe principalement deux types de projection, la projection parallèle et la projection en perspective. Les algorithmes d affichage 3D supposent que la caméra (ou l observateur) est placé au point O = (0, 0, 0), et regarde dans la direction de l axe Oz. Cette hypothèse peut être reformulée comme suit : les coordonnées qui définissent les objets (coordonnées des sommets de polyèdres), et les coordonnées des vecteurs normaux aux sommets de polyèdres, sont calculées dans un repère lié à la caméra (voir les figures 3.5 et 3.10 ). Une scène 3D possède un repère fixe (O, ı, ȷ, k ) dans lequel l utilisateur définit les objets, les sources lumineuses, et la position de la caméra. Ce repère s appelle le repère de la scène, ou le repère du monde. La caméra possède un repère (O, ı 1, ȷ 1, k 1 ) qui lui est propre, appelé repère de la caméra, dont l origine O coïncide avec la position de la caméra, et tel que la direction k 1 du troisième axe de coordonnée coïncide avec la direction de visée de la caméra. On associe donc à la caméra une matrice M = (a i,j ) i,j=1,2,3 telle que : ı1 = a 1,1 ı + a2,1 ȷ + a3,1 k ȷ1 = a 1,2 ı + a2,2 ȷ + a3,2 k k1 = a 1,3 ı + a2,3 ȷ + a3,3 k 28

29 Chapitre 3 : Positioner caméras et objets Rappelons que M est la matrice de passage du repère de la scène au repère de la caméra Initialisation d une caméra Le but de cette partie est d expliquer comment on peut calculer la matrice M = (a i,j ) i,j=1,2,3 d une caméra à partir de la position et du point de focalisation (le centre) de cette caméra. Soit O la position d une caméra et C un point, appelé le centre de la caméra, vers lequel est dirigé la caméra. Calculer les coefficients (a i,j ) de la matrice M associée à la caméra revient à calculer les coordonnées des vecteurs ı 1, ȷ 1 et k 1 dans le repère (O, ı, ȷ, k ) de la scène. Le vecteur k 1 du repère de la caméra, qui est le vecteur unitaire dans la direction de visée, est égal à k1 = O C O C Nous avons un choix pour définir les deuxième et troisième vecteur du repère de la caméra. En effet, pour le moment, nous n avons pas fixé exactement la position de la caméra, qui peut tourner autour de l axe O C. Nous allons fixer le vecteur ı 1 de sorte que l axe des X du repère de la caméra soit perpendiculaire à l axe des z du repère de la scène. De cette manière, l axe des z de la scène apparaîtra vertical lors de l affichage, ce qui est assez naturel. Le vecteur ı 1 doit donc être orthogonal au troisième vecteur k du repère de la scène. De plus, le vecteur ı 1 doit être orthogonal au vecteur k 1 de la direction de visée, puisque nous souhaitons obtenir un repère (O, ı 1, ȷ 1, k 1 ) orthonormé. Nous n avons pas beaucoup de choix, et nous définirons donc k1 k ı1 = k 1 k Enfin, le vecteur ȷ 1 doit être à la fois orthogonal à ı 1 et k 1, de manière à ce que le repère (O, ı 1, ȷ 1, k 1 ) soit orthonormé direct. On a donc : k1 ı 1 ȷ1 = k 1 ı Transformation des objets dans le repère de la caméra Une fois la matrice M associée à la caméra initialisée, dans le but d utiliser les algorithmes d affichage, nous devons exprimer les coordonnées des sommets, ainsi que les vecteurs normaux aux sommets dans le cas d une utilisation du modèle de Phong, dans le repère de la caméra. Pour cela, on utilise simplement les formules de changement de base pour calculer les coordonnées (X, Y, Z) des sommets dans le repère de la caméra à partir de ses coordonnées (x, y, z) dans le repère de la scène. Les coordonnées de la position des sources lumineuses doivent subir la même transformation. 3.6 Transformation de visualisation dans OpenGL Principe des transformations géométriques dans OpenGL Avant d être affiché à l écran, un objet subit plusieurs transformations (voir la figure 3.6). Dans l ordre chronologique, OpenGL effectue les transformations suivantes : 29

30 Rémy Malgouyres, Programmation 3D avec OpenGL 1. La transformation du modèle : les objets graphiques sont définis dans un repère ou ils sont simples à concevoir, puis on transforme ces objets par des rotations, translations et changements d échelle (affinités) pour les mettre dans le repère du monde. On fait subir ces transformations aux objets au moyen des fonctions glrotatef, gltranslatef et glscalef dans le mode GL_MODELVIEW. 2. La transformation de la caméra : une fois dans le repère du monde, tous les objets subissent un changement de repère vers le repère de la caméra. On fait subir cette transformation aux objets au moyen des fonctions glulookat, glrotatef, gltranslatef et glscalef dans le mode GL_MODELVIEW. 3. Projection : une fois dans le repère de la caméra, les objets subissent une projection vers une image 2D (dans un buffer OpenGL). Pour régler les paramètres de cette projection, on utilise la fonction gluperspective dans le mode GL_PROJECTION. 4. Transformation 2D : une fois générée l image 2D dans un buffer, elle subit des changement d échelle sur les axes (affinités orthogonales) pour être ajustée aux dimensions de la fenêtre graphique à l écran. Cette dernière transformation est paramétrée par la fonction glviewport. Le principe de ces transformations est très général, nous donons dans la suite une utilisation de base des fonctionalités d OpenGL en la matière Paramètres de la caméra Dans la fonction de redimensionnement, appelée suite à un événement SDL de type SDL_WINDOWEVENT qui se produit lors de l intialisation ou le redimantionnement de la fenêtre (par l utilisateur ou le programmeur), On peut réglér les paramètres de la projection et de la transformation 2D a La fonction glviewport En général il n est pas commode de créer toutes les scènes de façon à ce qu elles se projettent directement sur la fenêtre graphique. On préfère utiliser des coordonnées normalisées dans le plan (par exemple avec des coordonnées allant de 1 à +1). La fonction glviewport spécifie une transformation affine pour passer des coordonnées 2D de l image calculée aux coordonnées (en nombre de pixels) de la fenêtre (voir la figure 3.7). Ceci permet de choisir la portion du plan 2D qui sera visible. La fonction glviewport a pour prototype : void glviewport(glint x0, GLint y0, GLsizei dimx, GLsizei dimy); où (x 0, y 0 ) sont les coordonnées du milieu de la portion de plan visible souhaitée ; L et H sont respectivement la largeur et la hauteur de la portion de plan visible souhaitée. La transformation est X fenetre = (x normalise + 1) dim x 2 + x 0 30

31 Chapitre 3 : Positioner caméras et objets Y fenetre = (y normalise + 1) dim y + y 0 2 Pour que l aspect des objets soit préservé par la transformation c est à dire pour que le changement d échelle soit le même en x et en y, il faut que les rapports suivants soient égaux : dim x = largeur_fenetre dim y hauteur_fenetre On note aspect = dim x dim y b La fonction gluperspective La fonction gluperspective permet de régler les caractéristiques de la céméra (voir la figure 3.8) telles que l angle d ouverture θ y (en y). Lorsqu on affiche une scène avec OpenGL, seule une partie de la scène est visible. La partie qui 1. Se projette dans la portion de plan visible (de taille dim x dim y ) ; 2. Est comprise entre deux plans z = z proche et z = z eloigne. Le prototype de la fonction gluperspective est le suivant : void gluperspective(gldouble theta_y, GLdouble aspect, GLdouble z_proche, GLdouble z_eloigne) Avant d utiliser gluperspective, il faut passer en mode GL_PROJECTION, et il faut réinitialiser la transformation de projection à l identité. En général, on appelle les fonctions glviewport et gluperspective dans la fonction de redimentionnement de la fenêtre. Pour celà, au niveau de la SDL on ajoute une option SDL_WINDOW_RESIZABLE dans la fonction SDL_CreateWindow, puis on gère l évennement SDL_WINDOWEVENT en appelant la fonction de redimentionnement avec le code OpenGL qui adapte la perspective.... GLdouble theta_y=45;... Modifie l'affichage pour l'adapter à un redimensionnement de la l nouvelle largeur de la h nouvelle hauteur de la fenêtre */ void Redimensionnement(int l, int h) { /* l et h sont les nouvelles dimensions de la fenêtre */ largeur_fenetre = l; /* mise à jour des variables */ 31

32 Rémy Malgouyres, Programmation 3D avec OpenGL objets graphiques transformation du modèle transformation de la caméra projection transformation 2D image à l écran glrotatef gltranslatef glscalef glulookat glrotatef gluperspective glviewport gltranslatef glscalef Figure 3.6 : Les transformations géométriques subies par les objets avant affichage largeur fenetre dimy dim x (x 0,y 0 ) transformation 2D hauteur fenetre (0,0) Figure 3.7 : Les paramètres de glviewport Figure 3.8 : Les paramètres de gluperspective 32

33 Chapitre 3 : Positioner caméras et objets } hauteur fenetre = h; glviewport(0,0,(glsizei)largeur_fenetre,(glsizei)hauteur_fenetre); glmatrixmode(gl_projection); /* passage en mode GL_PROJECTION */ glloadidentity(); /* réinitialisation de la matrice de transformation*/ gluperspective(theta_y,l/(gldouble)h, 0.01, 10000); glmatrixmode(gl_modelview); /* repassage en mode GL_MODELVIEW */ SDL_Window * init_sdl_window(int windowwidth, int windowheight, const char* windowtitle){ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,3); SDL_Init(SDL_INIT_VIDEO); /* Le double buffering permet les animations temps réel */ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_Window *window = SDL_CreateWindow(windowTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS return window; } int main(int argc, char**argv) { /* Initialisation d'une fenêtre SDL */ SDL_Window *window =init_sdl_window(largeur_fenetre, hauteur_fenetre, "Premier programme OpenGL avec la SDL"); /* définition du contexte OpenGL associé à cette fenêtre */ SDL_GLContext glcontext(sdl_gl_createcontext(window)); /* Initialisation de la librarire GLEW pour que ça marche sous linux */ GLenum err = glewinit(); if (GLEW_OK!= err) { perror("failed to initialize GLEW!\n"); } /******************************************************************\ Boucle récupérant les évennements SDL et affichant périodiquement \******************************************************************/ bool terminer=false; SDL_Event evenements; /* union contenant un évennement */ GLint currenttime, nextdueframedate = 0; /* pour timer affichage */ { int nbframes=0; /* compteur de frames */ while(!terminer) { while (SDL_PollEvent(&evenements)) /* on défile les évennements */ switch (evenements.type){ /* suivant le type d'évennement */ case SDL_WINDOWEVENT : 33

34 Rémy Malgouyres, Programmation 3D avec OpenGL } int w,h; SDL_GetWindowSize(window,&w,&h); /* récupération taille fenêtre */ Redimensionnement(w, h); break; case SDL_QUIT: /* fermeture de la fenêtre */ terminer = true; break; } /* gestion des frames par secondes (ici 50 fps) */ currenttime = SDL_GetTicks(); /* date courante en milliseconde */ { } } if (currenttime > nextdueframedate) nextdueframedate = currenttime + 20; /* toutes les 20 millisecondes */ Affichage(); /* on raffraichit la vue */ nbframes++; /* On incrémente le compteur de frames */ SDL_GL_SwapWindow(window); /* On envoie le buffer à l'écran */ } // Libération des ressources SDL SDL_GL_DeleteContext(glcontext); SDL_DestroyWindow(window); SDL_Quit(); return 0; Positionnement de la caméra La fonction glulookat permet de modifier du GL_MODELVIEW pour régler la transformation de la caméra (voir la figure 3.9). Les paramètres de glulookat sont : 1. les coordonnées de la position (pos x, pos y, pos z ) de la caméra ; 2. Les coordonnées (C x, C y, C z ) d un point dans la direction de visée (ce point est aussi appelé le centre) ; 3. Les coordonnées d un vecteur V qui doit apparaître vertical dans l image obtenue par projection. Le prototype de glulookat est : void glulookat(gldouble posx, GLdouble posy, GLdouble posz, GLdouble Cx, GLdouble Cy, GLdouble Cy, GLdouble Vx, GLdouble Vy, GLdouble Vz); 34

35 Chapitre 3 : Positioner caméras et objets La fonction glulookat doit être utilisée dans le mode GL_MODELVIEW. void Affichage(void) { glclearcolor(1.0,1.0,1.0,1.0); glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glmatrixmode(gl_modelview); glloadidentity(); /* réinitialiation de la matrice de GL_MODELVIEW */ glulookat(10, 10, 10, /* réglage de la caméra */ 0,0,0, 0,1,0); glcolor3f(0.0,0.0,0.0); /* couleur des traits dessin en noir */ glutwireteapot(5); /* dessin d'une théière */ glutswapbuffers(); /* Envoyer le buffer à l'écran */ } 35

36 Rémy Malgouyres, Programmation 3D avec OpenGL 3.7 Positionner un objet dans une scène Positioner un objet Chaque objet 3D est construit et modélisé dans un repère qui lui est propre, appelé repère de l objet. Pour positioner l objet dans le repère du monde, nous effectuons un changement de repère (voir la figure 3.10). Dans ce cas, il importe de respecter un ordre pour les changements de repères successifs. Nous utiliserons dans ce chapitre l expression matricielle en coodonnées homogènes des changements de repère (voir la partie 3.2). 36

37 Chapitre 3 : Positioner caméras et objets Figure 3.9 : Les paramètres de glulookat 37

38 Rémy Malgouyres, Programmation 3D avec OpenGL k 0 j 0 ı 1 k 1 ı 0 j 1 (a) repère lié à une chaise (b) repère lié à la caméra k j k 0 ı 1 j 1 k 1 ı ı 0 j 0 (c) repères du monde, de la chaise, et de la caméra Figure 3.10 : Les changements de repère dans la construction et le rendu d une scène 3D 38

39 Chapitre 3 : Positioner caméras et objets Pour tranformer l objet de son repère vers le repère du monde, nous multiplierons les coordonnées des sommets ou des points de contrôle par une matrice T. Cette matrice T transformera les vecteurs (1, 0, 0), (0, 1, 0) et (0, 0, 1) dans le repère de l objet en des vecteurs ı 0, ȷ 0 et k 0 (voir la figure 3.10). La matrice T n est autre que la matrice de passage du repère du monde au repère de l objet. Pour passer du repère du monde au repère de la caméra, nous multiplierons par la matrice M 1, où M est la matrice en coordonnées homogènes associée à la caméra. La transformation totale à appliquer à un sommet ou un point de contrôle P de l objet sera (en coordonnées homogènes) : Transformer un objet P = M 1.T.P Pour appliquer une transformation d un objet sur lui-même, c est à dire dans son propre repère (voir la figure 3.11b pour le cas d une rotation de 30 degrés), il faut multiplier la matrice de passage du repère du monde au repère de l objet, à droite, par la matrice R de la transformation. En coordonnées homogènes, on obtient : P = M 1.T.R.P Considérons l exemple d une parallélépipède translaté le long de l axe des z. Le repère de l objet est translaté par rapport au repère du monde. Pour faire une rotation dans le repère de l objet, le parallélépipède doit subir d abord la rotation, puis la translation (voir la figure 3.11). 39

40 Rémy Malgouyres, Programmation 3D avec OpenGL repère de l objet x y x repère de l objet y Translation z z (a) La position initiale (b) Rotation dans le repère de la caméra x x repère de l objet repère du monde repère de l objet repère du monde 2. rotation 1 rotation y y z 2. translation z 1. translation (c) Rotation dans le repère de l objet (d) Rotation dans le repère du monde Figure 3.11 : Rotations d un objet initial autour de l axe Oz dans différents repères. Pour effectuer une transformation de l objet dans le repère du monde (voir la figure 3.11d), il faut muliplier à gauche la matrice de passage du repère du monde au repère de l objet par la matrice da la transformation : P = M 1.R.T.P Si l on reprend l exemple du parallélépipède de la figure 3.11 qui est translaté le long de l axe des y, pour lui faire subir une rotation dans le repère du monde, l objet doit au total subir d abord la translation, puis la rotation. Pour effectuer une transformation R du point de vue dans le repère de la caméra (voir la figure 3.11c), il faut multiplier à gauche l inverse M 1 de la matrice de passage du repère du monde au repère de la caméra par la matrice R. (celà revient à multiplier la matrice M à droite par R 1 ). En coordonnées homogènes, on obtient : P = R.M 1.T.P Pour reprendre l exemple de la figure 3.11, la rotation a lieu après la projection sur le plan 2D. 40

41 Chapitre 3 : Positioner caméras et objets 3.8 Rotation, translation et changement d échelle Matrices GL_MODELVIEW et GL_PROJECTION La succession de transformations que subit un objet avant d être affiché correspond à une succession de produits de matrices. Les transformations 3D sont la composition de deux matrice 4 4 (voir la figure 3.12). 1. La matrice GL_MODELVIEW correspond à la transformation du modèle suivie de la transformation de la caméra ; 2. La matrice GL_PROJECTION correspond à la projection (transformation des coordonnées 3D en coordonées 2D. repère repère repère repère 2D repère 2D de l objet du monde de la caméra du plan de l image objets graphiques transformation du modèle transformation de la caméra projection transformation 2D image à l écran } {{ } matrice GL MODELVIEW matrice GL PROJECTION viewport Figure 3.12 : Les matrices GL_MODELVIEW et GL_PROJECTION Toutes les transfomations 3D effectuées par OpenGL (rotations, translations, changements d échelle, modification de la caméra, de l angle d ouverture, etc...) correspondent à la multiplication à droite de l une des deux matrices GL_MODELVIEW et GL_PROJECTION par une matrice. Pour modifier l une des matrices GL_MODELVIEW ou GL_PROJECTION, il faut sélectioner le mode correspondant par un appel à glmatrixmode Les fonctions glrotatef, gltranslatef et glscalef a La fonction glrotatef La fonction glrotatef permet de faire des rotations, c est à dire de multiplier l une des matrices GL_MODELVIEW ou GL_PROJECTION par une matrice de rotation. Lorsqu on veut faire tourner un objet dans le monde, on fait appel à glrotatef dans le mode GL_MODELVIEW. On conçoit que faire tourner le monde sur lui-même ou faire tourner la caméra autour du monde revient au même du point de vue de l image obtenue. Ces deux choses se réalisent aussi dans le mode GL_MODELVIEW. L appel de glrotatef provoque une multiplication à droite par une matrice de rotation. En d autres termes, la rotation en question sera effectuée avant toutes les autres transformations déjà accumulées dans le mode (GL_MODELVIEW ou GL_PROJECTION selon le cas). Le prototype de la fonction glrotatef est le suivant : \void glrotatef(glfloat angle, GLfloat vx, GLfloat vy, GLfloat vz); 41

42 Rémy Malgouyres, Programmation 3D avec OpenGL Les coordonnées vx, vy et vz sont celles d un vecteur directeur de l axe de rotation. L axe de rotation passe toujour par l origine (rotation vectorielle). Pour faire une rotation dautour d un axe ne passant pas par l origine, il faut composer la rotation avec une translation b La fonction gltranslatef La fonction gltranslatef permet de faire des translation, c est à dire de multiplier l une des matrices GL_MODELVIEW ou GL_PROJECTION par une matrice de translation en coordonnées homogènes. Lorsqu on veut translater un objet dans le monde, ou encore le monde par rapport à la caméra, on fait appel à gltranslatef dans le mode GL_MODELVIEW. Comme pour les rotations, l appel de gltranslatef provoque une multiplication à droite par une matrice de translation. En d autres termes, la translation en question sera effectuée avant toutes les autres transformations déjà accumulées dans le mode (GL_MODELVIEW ou GL_PROJECTION selon le cas). Le prototype de la fonction gltranslatef est le suivant : \void gltranslatef(glfloat vx, GLfloat vy, GLfloat vz); Les coordonnées vx, vy et vz sont celles du vecteur de translation c La fonction glscalef La fonction glscalef permet de faire des changlements d échelle sur les axes (affinités orthogonales). Le prototype de la fonction glscalef est le suivant : \void glscalef(glfloat facteurx, GLfloat facteury, GLfloat facteurz); Les coordonnées x des objets dessinés après l appel à glscalef sont multipliées par facteurx, les coordonnées y par facteury, et les coordonnées z par facteurz. la matrice de changement d échelle est donc ma suivantes : facteurx facteury facteurz Comme pour les rotations et translations, l appel de glscalef provoque une multiplication à droite par une matrice de changement d échelle. En d autres termes, le changement d échelle en question sera effectuée avant toutes les autres transformations déjà accumulées dans le mode (GL_MODELVIEW ou GL_PROJECTION selon le cas). 3.9 Pile de matrices Avec ce que nous avons vu jusqu à présent chaque appel à glrotatef affectera tous les objets dessinés par la suite. Les fonction glpushmatrix et glpopmatrix permettent d appliquer une transformation à une partie des objets. Les matrices GL_MODELVIEW et GL_PROJECTION sont en fait des piles de matrices. La matrice courante est la matrice qui se trouve au sommet de la pile. 42

43 Chapitre 3 : Positioner caméras et objets Lors de l appel à glpushmatrix, la matrice de transformation courante (GL_MODELVIEW ou GL_PROJECTION selon le mode sélectionné) est dupliquée, la copie est ajoutée au sommet de la pile de matrices, et devient la matrice courante. Lors de l appel à glpopmatrix, elle est dépilée, et la matrice courante est restaurée à l état d avant l appel à glpopmatrix. Toutes les transformations effectuées entre les appels de glpushmatrix et glpopmatrix n auront aucun effet sur les objets dessinés après le glpopmatrix. La structure de pile est particulièrement adaptée pour structurer les affichage en décomposant les objets en différentes parties. Par exemple, si l on souhaite dessiner une voiture (voir la figure 3.13). avec deux essieux et deux roues par essieu, on va dessiner le corps de la voiture, Figure 3.13 : Dessin d une voiture on va translater pour dessiner l essieu et les roues avant, puis on va revenir à la posistion de départ, puis translater pour dessiner l essieu et les roues arrière, puis revenir à la position de départ. De même, pour dessiner l essieu (par exemple avant), on va dessiner l essieu, translater pour dessiner la roue de gauche, revenir à la position antérieure, translater pour dessiner la roue de droite, et revenir à la position antérieure. Avec la structure de pile, on dessine le cors de la voiture, on duplique et on empile la matrice GL_MODELVIEW, on dessine l essieu et les roues, puis on dépile la matrice GL_MODELVIEW, ce qui restore la matrice à l état où elle était lors du dessin du corps de la voiture. 43

44 Chapitre 4 Éclairage 4.1 Élimination des parties cachées Lorsqu on affiche des objets en 3D, certaines parties de la scène sont cachées par d autres qui se trouvent plus proches de l observateur. Ainsi, tel un peintre, l algorithme d affichage doit dessiner les objets plus proches en dernier pour que seuls ceux-ci soient visibles. On appelle ce procédé l élimination des parties cachées. L algorithme du z buffer utilisé par OpenGL permet d afficher des scènes dont les objets sont des maillages. Si une scène comprend d autres types d objets (sphères, quadriques, splines...), il faut facettiser ces surfaces (c est à dire les approximer par des maillages pour pouvoir les afficher. Dans l algorithme du z buffer, on calcule une image discrète mémorisée dans un framebuffer. L idée de l algorithme est de calculer, pour chaque pixel, le point de profondeur minimale pour tous les polygones qui se projettent sur ce pixel, ou plus exactement la couleur du polygone en ce point. Pour celà, pour chaque facette du maillage, on parcourt tous les pixels de la projection de la facette (voir la figure 4.1), et on fait un test sur la profondeur z (dans le repère de la caméra) pour savoir si un objet plus proche a déjà été affiché sur ce pixel. Polygone P Projection du polygone P M plan de l écran Pixel (x,y) de la projection Figure 4.1 : Principe de l algorithme du z buffer 44

45 Chapitre 4 : Éclairage Pour activer l élimination des parties cachées dans une application OpenGL sous Glut, il faut activer l option GLUT_DEPTH lors de l appel de glutinitdisplaymode : glutinitdisplaymode(glut_rgba GLUT_DOUBLE GLUT_DEPTH); et activer le test de profondeur : glenable(gl_depth_test); 4.2 Sources de lumière et matériaux Seulement si aucun objet plus proche n a été affiché, on stocke la couleur de la facette pour ce pixel dans le frame buffer. Pour réaliser les tests sur la profondeur, on doit stocker les profondeurs de tous les pixels dans un z buffer. L affichage (plus ou moins) réaliste sous OpenGL repose sur une simulation simplifiée des éclairages. Pour l utiliser, il faut d abord activer l éclairage par glenable(gl_lighting); Lumière ambiante La lumière ambiante vient avec une même intensité de toutes les directions, et elle est réfléchie par les objets dans toutes les directions avec une même intensité. Un modèle d illumination est traduit par une équation : l équation d éclairement. L équation d éclairement pour la lumière ambiante sur un objet est de la forme : I = I a k a où I a est l intensité de la lumière ambiante, caractéristique de la scène, et k a est un coefficient entre 0 et 1, caractéristique de l objet considéré. Pour régler la lumière ambiante dans la scène, on peut utiliser la fonction gllightmodelfv : GLfloat ambient_scene[] = {\bf\{}0.2, 0.2, 0.2, 1.0{\bf\}}; gllightmodelfv(gl_light_model_ambient, ambient_scene); Les trois premiers coefficients du vecteur sont les intensités en RGB de la lumière ambiante. Le quatrième coefficient, appelé alpha, est pour le moment ignoré. On s en sert pour faire du apha-blending, par exemple pour faire des effets de transparence. Pour régler les coefficients de réflexion de la lumière ambiante du matériau courant, on utilise glmaterialfv : GLfloat ambient[] = {\bf\{}0.2, 0.2, 0.2, 1.0{\bf\}}; glmaterialfv(gl_front_and_back, GL_AMBIANT, ambient); Le premier paramètre de glmaterialfv peut être soit GL_FRONT, soit GL_BACK, soit GL_FRONT_AND_BACK. Cela permet de mettre un comportement différent pour les faces selon leur orientation. Voir aussi le culling dans la section 2.3. Les trois premiers coefficients du vecteurs sont les coefficients de réflexion de la lumière ambiante dans le rouge, vert et bleu. 45

46 Rémy Malgouyres, Programmation 3D avec OpenGL N L θ V Figure 4.2 : Le vecteur normal et le vecteur dirigé vers la source Réflexion diffuse Dans le cas d une source lumineuse ponctuelle non directionnelle, la réflexion diffuse tient compte, en un point d un objet, de la direction du vecteur N normal sortant à l objet en ce point, et de la direction du vecteur L dirigé vers la source lumineuse (voir figure 4.2). I = I S k rd cos θ si cos θ > 0 où I S est l intensité de la source lumineuse. Le coefficient de réflexion diffuse k rd est une caractéristique de l objet et varie entre 0 et 1. Pour définir l intensité d une source lumineuse ponctuelle (pour le diffus), on utilise gllightfv : GLfloat diffuse_light0[] = {\bf\{}1.0,1.0,1.0,1.0{\bf\}} gllightfv(gl_light0, GL_DIFFUSE, diffuse_light0); Les trois premières coordonnées du vecteur sont les intensités dans le rouge, vert et bleu de la source. Il existe au moint 8 sources lumineuses (plus selon les implémentations d OpenGL) nommées GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, etc... Il faut activer chaque source individuellement par glenable(gl_light0); Ne pas oublier d activer l éclairage par glenable(gl_lighting). Pour régler les coefficients de réflexion diffuse du matériau courant, on utilise glmaterialfv : GLfloat diffuse[] = {\bf\{}0.2, 0.2, 0.2, 1.0{\bf\}}; glmaterialfv(gl_front_and_back, GL_DIFFUSE, diffuse); Les trois premiers coefficients du vecteurs sont les coefficients de réflexion diffuse dans le rouge, vert et bleu Réflexion spéculaire La réflexion spéculaire est un phénomène apparaissant sur les surfaces brillantes (voir la figure 4.4c). Considérons le vecteur R, symétrique de V par rapport à N (voir figure 4.3). La direction R est la direction privilégiée de réflexion de la lumière vers l observateur selon les lois de Descartes. Si la direction L de la source lumineuse est proche de la direction R, une lumière vive apparaît à l observateur en ce point de l objet. 46

47 Chapitre 4 : Éclairage L N θ α R V Figure 4.3 : Le vecteur de la direction principale de réflexion et de la direction de l observateur. (a) Lumière ambiante (b) Réflexion diffuse (c) Réflexion spéculaire Figure 4.4 : Les différentes sortes de réflexion. Le terme de l équation d éclairement correspondant à la réflexion spéculaire est couramment choisi proportionnel à cos ns α (si α < π 2 ), où α est l angle entre L et R et n s N. On peut choisir une équation de la forme : I sλ = k s cos n s α où λ {R, G, B} et k s est le coefficient de réflexion spéculaire, caractéristique de l objet, et variant entre 0 et 1. L exposant n s s appelle l exposant spéculaire, aussi appelé brillance. Plus l exposant n s est élevé, moins large est la tache claire liée à la réflexion spéculaire (voir la figure 4.5). Pour définir l intensité d une source lumineuse ponctuelle pour le spéculaire, on utilise gllightfv : GLfloat specular_light0[] = {\bf\{}1.0,1.0,1.0,1.0{\bf\}} gllightfv(gl_light0, GL_SPECULAR, specular_light0); Les trois premières coordonnées du vecteur sont les intensités dans le rouge, vert et bleu de la source. Pour régler les coefficients de réflexion spéculaire du matériau courant, on utilise glmaterialfv : GLfloat specular[] = {\bf\{}0.2, 0.2, 0.2, 1.0{\bf\}}; glmaterialfv(gl_front_and_back, GL_SPECULAR, specular); glmaterialf((gl_front_and_back, GL_SHININESS, 110.0); Les trois premiers coefficients du vecteurs sont les coefficients de réflexion specular dans le rouge, vert et bleu. La brillance (shininess) est l exposant spéculaire. Dnas OpenGL, il est compris entre 0.0 et

48 Rémy Malgouyres, Programmation 3D avec OpenGL Figure 4.5 : L effet des coefficients spéculaires et brillance. Les coefficients sont : en haut à gauche k s = 0.2, n s = 5 ; en haut à droite k s = 0.4, n s = 5 ; en bas à gauche k s = 0.2, n s = 30 ; en bas à droite k s = 0.4, n s = Atténuation de la lumière avec la distance L effet de la lumière s atténue avec la distance de l objet considéré à la source lumineuse, et on modifie fréquemment le terme de l équation d éclairement lié aux réflexions diffuses et spéculaires en multipliant par une fonction f att. On peut par exemple prendre une fonction f att de la forme : 1 f att = min(, 1) c 1 + c 2 d L + c 3 d 2 L où d L est la distance du point de l objet considéré à la source lumineuse, et c 1, c 2 et c 3 sont choisis par l utilisateur, appelés respectivement atténuation constante, atténuation linéaire, et atténuation quadratique. Pour définir les coefficients d atténuation de la lumière avec la distance à la source lumineuse, on utilise la fonction gllightf : gllightf(gl_light0, GL_CONSTANT_ATTENUATION, 2.0); gllightf(gl_light0, GL_LINEAR_ATTENUATION, 1.0); gllightf(gl_light0, GL_QUADRATIC_ATTENUATION, 0.5); Les valeurs doivent être adaptées suivant les dimensions de la scène à éclairer Spots Jusqu à présent, nous n avons étudié que des sources non directionnelles, c est à dire que la lumière issue d une telle source part de la même manière dans toutes les directions. En réalité, les sources de lumière, tels des spots, émettent souvent de la lumière dans une direction privilégiée. Cela correspond au modèle de source lumineuse de type spot. 4.3 Vecteurs normaux Pour calculer les termes de réflexion diffuse et spéculaire, OpenGL a besoin de connaître les vecteurs normaux (vecteurs orthogonaux à la surface) aux sommets du maillage. Ces vecteurs 48

49 Chapitre 4 : Éclairage Figure 4.6 : Effet de l atténuation de la lumière avec la distance sur des sphères de même coefficient de réflexion diffuse. Les sphères sont à une distance à la source lumineuse de 302 (en haut à gauche et en bas à droite), 177 (en haut à droite), et 389 (en bas à gauche). Les coefficients d atténuation sont de c 1 = 0.1, c 2 = , c 3 = normaux peuvent être calculés et mémorisés lors de la construction du maillage à partir d un modèle analytique de surface, ou bien il peut être estimé sur le maillage. Pour estimer la normale sur un maillage, on fait pour chaque sommet une moyenne des normales incidentes au sommet. Une fois les normales connues, on peut les communiquer à OpenGL en utilisant la fonction glnormal3f avant un appel à glvertex3f lors du dessin d une primitive géomérique. Par exemple, on peut indiquer les normales aux sommet d un triangle comme suit : On doit tout d abord appeler glenable(gl_normalize) qui assure que les vecteurs normaux sont normalisés (de longuer 1), en calculant la norme du vecteur normal et en divisant ses coordonnées par la norme. C est d autant plus utile si l on effectue des transformation de type changement d échelle (glscalef). Ensuite, on appelle glnormal3f avant chaque définition de sommet : glbegin(gl_triangles); glnormal3f(1.0,2.0,3.0); \com{ce vecteur doit être normalisé} glvertex3f(0.0, 1.0, 0.0); glnormal3f(2.0,1.0, 3.0); glvertex3f(1.0, 0.0, 0.0); glnormal3f(1.0,1.0, 2.0); glvertex3f(0.0, 0.0, 0.5); glend(); 4.4 Éclairement plat et lissage de Gouraud L algorithme d élimination des partie cachées utilisé par OpenGL, appelé z buffer, utilise une approximation des tous les objets par des maillages. Si l on visualise directement un tel maillage, des facettes sont visibles (voir la figure 4.7). Prendre des facettes diminue les performances et n est pas vraiment envisageable. Aussi préfère-t-on en général faire des interpolations pour lisser l intensité lumineuse sur la surface. Pour celà, OpenGL propose un affichage par le modèle de Gouraud, dans lequel ine interpolation bilinéaire est effectuée à partir des intensités 49

50 Rémy Malgouyres, Programmation 3D avec OpenGL des sommet. (a) Éclairement plat GL_FLAT (b) Lissage de Gourand GL_SMOOTH Figure 4.7 : La fonction glshademodel permet de sélectioner l éclairement plat ou le lissage de Gouraud Pour sélectionner l éclairement plat : glshademodel(gl_flat); Pour sélectionner l éclairement lissé de Gouraud : glshademodel(gl_smooth); 4.5 Gérer la position et direction des sources lumineuses Pour définir la position d une source lumineurs GL_LIGHT0, GL_LIGHT1, etc. on utilise la fonction gllightfv. Par exemple, pour placer la source GL_LIGHT0 en position (5, 10, 7) /* Exemple de source placée en (5,10,7) */ GLfloat lightposition0[] = {\bf\{}5.0,10.0,7.0,1.0{\bf\}};... gllightfv(gl_light0, GL_POSITION, lightposition0); Les coordonnées de la position de la source sont des coordonnées homogènes. On peut définir une source placée à l infini en définissant la quatriemme coordonnée w égale à 0. /* Exemple de source placée à l'infini le long de l'axe des x */ GLfloat lightposition0[] = {\bf\{}1.0,0.0,0.0,0.0{\bf\}};... gllightfv(gl_light0, GL_POSITION, lightposition0); 50

51 Chapitre 4 : Éclairage Les sources placées à l infini (comme le soleil) projettent des rayons lumineux parallèles dans la scène. La position de la source est multipliée par la matrice GL_MODELVIEW courante. (la matrice GL_PROJECTION n a pas d effet sur la position d une source lumineuse). On peut donc, suivant le point dans le code où l on définit la postion de la source, positioner la source ou bien dans le repère du monde ou bien dans le repère de la caméra. Exemple 1. Source fixe dans le repère de la caméra. Pour faire une source lumineuse fixe dans le repère de la caméra, il faut définir la position de la source dans le code juste après l initialisation de la matrice GL_MODELVIEW. Dans l exemple suivant, la source est positionnée précisément à l infini le long de l axe de visée, derière l observateur (voir la figure 4.8). (a) Exemple 1 (b) Exemple 2 Figure 4.8 : Dans l exemple 1, la source est placée sur l axe de visée du repère de la caméra. Dans l exemple 2, la source subit la transformation glulookat et se trouve dans le repère de la théière sur l axe des z shading/progc/exshading1.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include <GL/ g l u t. h> /* Uniquement pour l a t h i r e GLUT */ 9 10 GLushort l a r g e u r _ f e n e t r e =500 ; 11 GLushort hauteur_fenetre =500 ; brief Modifie l a f f i c h a g e pour l adapter un redimensionnement de l a f e n t r e. l n o u v e l l e l a r g e u r de l a f e n t r e h n o u v e l l e hauteur de l a f e n t r e 16 */ 17 void Redimensionnement ( int l, int h ) 18 { 19 GLfloat l i g h t P o s i t i o n 0 [ ] = { 0. 0, 0. 0, , 0. 0 } ; 51

52 Rémy Malgouyres, Programmation 3D avec OpenGL 20 GLfloat d i f f u s e L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 21 GLfloat s p e c u l a r L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 22 l a r g e u r _ f e n e t r e = l ; 23 hauteur_fenetre = h ; 24 glviewport ( 0, 0, ( GLsizei ) l a r g e u r _ f e n e t r e, ( GLsizei ) hauteur_fenetre ) ; 25 glmatrixmode (GL_PROJECTION) ; 26 g l L o a d I d e n t i t y ( ) ; 27 g l u P e r s p e c t i v e (20, l /( GLdouble )h, , 10000) ; 28 glmatrixmode (GL_MODELVIEW) ; 29 g l L o a d I d e n t i t y ( ) ; 30 g l L i g h t f v (GL_LIGHT0,GL_DIFFUSE, d i f f u s e L i g h t 0 ) ; 31 g l L i g h t f v (GL_LIGHT0,GL_SPECULAR, s p e c u l a r L i g h t 0 ) ; 32 g l L i g h t f v (GL_LIGHT0, GL_POSITION, l i g h t P o s i t i o n 0 ) ; 33 } void A f f i c h a g e ( void ) 36 { 37 GLfloat d i f f u s e [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 38 GLfloat s p e c u l a r [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 39 GLfloat ambient [ ] = { 0. 2, 0. 2, 0. 2, 1. 0 } ; 40 GLfloat s h i n i n e s s = ; 41 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 42 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; 43 glmatrixmode (GL_MODELVIEW) ; 44 glpushmatrix ( ) ; 45 glulookat ( 8, 10, 15, /* r g l a g e de l a camra */ 46 0, 0, 0, 47 0, 1, 0 ) ; 48 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_DIFFUSE, d i f f u s e ) ; 49 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_SPECULAR, s p e c u l a r ) ; 50 g l M a t e r i a l f (GL_FRONT_AND_BACK, GL_SHININESS, s h i n i n e s s ) ; 51 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_AMBIENT, ambient ) ; 52 glutsolidteapot ( 2 ) ; /* d e s s i n d une t h i r e */ 53 glpopmatrix ( ) ; 54 } brief Fonction d i n i t i a l i s a t i o n de l a f e n t r e SDL windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowtitle T i t r e de l a f e n t r e dans sa barre de t i t r e 60 */ 61 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 62 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 63 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 64 SDL_Init (SDL_INIT_VIDEO) ; 65 /* Le double b u f f e r i n g permet l e s animations temps r e l */ 66 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 67 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL SDL_WINDOW_RESIZABLE) ; 68 return window ; 69 } int main ( int argc, char** argv ) 72 { 52

53 Chapitre 4 : Éclairage 73 g l u t I n i t (&argc, argv ) ; /* u t i l i s a t i o n de l a t h i r e g l u t */ 74 /* I n i t i a l i s a t i o n d une f e n t r e SDL */ 75 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 76 Exemple source f i x e dans l e r e p r e Camra ) ; 77 /* d f i n i t i o n du c o n t e x t e OpenGL a s s o c i c e t t e f e n t r e */ 78 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 81 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 82 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* A c t i v a t i o n des o p t i o n s de rendu */ 85 glenable (GL_DEPTH_TEST) ; /* l i m i n a t i o n des p a r t i e s caches */ 86 glenable (GL_LIGHTING) ; /* c l a i r a g e */ 87 glenable (GL_LIGHT0) ; /* a c t i v a t i o n d une source lumineuse */ 88 gllightmodelf (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) ; /* modle l o c a l */ 89 glshademodel (GL_SMOOTH) ; /* l i s s a g e de phong */ /* *****************************************************************\ 92 Boucle rcuprant l e s vennements SDL e t a f f i c h a n t priodiquement 93 \***************************************************************** */ 94 bool terminer=f a l s e ; 95 SDL_Event evenements ; /* union contenant un vennement */ 96 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 99 while (! terminer ) 100 { 101 while ( SDL_PollEvent(&evenements ) ) /* on d f i l e l e s vennements */ 102 { 103 switch ( evenements. type ) { /* s u i v a n t l e type d vennement */ 104 case SDL_WINDOWEVENT : 105 int w, h ; 106 SDL_GetWindowSize ( window,&w,&h ) ; /* r c u p r a t i o n t a i l l e f e n t r e */ 107 Redimensionnement (w, h ) ; 108 break ; 109 case SDL_QUIT : /* fermeture de l a f e n t r e */ 110 terminer = true ; 111 break ; 112 } 113 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 116 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 119 { 120 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 121 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 122 nbframes++ ; /* On incrmente l e compteur de frames */ 123 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r l cran */ 124 } 125 } // L i b r a t i o n des r e s s o u r c e s SDL 128 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 53

54 Rémy Malgouyres, Programmation 3D avec OpenGL 129 SDL_DestroyWindow ( window ) ; 130 SDL_Quit ( ) ; 131 return 0 ; 132 } Exemple 2. Source placée dans le repère du monde shading/progc/exshading2.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include <GL/ g l u t. h> /* Uniquement pour l a t h i r e GLUT */ 9 10 GLushort l a r g e u r _ f e n e t r e =500 ; 11 GLushort hauteur_fenetre =500 ; void Redimensionnement ( int l, int h ) 14 { 15 l a r g e u r _ f e n e t r e = l ; 16 hauteur_fenetre = h ; 17 glviewport ( 0, 0, ( GLsizei ) l a r g e u r _ f e n e t r e, ( GLsizei ) hauteur_fenetre ) ; 18 glmatrixmode (GL_PROJECTION) ; 19 g l L o a d I d e n t i t y ( ) ; 20 g l u P e r s p e c t i v e (20, l /( GLdouble )h, , 10000) ; 21 glmatrixmode (GL_MODELVIEW) ; 22 g l L o a d I d e n t i t y ( ) ; 23 } void A f f i c h a g e ( void ) 26 { 27 GLfloat l i g h t P o s i t i o n 0 [ ] = { 0. 0, 0. 0, , 0. 0 } ; 28 GLfloat d i f f u s e L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 29 GLfloat s p e c u l a r L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 30 GLfloat d i f f u s e [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 31 GLfloat s p e c u l a r [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 32 GLfloat ambient [ ] = { 0. 2, 0. 2, 0. 2, 1. 0 } ; 33 GLfloat s h i n i n e s s = ; 34 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 35 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; 36 glmatrixmode (GL_MODELVIEW) ; 37 glpushmatrix ( ) ; 38 glulookat ( 8, 10, 15, /* r g l a g e de l a camra */ 39 0, 0, 0, 40 0, 1, 0 ) ; 41 g l L i g h t f v (GL_LIGHT0,GL_DIFFUSE, d i f f u s e L i g h t 0 ) ; 42 g l L i g h t f v (GL_LIGHT0,GL_SPECULAR, s p e c u l a r L i g h t 0 ) ; 43 g l L i g h t f v (GL_LIGHT0, GL_POSITION, l i g h t P o s i t i o n 0 ) ; 44 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_DIFFUSE, d i f f u s e ) ; 45 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_SPECULAR, s p e c u l a r ) ; 46 g l M a t e r i a l f (GL_FRONT_AND_BACK, GL_SHININESS, s h i n i n e s s ) ; 47 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_AMBIENT, ambient ) ; 48 glutsolidteapot ( 2 ) ; /* d e s s i n d une t h i r e */ 54

55 Chapitre 4 : Éclairage 49 glpopmatrix ( ) ; 50 } brief Fonction d i n i t i a l i s a t i o n de l a f e n t r e SDL windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowtitle T i t r e de l a f e n t r e dans sa barre de t i t r e 56 */ 57 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 58 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 59 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 60 SDL_Init (SDL_INIT_VIDEO) ; 61 /* Le double b u f f e r i n g permet l e s animations temps r e l */ 62 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 63 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL SDL_WINDOW_RESIZABLE) ; 64 return window ; 65 } int main ( int argc, char** argv ) 68 { 69 g l u t I n i t (&argc, argv ) ; /* u t i l i s a t i o n de l a t h i r e g l u t */ 70 /* I n i t i a l i s a t i o n d une f e n t r e SDL */ 71 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 72 Exemple source f i x e dans l e r e p r e du monde ) ; 73 /* d f i n i t i o n du c o n t e x t e OpenGL a s s o c i c e t t e f e n t r e */ 74 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 77 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 78 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* A c t i v a t i o n des o p t i o n s de rendu */ 81 glenable (GL_DEPTH_TEST) ; /* l i m i n a t i o n des p a r t i e s caches */ 82 glenable (GL_LIGHTING) ; /* c l a i r a g e */ 83 glenable (GL_LIGHT0) ; /* a c t i v a t i o n d une source lumineuse */ 84 gllightmodelf (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) ; /* modle l o c a l */ 85 glshademodel (GL_SMOOTH) ; /* l i s s a g e de phong */ /* *****************************************************************\ 88 Boucle rcuprant l e s vennements SDL e t a f f i c h a n t priodiquement 89 \***************************************************************** */ 90 bool terminer=f a l s e ; 91 SDL_Event evenements ; /* union contenant un vennement */ 92 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 95 while (! terminer ) 96 { 97 while ( SDL_PollEvent(&evenements ) ) /* on d f i l e l e s vennements */ 98 { 99 switch ( evenements. type ) { /* s u i v a n t l e type d vennement */ 100 case SDL_WINDOWEVENT : 101 int w, h ; 55

56 Rémy Malgouyres, Programmation 3D avec OpenGL 102 SDL_GetWindowSize ( window,&w,&h ) ; /* r c u p r a t i o n t a i l l e f e n t r e */ 103 Redimensionnement (w, h ) ; 104 break ; 105 case SDL_QUIT : /* fermeture de l a f e n t r e */ 106 terminer = true ; 107 break ; 108 } 109 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 112 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 115 { 116 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 117 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 118 nbframes++ ; /* On incrmente l e compteur de frames */ 119 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r l cran */ 120 } 121 } // L i b r a t i o n des r e s s o u r c e s SDL 124 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 125 SDL_DestroyWindow ( window ) ; 126 SDL_Quit ( ) ; 127 return 0 ; 128 } 56

57 Chapitre 5 Textures Principe du plaquage de texture Le but du plaquage de texture est de représenter des objets qui n ont pas une couleur uniforme (voir figures 5.1). De tels objets sont très courants dans le réel, leur représentation est donc essentielle en synthèse d images. Le principe du plaquage de textures consiste à plaquer une image plane, appelée image de texture, sur la surface de l objet. Par exemple, l objet de la figure 5.1b a été obtenu en plaquant l image de la figure 5.1a sur une sphère. Pour cela, étant donné un point M de la surface, il faut faire correspondre au point M un point T (M) de l image de texture. La couleur de l objet au point M à prendre en compte pour l affichage est alors la couleur de l image de texture au point T (M). Les coordonnées du point T (M) dans le plan s appellent les coordonnées de texture du point M. En général, on associe au point M des coordonnées s(m) et t(m) dans [0, 1]. Par exemple, dans le cas d une sphère, on fait correspondre à un point M un point d une image suivant la latitude et longiture. (voir figure 5.2). Notons que les changements d échelle sur les axes permettent de ramener l intervalle [0, 2π] où varie l angle θ sur l intervalle [0, largeur 1]. Il en va de même pour l intervalle où varie l angle φ avec la hauteur. Plus généralement, soit σ : [0, 1] [0, 1] R 3 une surface paramétrée, et soit une image de texture de dimensions largeur hauteur. On peut faire correspondre au point M = σ(s, t) de la surface les coordonnées s(m) = s et t(m) = t, on obtient donc le point T (M) = (s.largeur, t.hauteur) dans l image de texture. 5.1 Plaquage de textures avec OpenGL Exemple 1. Génération de texture par un algorithme puis plaquage de la texture. La fonction CreeBitmap génère les couleurs des texels (les texels sont l équivalent des pixels dans une image de texture). Les données de textels sont stockés dans un grand tableau qui contient les lignes les unes à la suite des autres. La couleur de chaque texel est sockée sur 4 octets par ses composantes RGBA. 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> textures/progc/premierexemple.c 57

58 Rémy Malgouyres, (a) Image de texture Programmation 3D avec OpenGL (b) Rendu de sphère texturée (c) Objets texturés Figure 5.1 : Exemple de plaquage de texture N hauteur 1 ϕ π (hauteur 1) M 0 0 S (a) Le point M sur la sphère θ 2π (largeur 1) largeur 1 (b) Le point correspondant dans l image de texture (c) Latitude et longitude sur la sphère Figure 5.2 : Correspondance Surface - Image de texture. 58

59 Chapitre 5 : Textures (a) Image de texture générée (b) Quadrilatère texturé vu en perspective 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include <GL/ g l u t. h> 9 10 #define largeur_tex #define hauteur_ tex GLushort l a r g e u r _ f e n e t r e =500 ; 14 GLushort hauteur_fenetre =500 ; GLuint id = 0 ; /* t e x t u r e ID */ /* bitmap contenant l e s c o u l e u r s RGBA de l a t e x t u r e */ 19 GLubyte image_tex [ largeur_tex * hauteur_tex * 4 ] ; void CreeBitmap ( ) 22 { 23 int i, j ; 24 GLubyte r, g, b ; 25 for ( i =0 ; i <hauteur_ tex ; i ++) 26 { 27 for ( j=0 ; j<largeur_tex ; j++) 28 { 29 r = ( i *32) %256 ; 30 g = ( j *32) %256 ; 31 b = ( ( i *16) *( j *16) ) %256 ; 32 image_tex [ ( i * largeur_tex+j ) * 4 ] = r ; 33 image_tex [ ( i * largeur_tex+j ) *4+1] = g ; 34 image_tex [ ( i * largeur_tex+j ) *4+2] = b ; 35 image_tex [ ( i * largeur_tex+j ) *4+3] = 255 ; 36 } 59

60 Rémy Malgouyres, Programmation 3D avec OpenGL 37 } 38 } void CreeTexture2D ( void ) 41 { 42 struct gl_texture_t *png_tex = NULL; CreeBitmap ( ) ; 45 /* Generation t e x t u r e */ 46 glgentextures ( 1, &id ) ; 47 glbindtexture (GL_TEXTURE_2D, id ) ; /* Paramtres de f i l t r e s l i n a i r e s */ 50 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) ; 51 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ; /* Cration de l a t e x t u r e */ 54 glteximage2d (GL_TEXTURE_2D, 0, GL_RGBA, largeur_tex, hauteur_tex, 55 0, GL_RGBA, GL_UNSIGNED_BYTE, image_tex ) ; 56 } void A f f i c h a g e ( GLint angle ) 59 { 60 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 61 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; glmatrixmode (GL_MODELVIEW) ; 64 glpushmatrix ( ) ; 65 glulookat ( 8, 10, 15, /* r g l a g e de l a camra */ 66 0, 0, 0, 67 0, 1, 0 ) ; 68 g l R o t a t e f ( 0. 4 * angle, 0. 0, 1. 0, 0. 0 ) ; glbindtexture (GL_TEXTURE_2D, id ) ; /* s l e c t i o n de l a t e x t u r e */ 71 glenable (GL_TEXTURE_2D) ; /* a c t i v a t i o n des t e x t u r e s */ glbegin (GL_QUADS) ; 74 gltexcoord2f ( 0. 0, 0. 0 ) ; g l V e r t e x 3 f ( 3.0, 2.0,0.0) ; 75 gltexcoord2f ( 1. 0, 0. 0 ) ; g l V e r t e x 3 f ( 3. 0, 2. 0, 0. 0 ) ; 76 gltexcoord2f ( 1. 0, 1. 0 ) ; g l V e r t e x 3 f ( 3. 0, 2. 0, 0. 0 ) ; 77 gltexcoord2f ( 0. 0, 1. 0 ) ; g l V e r t e x 3 f ( 3. 0, 2. 0, 0. 0 ) ; 78 glend ( ) ; g l D i s a b l e (GL_TEXTURE_2D) ; /* d s a c t i v a t i o n des t e x t u r e s */ glpopmatrix ( ) ; 83 } void Redimensionnement ( int l, int h ) 86 { 87 l a r g e u r _ f e n e t r e = l ; 88 hauteur_fenetre = h ; 89 glviewport ( 0, 0, ( GLsizei ) l a r g e u r _ f e n e t r e, ( GLsizei ) hauteur_fenetre ) ; 90 glmatrixmode (GL_PROJECTION) ; 91 g l L o a d I d e n t i t y ( ) ; 92 g l u P e r s p e c t i v e (20, l /( GLdouble )h, , 10000) ; 60

61 Chapitre 5 : Textures 93 glmatrixmode (GL_MODELVIEW) ; 94 g l L o a d I d e n t i t y ( ) ; 95 } brief Fonction d i n i t i a l i s a t i o n de l a f e n t r e SDL windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowtitle T i t r e de l a f e n t r e dans sa barre de t i t r e 101 */ 102 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 103 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 104 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 105 SDL_Init (SDL_INIT_VIDEO) ; 106 /* Le double b u f f e r i n g permet l e s animations temps r e l */ 107 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 108 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL SDL_WINDOW_RESIZABLE) ; 109 return window ; 110 } int main ( int argc, char** argv ) 113 { /* I n i t i a l i s a t i o n d une f e n t r e SDL */ 116 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 117 Premier exemple de t e x t u r e OpenGL ) ; 118 /* d f i n i t i o n du c o n t e x t e OpenGL a s s o c i c e t t e f e n t r e */ 119 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; CreeTexture2D ( ) ; /* I n i t i a l i s a t i o n de l a t e x t u r e */ /* *****************************************************************\ 124 Boucle rcuprant l e s vennements SDL e t a f f i c h a n t priodiquement 125 \***************************************************************** */ 126 bool terminer=f a l s e ; 127 SDL_Event evenements ; /* union contenant un vennement */ 128 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 131 while (! terminer ) 132 { 133 while ( SDL_PollEvent(&evenements ) ) /* on d f i l e l e s vennements */ 134 { 135 switch ( evenements. type ) { /* s u i v a n t l e type d vennement */ 136 case SDL_WINDOWEVENT : 137 int w, h ; 138 SDL_GetWindowSize ( window,&w,&h ) ; /* r c u p r a t i o n t a i l l e f e n t r e */ 139 Redimensionnement (w, h ) ; 140 break ; 141 case SDL_QUIT : /* fermeture de l a f e n t r e */ 142 terminer = true ; 143 break ; 144 } 145 } 61

62 Rémy Malgouyres, Programmation 3D avec OpenGL /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 148 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 151 { 152 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 153 A f f i c h a g e ( nbframes ) ; /* on r a f f r a i c h i t l a vue */ 154 nbframes++ ; /* On incrmente l e compteur de frames */ 155 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r l cran */ 156 } 157 } // L i b r a t i o n des r e s s o u r c e s SDL 160 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 161 SDL_DestroyWindow ( window ) ; 162 SDL_Quit ( ) ; 163 return 0 ; 164 } Les principales fonctions utilisées ici sont : void glgentextures(glsizei n, GLuint *texturenames); Génère n identifiants de textures non utilisés et le met dans texturenames. void glbindtexture(glenum target, GLuint texturename); Permet trois choses : D activer (par un identifiant obtenu par glgentextures) une texture pour l utiliser, par exmple dans un affichage ; De créer une nouvelle texture si la texture n a pas encore été utilisée ; De désactiver l utilisation des textures si l on passe 0 comme identifiant de texture. void gldeletetextures(glsizei n, const GLuint *texturenames); Libère la mémoire et les identifiants coorespondant aux textures dont les noms sont passés dans le tableau texturenames. void glteximage2d(glenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); 62

63 Chapitre 5 : Textures Définit une texture 2D. On spécifie la largeur, hauteur, et les couleurs des pixels, et la texture précédement sélectionnée par glbindtexture est initialisée avec ces pixels. Le format interne indique lesquelles des composantes R,G,B,A, luminance ou intensités seront utilisées par OpenGL pour décrire les texels de l image. Il y a trente 38 constantes possibles pour le format, qui peut aussi spécifier le nombre d octets utilisés pour chaque composante. Les valeurs les plus simples sont GL_RGB, GL_RGBA, GL_LUMINANCE ou encore GL_ALPHA pour le alpha-blending. Ces valeurs peuvent aussi être utilisées pour la variable format qui décrit le format du tableau pixels. void gltexcoord2f(glfloat s, GLfloat t); Attribue les coordonnées de texture (s, t) au(x) prochain(s) sommet(s) créé avec glvertex*(). void gltexparameteri(glenum target, GLenum pname, TYPE param); Permet de sélectionner des modes d utilisation de texture. On peut par exemple créer des textures cycliques avec pname égal à GL_TEXTURE_WRAP_S ou GL_TEXTURE_WRAP_T et param égal à GL_REPEAT. Avec le paramètre pname égal à GL_TEXTURE_MAG_FILTER ou GL_TEXTURE_MIN_FILTER, on définit comment les couleurs de textures sont interpolées lorsqu un pixel de l écran ne correspond pas exactement à un pixel de l image de texture (ce qui est généralement le cas). Exemple 2. Plaquage de texture sur une sphère. La texture est chargée à partir d un fichier PNG. On ne décrit pas ici le chargement de fichier PNG mais on suggère d utiliser par exemple la librairie Open Source libpng. La sphère est affichée en tant que quadrique, ce qui permet de générer automatiquement des coordonnées de textures (contrairement à glutsolidsphere). La technique des quadriques permet aussi d afficher des cônes, cylindres, paraboloïdes, etc. (a) Fichier PNG (extrait) (b) Sphère texturée 63

64 Rémy Malgouyres, Programmation 3D avec OpenGL textures/progc/extexture1.c 1 #include <s t d l i b. h> 2 3 #include <SDL2/SDL. h> 4 #include <SDL2/ SDL_opengl. h> 5 #include <GLES3/ g l 3. h> 6 7 #include <GL/ g l u t. h> 8 9 #include <s t d i o. h> GLushort l a r g e u r _ f e n e t r e =500 ; 12 GLushort hauteur_fenetre =500 ; void Redimensionnement ( int l, int h ) 16 { 17 GLfloat l i g h t P o s i t i o n 0 [ ] = { 0. 0, 0. 0, , 0. 0 } ; 18 GLfloat d i f f u s e L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 19 GLfloat s p e c u l a r L i g h t 0 [ ] = { 0. 6, 0. 6, 0. 6, 1. 0 } ; 20 l a r g e u r _ f e n e t r e = l ; 21 hauteur_fenetre = h ; 22 glviewport ( 0, 0, ( GLsizei ) l a r g e u r _ f e n e t r e, ( GLsizei ) hauteur_fenetre ) ; 23 glmatrixmode (GL_PROJECTION) ; 24 g l L o a d I d e n t i t y ( ) ; 25 g l u P e r s p e c t i v e (20, l /( GLdouble )h, , 10000) ; 26 glmatrixmode (GL_MODELVIEW) ; 27 g l L o a d I d e n t i t y ( ) ; 28 g l L i g h t f v (GL_LIGHT0,GL_DIFFUSE, d i f f u s e L i g h t 0 ) ; 29 g l L i g h t f v (GL_LIGHT0,GL_SPECULAR, s p e c u l a r L i g h t 0 ) ; 30 g l L i g h t f v (GL_LIGHT0, GL_POSITION, l i g h t P o s i t i o n 0 ) ; 31 } void A f f i c h a g e ( GLint angle, GLuint texid ) 34 { 35 GLUquadricObj * quadrique ; 36 GLfloat d i f f u s e [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 37 GLfloat s p e c u l a r [ ] = { 1. 0, 1. 0, 1. 0, 1. 0 } ; 38 GLfloat ambient [ ] = { 0. 2, 0. 2, 0. 2, 1. 0 } ; 39 GLfloat s h i n i n e s s = ; 40 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 41 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; glbindtexture (GL_TEXTURE_2D, texid ) ; 44 glmatrixmode (GL_MODELVIEW) ; glpushmatrix ( ) ; 47 glulookat ( 8, 10, 15, /* r g l a g e de l a camra */ 48 0, 0, 0, 49 0, 1, 0 ) ; 50 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_DIFFUSE, d i f f u s e ) ; 51 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_SPECULAR, s p e c u l a r ) ; 52 g l M a t e r i a l f (GL_FRONT_AND_BACK, GL_SHININESS, s h i n i n e s s ) ; 53 g l M a t e r i a l f v (GL_FRONT_AND_BACK, GL_AMBIENT, ambient ) ; 54 g l R o t a t e f ( 0. 4 * angle, 0. 0, 1. 0, 0. 0 ) ; 55 glenable (GL_TEXTURE_2D) ; 64

65 Chapitre 5 : Textures 56 quadrique = glunewquadric ( ) ; gluquadrictexture ( quadrique, GL_TRUE) ; 59 gluquadricnormals ( quadrique, GLU_SMOOTH) ; 60 glusphere ( quadrique, 2, 128, 64) ; 61 g l D i s a b l e (GL_TEXTURE_2D) ; glpopmatrix ( ) ; 64 } GLuint loadbmptexture ( const char * f i l e n a m e ) 67 { 68 GLuint tex_ id = 0 ; /* Chargement d une image p a r t i r d un f i c h i e r avec l a SDL */ 71 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 74 glgentextures ( 1, &tex_ id ) ; 75 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 78 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 79 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 82 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 83 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 86 return tex_id ; 87 } brief Fonction d i n i t i a l i s a t i o n de l a f e n t r e SDL windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowwidth l a r g e u r de l a f e n t r e en p i x e l s windowtitle T i t r e de l a f e n t r e dans sa barre de t i t r e 93 */ 94 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 95 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 96 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 97 SDL_Init (SDL_INIT_VIDEO) ; 98 /* Le double b u f f e r i n g permet l e s animations temps r e l */ 99 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 100 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL SDL_WINDOW_RESIZABLE) ; 101 return window ; 102 } /** argv [ 1 ] d o i t c o n t e n i r l e chemin v e r s une images BMP 106 */ 107 int main ( int argc, char** argv ) 108 { 65

66 Rémy Malgouyres, Programmation 3D avec OpenGL /* I n i t i a l i s a t i o n d une f e n t r e SDL */ 111 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 112 Chargement d une t e x t u r e au format BMP ) ; 113 /* d f i n i t i o n du c o n t e x t e OpenGL a s s o c i c e t t e f e n t r e */ 114 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; glenable (GL_DEPTH_TEST) ; 117 glenable (GL_LIGHTING) ; 118 glenable (GL_LIGHT0) ; 119 gllightmodelf (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) ; 120 glshademodel (GL_SMOOTH) ; GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 123 i f (! texid ) 124 e x i t (EXIT_FAILURE) ; /* *****************************************************************\ 127 Boucle rcuprant l e s vennements SDL e t a f f i c h a n t priodiquement 128 \***************************************************************** */ 129 bool terminer=f a l s e ; 130 SDL_Event evenements ; /* union contenant un vennement */ 131 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 134 while (! terminer ) 135 { 136 while ( SDL_PollEvent(&evenements ) ) /* on d f i l e l e s vennements */ 137 { 138 switch ( evenements. type ) { /* s u i v a n t l e type d vennement */ 139 case SDL_WINDOWEVENT : 140 int w, h ; 141 SDL_GetWindowSize ( window,&w,&h ) ; /* r c u p r a t i o n t a i l l e f e n t r e */ 142 Redimensionnement (w, h ) ; 143 break ; 144 case SDL_QUIT : /* fermeture de l a f e n t r e */ 145 terminer = true ; 146 break ; 147 } 148 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 151 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 154 { 155 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 156 A f f i c h a g e ( nbframes, texid ) ; /* on r a f f r a i c h i t l a vue */ 157 nbframes++ ; /* On incrmente l e compteur de frames */ 158 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r l cran */ 159 } 160 } // L i b r a t i o n des r e s s o u r c e s SDL 163 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 164 SDL_DestroyWindow ( window ) ; 66

67 Chapitre 5 : Textures 165 SDL_Quit ( ) ; 166 return 0 ; 167 } 67

68 Deuxième partie Programmation par shaders et VBO 68

69 Chapitre 6 Initiation à GLSL Les shaders OpenGL, avec les VBO, sont un moyen d accélérer considérablement l affichage par rapport au mode de compatibilité qui est hérité des anciennes versions d OpenGL. Les shaders sont des programmes, écrits en OpenGL Shading Language (GLSL) qui s exécutent en parallèle, sur les sommets pour les vertex shaders, ou sur les pixels pour les fragment shaders. Nous n allons pas insérer ici les faméux diagramme sur le pipeline d OpenGL. On trouve celà dans le redbook que l on peut télécharger sur internet. Rappelons tout de même comment sont traités les maillages lors de l affichage OpenGL lours d un rendu de base avec lissage de Phong. Les sommets subissents d abord la transformation du modèle et la transformation de projection et enfin la transformation viewport. Puis, pour chaque triangle, le triangle est rasterisé c est à dire que les pixels à l interieur du triangle sont parcourus. Pour calculer la couleur des pixels à l intérieur des triangles des interpolations bilinéaires sont effectuées (c est le cas bien souvent des coordonnées de textures ou encore du vecteur normal pour le lissage de phong). On obtient ainsi des valeurs (de normale, coordonnée de texture, etc.) en chaque pixel, qui l on combine avec les modèles d éclairement pour calculer la couleur des pixels. Dans le mode de compatibilité, les couleurs, coordonnées de textures et normales aux sommets sont définies par les fonctions glcolor*, gltexcoord* et glnormal*. (Nous verrons plus loin comment définir ces valeurs dans des tableaux en mémoire vidéo avec les VBO). Le rôle du vertex shader est de personnaliser par un programme le traitement en parallèle de tous les sommets. Le rôle du fragment shader est de personnaliser par un programme le traitement en parallèle de tous les pixels après rasterisation des triangles. Des valeurs peuvent être transmises, soit du programme C/C++ vers les shaders (c est le cas des variables uniform) soit du vertex shader vers le fragment shader avec interpolation bilinéaire pour calculer les valeurs à l intérieur des triangles (c est le cas des variables varying) (voir la figure 6.1). 69

70 Rémy Malgouyres, Programmation 3D avec OpenGL Programme C/C++ Variables uniform Position sommets Normales sommets Couleurs sommets Coordonnes de textures Variables uniform Fragment Shader Variables varying (interpolation) Vertex Shader Figure 6.1 : Schéma de circulation de l information vers et entre les shaders 6.1 Création d un programme OpenGL avec ses deux shaders Les routines suivantes permettent de charger le code source des shaders, de les compiler, et de lies lier au sein d un programme OpenGL. Ne pas confondre le programme OpenGL avec le programme C/C++ réalisant l application. Le programme C/C++ peut utiliser successivement plusieurs programmes OpenGL avec des shaders différents (par exemple pour faire des rendus dans différents Frame Buffers. basicshaders/progc/shadersutils.h 1 #include <GLES3/ g l 3. h> 2 3 void CreateShadersProgram ( GLuint* pprogid, GLuint* pvertexid, GLuint* pfragid, 4 const char* v e r t e x S o u r c e F i l e, 5 const char* fragmentsourcefile ) ; basicshaders/progc/shadersutils.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 #include <s t r i n g. h> 4 5 #include s h a d e r s U t i l s. h 6 7 /** Charge l e code source du shader contenu dans un f i c h i e r t e x t e v e r s une chaîne de c a r a c t è r e s. filename nom du f i c h i e r t e x t e contenant l e code du shader l e code du shader contenu dans une chaîne de c a r a c t è r e s 11 */ 12 char* LoadShaderSource ( const char * f i l e n a m e ) 13 { 14 char * shadersrc = NULL; /* chaîne d e s t i n é e à c o n t e n i r l e source */ 15 FILE * fp = NULL; /* p o i n t e u r v e r s l e f i c h i e r source */ 16 long t a i l l e ; /* t a i l l e en c a r a c t è r e s du f i c h i e r source */ 17 long i ; /* i n d i c e */ /* Ouverture du f i c h i e r */ 70

71 Chapitre 6 : Initiation à GLSL 20 i f ( ( fp = fopen ( filename, r ) )==NULL) 21 { 22 f p r i n t f ( s t d e r r, I m p o s s i b l e d o u v r i r l e f i c h i e r % s \ n, f i l e n a m e ) ; 23 return NULL; 24 } /* on recupere l a longueur du f i c h i e r pour l a l l o c a t i o n */ 27 f s e e k ( fp, 0, SEEK_END) ; 28 t a i l l e = f t e l l ( fp ) ; /* on r e v i e n t au debut du f i c h i e r */ 31 f s e e k ( fp, 0, SEEK_SET) ; /* on a l l o u e de l a memoire pour l a chaîne ( en comptant l e \0 ) */ 34 shadersrc = ( char *) malloc ( ( t a i l l e +1)* sizeof ( char ) ) ; i f ( shadersrc == NULL) 37 { 38 f c l o s e ( fp ) ; 39 f p r i n t f ( s t d e r r, eereur d a l l o c a t i o n : f i c h i e r trop long??\n ) ; 40 return NULL; 41 } /* l e c t u r e du f i c h i e r v e r s l a chaîne */ 44 for ( i =0 ; i <t a i l l e ; i++) 45 shadersrc [ i ] = f g e t c ( fp ) ; /* on termine l a chaîne par un \0 */ 48 shadersrc [ t a i l l e ] = \0 ; f c l o s e ( fp ) ; return shadersrc ; 53 } /** Création d un programme OpenGL avec son v e r t e x shader e t son fragment shader. $ProgID passage par a d r e s s e de l ID du programme pvertexid passage par a d r e s s e de l ID du v e r t e x shader pfragid passage par a d r e s s e de l ID du fragment shader v e r t e x S o u r c e F i l e nom du f i c h i e r contenant l e code source du v e r t e x shader fragmentsourcefile nom du f i c h i e r contenant l e code source du fragment shader 62 */ 63 void CreateShadersProgram ( GLuint* pprogid, GLuint* pvertexid, GLuint* pfragid, 64 const char* v e r t e x S o u r c e F i l e, 65 const char* fragmentsourcefile ) { 66 GLsizei l o g s i z e = 0 ; /* pour récupérer l e l o g d e r r e u r */ 67 GLint compile_status = GL_TRUE; /* pour d é t e c t e r l e s e r r e u r s de c o m p i l a t i o n */ 68 char * l o g = NULL; /* chaîne d e s t i n é e à c o n t e n i r l e l o g d e r r e u r */ /* g é n é r a t i o n des ID des shaders */ 71 GLuint vertexid = glcreateshader (GL_VERTEX_SHADER) ; 72 GLuint fragmentid = glcreateshader (GL_FRAGMENT_SHADER) ; 71

72 Rémy Malgouyres, Programmation 3D avec OpenGL /* On r e n v o i e l e s ID par passage par a d r e s s e */ 75 * pvertexid = vertexid ; 76 *pfragid = fragmentid ; /* On charge l e s codes sources des shaders dans des chaînes */ 79 const char * vertexsource = LoadShaderSource ( v e r t e x S o u r c e F i l e ) ; 80 const char * fragmentsource = LoadShaderSource ( fragmentsourcefile ) ; /* On d é f i n i t l e code source des shaders */ 83 glshadersource ( vertexid, 1, &vertexsource, NULL) ; 84 glshadersource ( fragmentid, 1, &fragmentsource, NULL) ; /* Compilation du v e r t e x shader */ 87 glcompileshader ( vertexid ) ; /* On d é t e c t e l e s e r r e u r s de c o m p i l a t i o n */ 90 glgetshaderiv ( vertexid, GL_COMPILE_STATUS, &compile_status ) ; 91 i f ( compile_status!= GL_TRUE) 92 { 93 p e r r o r ( probleme vertexid ) ; glgetshaderiv ( vertexid, GL_INFO_LOG_LENGTH, &l o g s i z e ) ; l o g = ( char *) malloc ( l o g s i z e + 1) ; 98 i f ( l o g == NULL) 99 { 100 f p r i n t f ( s t d e r r, I m p o s s i b l e d a l l o u e r de l a memoire pour l e l o g! \ n ) ; 101 return ; 102 } 103 memset ( log, \0, l o g s i z e + 1) ; glgetshaderinfolog ( vertexid, l o g s i z e, &l o g s i z e, l o g ) ; 106 f p r i n t f ( s t d e r r, I m p o s s i b l e de compiler l e shader % s :\n%s, 107 v e r t e x S o u r c e F i l e, l o g ) ; 108 f r e e ( l o g ) ; 109 gldeleteshader ( vertexid ) ; 110 } /* Compilation du fragment shader */ 114 compile_status = GL_TRUE; glcompileshader ( fragmentid ) ; glgetshaderiv ( fragmentid, GL_COMPILE_STATUS, &compile_status ) ; 119 i f ( compile_status!= GL_TRUE) 120 { p e r r o r ( probleme fragmentid ) ; 123 glgetshaderiv ( vertexid, GL_INFO_LOG_LENGTH, &l o g s i z e ) ; l o g = ( char *) malloc ( l o g s i z e + 1) ; 127 i f ( l o g == NULL) 128 { 72

73 Chapitre 6 : Initiation à GLSL 129 f p r i n t f ( s t d e r r, i m p o s s i b l e d a l l o u e r de l a memoire pour l e l o g! \ n ) ; 130 return ; 131 } 132 memset ( log, \0, l o g s i z e + 1) ; glgetshaderinfolog ( fragmentid, l o g s i z e, &l o g s i z e, l o g ) ; 135 f p r i n t f ( s t d e r r, i m p o s s i b l e de compiler l e shader % s :\n%s, 136 fragmentsourcefile, l o g ) ; f r e e ( l o g ) ; 139 gldeleteshader ( fragmentid ) ; 140 } /* Création du programme OpenGL avec s e s shaders */ 143 GLuint programid = glcreateprogram ( ) ; 144 /* On r e n v o i r l ID du programme par un passage par a d r e s s e */ 145 * pprogid = programid ; /* On d é f i n i t l e s shaders a s s o c i é s à ce programme */ 148 glattachshader ( programid, vertexid ) ; 149 glattachshader ( programid, fragmentid ) ; /* On termine l a c o m p i l a t i o n du programme */ 152 gllinkprogram ( programid ) ; 153 } 6.2 Mes premiers Shaders Le programme C/C++ suivant affiche un triangle rouge. Pour cela, un maillage avec 3 sommets et 1 facette est défini. Il est affiché dans la fonction d affichage (ici avec le mode de compatibilité) en utilisant un programme OpenGL. Ici, le vertex shader transmet la position des sommets inchangée et le fragment shader renvoie du rouge pour tous les pixels. On obteint donc un triangle rouge (voir figure 6.2) basicshaders/progc/exshader1.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> #include s h a d e r s U t i l s. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 12 GLushort l a r g e u r _ f e n e t r e =700 ; 13 GLushort hauteur_fenetre =700 ; /* ************************************ */ 16 /* S t r u c t u r e de m a i l l a g e d un t r i a n g l e */ GLint n v e r t i c e s =3, n f a c e s =1 ; 73

74 Rémy Malgouyres, Programmation 3D avec OpenGL GLfloat v e r t i c e s [ ] [ 3 ] = { 21 { 0.5, 1. 0, 0. 0 }, 22 { 1. 0, 0.5, 0. 0 }, 23 { 1.0, 1.0, 0.0} 24 } ; GLuint f a c e s [ ] [ 3 ] = { 27 {0, 1, 2} 28 } ; /* *************************************** */ 31 /* a f f i c h a g e */ 32 void A f f i c h a g e ( void ) 33 { 34 int i, j ; 35 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 36 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 37 /* On u t i l i s e encore i c i l e mode de c o m p a t i b i l i t é */ 38 glbegin (GL_TRIANGLES) ; 39 for ( i =0 ; i<n f a c e s ; i++) 40 for ( j=0 ; j <3 ; j++) 41 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 42 glend ( ) ; 43 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 49 */ 50 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 51 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 52 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 53 SDL_Init (SDL_INIT_VIDEO) ; 54 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 55 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 56 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 57 return window ; 58 } int main ( int argc, char** argv ) 61 { 62 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 63 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 64 Dessin d un t r i a n g l e uni ) ; 65 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 66 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 69 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 70 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; 71 74

75 Chapitre 6 : Initiation à GLSL 72 /* ************************************* */ 73 /* c r é a t i o n des shaders */ 74 GLuint vertexid, fragmentid ; 75 GLuint programid ; 76 CreateShadersProgram(&programID, &vertexid, &fragmentid, 77 vertexshader1. txt, 78 fragmentshader1. txt ) ; 79 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* *****************************************************************\ 82 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 83 \***************************************************************** */ 84 bool terminer=f a l s e ; 85 SDL_Event evenements ; /* union contenant un évennement */ 86 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 89 while (! terminer ) 90 { 91 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 92 { 93 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 94 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 95 terminer = true ; 96 break ; 97 } 98 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 101 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 104 { 105 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 106 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 107 nbframes++ ; /* On incrémente l e compteur de frames */ 108 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 109 } 110 } // L i b é r a t i o n des r e s s o u r c e s SDL 113 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 114 SDL_DestroyWindow ( window ) ; 115 SDL_Quit ( ) ; 116 return 0 ; 117 } Le Vertex shader est un fichier texte comme suit : basicshaders/progc/vertexshader1.txt 1 #v e r s i o n void main ( void ) 4 { 5 // p o s i t i o n du sommet après p r o j e c t i o n ( i c i inchangée ) 6 gl_position = gl_vertex ; 75

76 Rémy Malgouyres, Programmation 3D avec OpenGL 7 } Le Fragment shader est un fichier texte comme suit : basicshaders/progc/fragmentshader1.txt 1 #v e r s i o n void main ( void ) 4 { 5 // On a f f i c h e du rouge 6 gl_fragcolor = vec4 ( 1. 0, 0. 0, 0. 0, 1. 0 ) ; 7 } Figure 6.2 : Exemple 1. Un triangle rouge 6.3 Interpolation des couleurs aux sommets (voir figure 6.3) basicshaders/progc/exshader2.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include s h a d e r s U t i l s. h 9 10 /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 11 GLushort l a r g e u r _ f e n e t r e =700 ; 76

77 Chapitre 6 : Initiation à GLSL 12 GLushort hauteur_fenetre =700 ; /* ************************************ */ 15 /* S t r u c t u r e de m a i l l a g e d un t r i a n g l e */ GLint n v e r t i c e s =3, n f a c e s =1 ; GLfloat v e r t i c e s [ ] [ 3 ] = { 20 { 0.5, 1. 0, 0. 0 }, 21 { 1. 0, 0.5, 0. 0 }, 22 { 1.0, 1.0, 0.0} 23 } ; GLfloat c o l o r s [ ] [ 3 ] = { 26 { 1. 0, 0. 0, 0. 0 }, 27 { 0. 0, 1. 0, 0. 0 }, 28 { 0. 0, 0. 0, 1.0} 29 } ; GLuint f a c e s [ ] [ 3 ] = { 32 {0, 1, 2} 33 } ; /* *************************************** */ 37 /* a f f i c h a g e */ 38 void A f f i c h a g e ( void ) 39 { 40 int i, j ; 41 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 42 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 43 /* On u t i l i s e encore i c i l e mode de c o m p a t i b i l i t é */ 44 glbegin (GL_TRIANGLES) ; 45 for ( i =0 ; i<n f a c e s ; i++) 46 for ( j=0 ; j <3 ; j++){ 47 g l C o l o r 3 f v ( c o l o r s [ f a c e s [ i ] [ j ] ] ) ; 48 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 49 } 50 glend ( ) ; 51 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 57 */ 58 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 59 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 60 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 61 SDL_Init (SDL_INIT_VIDEO) ; 62 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 63 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 64 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 77

78 Rémy Malgouyres, Programmation 3D avec OpenGL 65 return window ; 66 } int main ( int argc, char** argv ) 69 { 70 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 71 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 72 Dessin d un t r i a n g l e avec c o u l e u r s i n t e r p o l é e s ) ; 73 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 74 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 77 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 78 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 81 /* c r é a t i o n des shaders */ 82 GLuint vertexid, fragmentid ; 83 GLuint programid ; 84 CreateShadersProgram(&programID, &vertexid, &fragmentid, 85 vertexshader2. txt, 86 fragmentshader2. txt ) ; 87 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* *****************************************************************\ 90 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 91 \***************************************************************** */ 92 bool terminer=f a l s e ; 93 SDL_Event evenements ; /* union contenant un évennement */ 94 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 97 while (! terminer ) 98 { 99 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 100 { 101 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 102 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 103 terminer = true ; 104 break ; 105 } 106 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 109 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 112 { 113 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 114 A f f i c h a g e ( ) ; /* on r a f f r a i c h i t l a vue */ 115 nbframes++ ; /* On incrémente l e compteur de frames */ 116 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 117 } 118 } // L i b é r a t i o n des r e s s o u r c e s SDL 78

79 Chapitre 6 : Initiation à GLSL 121 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 122 SDL_DestroyWindow ( window ) ; 123 SDL_Quit ( ) ; 124 return 0 ; 125 } Le Vertex shader est un fichier texte comme suit : basicshaders/progc/vertexshader2.txt 1 #v e r s i o n void main ( void ) 4 { 5 // p o s i t i o n du sommet après p r o j e c t i o n 6 gl_position = gl_vertex ; 7 // D é f i n i t i o n de l a c o u l e u r au sommet 8 gl_ FrontColor = gl_ Color ; 9 } Le Fragment shader est un fichier texte comme suit : 1 void main ( void ) 2 { 3 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 4 gl_ FragColor = gl_ Color ; 5 } basicshaders/progc/fragmentshader2.txt Figure 6.3 : Un triangle avec couleurs interpolées à partir des sommets 79

80 Rémy Malgouyres, Programmation 3D avec OpenGL 6.4 Variables uniform Les avriables uniform sont un moyen de transmettre des données du programme C/C++ vers les shaders. La variable uniform aura la même valeur pour tous les sommets et tous les pixels d une même frame (d une même image). Par contre, lors d une animation ou dans un programme interactif, les variables uniform peuvent varier d une frame à l autre. Dans l exemple suivant, une variable uniform appelée temps, qui est liée au numéro de frame, permet de réaliser une animation en faisant varier les position des sommets en fonction du temps dans le vertex shader. (voir figure 6.4) basicshaders/progc/exuniform1.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include s h a d e r s U t i l s. h 9 10 /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 11 GLushort l a r g e u r _ f e n e t r e =700 ; 12 GLushort hauteur_fenetre =700 ; /* ************************************ */ 15 /* S t r u c t u r e de m a i l l a g e d un t r i a n g l e */ GLint n v e r t i c e s =3, n f a c e s =1 ; GLfloat v e r t i c e s [ ] [ 3 ] = { 20 { 0.5, 1. 0, 0. 0 }, 21 { 1. 0, 0.5, 0. 0 }, 22 { 1.0, 1.0, 0.0} 23 } ; GLfloat c o l o r s [ ] [ 3 ] = { 26 { 1. 0, 0. 0, 0. 0 }, 27 { 0. 0, 1. 0, 0. 0 }, 28 { 0. 0, 0. 0, 1.0} 29 } ; GLuint f a c e s [ ] [ 3 ] = { 32 {0, 1, 2} 33 } ; /* *************************************** */ 36 /* a f f i c h a g e */ 37 void A f f i c h a g e ( GLint nbframes, GLuint programid ) 38 { 39 /* On c a l c u l e l e temps e t on i n i t i a l i s e l a v a r i a b l e uniform */ 40 GLfloat temps = 0. 2 * ( GLfloat ) nbframes ; 41 /* On récupère l emplacement ( en mémoire v i d é o ) de l a v a r i a b l e */ 42 GLint temps_loc = glgetuniformlocation ( programid, temps ) ; 43 /* On i n i t i a l i s e l a v a r i a b l e avant l a f f i c h a g e */ 44 gluniform1f ( temps_loc, temps ) ; 80

81 Chapitre 6 : Initiation à GLSL int i, j ; 47 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 48 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 49 /* On u t i l i s e encore i c i l e mode de c o m p a t i b i l i t é */ 50 glbegin (GL_TRIANGLES) ; 51 for ( i =0 ; i<n f a c e s ; i++) 52 for ( j=0 ; j <3 ; j++){ 53 g l C o l o r 3 f v ( c o l o r s [ f a c e s [ i ] [ j ] ] ) ; 54 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 55 } 56 glend ( ) ; 57 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 63 */ 64 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 65 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 66 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 67 SDL_Init (SDL_INIT_VIDEO) ; 68 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 69 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 70 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 71 return window ; 72 } int main ( int argc, char** argv ) 75 { 76 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 77 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 78 Dessin d un t r i a n g l e dont l e s sommets bougent ) ; 79 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 80 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 83 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 84 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 87 /* c r é a t i o n des shaders */ 88 GLuint vertexid, fragmentid ; 89 GLuint programid ; 90 CreateShadersProgram(&programID, &vertexid, &fragmentid, 91 vertexshader3. txt, 92 fragmentshader3. txt ) ; 93 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* *****************************************************************\ 97 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 81

82 Rémy Malgouyres, Programmation 3D avec OpenGL 98 \***************************************************************** */ 99 bool terminer=f a l s e ; 100 SDL_Event evenements ; /* union contenant un évennement */ 101 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ GLint nbframes=0 ; /* compteur de frames */ 104 while (! terminer ) 105 { 106 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 107 { 108 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 109 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 110 terminer = true ; 111 break ; 112 } 113 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 116 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 119 { 120 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 121 A f f i c h a g e ( nbframes, programid ) ; /* on r a f f r a i c h i t l a vue */ 122 nbframes++ ; /* On incrémente l e compteur de frames */ 123 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 124 } 125 } // L i b é r a t i o n des r e s s o u r c e s SDL 128 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 129 SDL_DestroyWindow ( window ) ; 130 SDL_Quit ( ) ; 131 return 0 ; 132 } Le Vertex shader est un fichier texte comme suit : basicshaders/progc/vertexshader3.txt 1 uniform float temps ; 2 3 void main ( void ) 4 { 5 // p o s i t i o n du sommet après p r o j e c t i o n 6 // matrice ModelView * ( p o s i t i o n avant p r o j e c t i o n ) 7 vec3 tmppos = vec3 ( gl_ Vertex ) ; 8 gl_position = vec4 ( 0. 7 * tmppos. x *(1+0.25* s i n ( temps ) ), 9 0.7* tmppos. y *(1+0.25* s i n ( temps ) ), * tmppos. z *(1+0.25* s i n ( temps ) ), 1. 0 ) ; 11 gl_ FrontColor = gl_ Color ; 12 } Le Fragment shader est un fichier texte comme suit : 1 void main ( void ) basicshaders/progc/fragmentshader3.txt 82

83 Chapitre 6 : Initiation à GLSL 2 { 3 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 4 gl_ FragColor = gl_ Color ; 5 } Figure 6.4 : Un triangle qui évolue en fonction du temps 6.5 Variables varying Les variables varying permettent de passer des valeurs du vertex shader vers le fragment shader en interpolant les valeurs pour calculer les valeurs au pixels intérieur aux triangle. Dans l exemple suivant, nous définissons les coordonnées de textures en chaque sommet, puis ces valeurs sont interpolées (via une variable varying tex_coord) pour calculer les coordonnées de texture en chaque pixel. Dans le fragment shader, une variable uniform de type sampler2d, contenant un ID de texture, permet de récupérer la couleur de la texture à partir des coordonnées de texture. (voir figure 6.5) Notez que la variable varying doit exister et être déclarée à la fois dans le vertex shader et dans le fragment shader. basicshaders/progc/exvaryingtexture1.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #include s h a d e r s U t i l s. h 9 10 /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 11 GLushort l a r g e u r _ f e n e t r e =700 ; 83

84 Rémy Malgouyres, Programmation 3D avec OpenGL 12 GLushort hauteur_fenetre =700 ; /* ************************************ */ 15 /* S t r u c t u r e de m a i l l a g e d un t r i a n g l e */ GLint n v e r t i c e s =3, n f a c e s =1 ; GLfloat v e r t i c e s [ ] [ 3 ] = { 20 { 0.5, 1. 0, 0. 0 }, 21 { 1. 0, 0.5, 0. 0 }, 22 { 1.0, 1.0, 0.0} 23 } ; GLfloat coordtex [ ] [ 2 ] = { 26 { , 1. 0 }, 27 { 1. 0, }, 28 { 0. 0, 0.0} 29 } ; GLuint f a c e s [ ] [ 3 ] = { 32 {0, 1, 2} 33 } ; GLuint loadbmptexture ( const char * f i l e n a m e ) 36 { 37 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 40 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 43 glgentextures ( 1, &tex_ id ) ; 44 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 47 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 48 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 51 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 52 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 55 return tex_id ; 56 } 57 /* *************************************** */ 58 /* a f f i c h a g e */ 59 void A f f i c h a g e ( GLint nbframes, GLuint programid ) 60 { 61 /* On c a l c u l e l e temps e t on i n i t i a l i s e l a v a r i a b l e uniform */ 62 GLfloat temps = 0. 2 * ( GLfloat ) nbframes ; 63 /* On récupère l emplacement ( en mémoire v i d é o ) de l a v a r i a b l e */ 64 GLint temps_loc = glgetuniformlocation ( programid, temps ) ; 65 /* On i n i t i a l i s e l a v a r i a b l e avant l a f f i c h a g e */ 66 gluniform1f ( temps_loc, temps ) ; 67 84

85 Chapitre 6 : Initiation à GLSL 68 int i, j ; 69 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 70 g l C l e a r (GL_COLOR_BUFFER_BIT) ; 71 /* On u t i l i s e encore i c i l e mode de c o m p a t i b i l i t é */ 72 glbegin (GL_TRIANGLES) ; 73 for ( i =0 ; i<n f a c e s ; i++) 74 for ( j=0 ; j <3 ; j++){ 75 gltexcoord2fv ( coordtex [ f a c e s [ i ] [ j ] ] ) ; 76 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 77 } 78 glend ( ) ; 79 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 85 */ 86 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 87 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 88 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 89 SDL_Init (SDL_INIT_VIDEO) ; 90 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 91 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 92 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 93 return window ; 94 } int main ( int argc, char** argv ) 97 { 98 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 99 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 100 Dessin d un t r i a n g l e avec plaquage de t e x t u r e ) ; 101 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 102 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 105 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 106 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 109 /* c r é a t i o n des shaders */ 110 GLuint vertexid, fragmentid ; 111 GLuint programid ; 112 CreateShadersProgram(&programID, &vertexid, &fragmentid, 113 vertexshader4. txt, 114 fragmentshader4. txt ) ; 115 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* ************************************* */ 119 /* Chargement de l a t e x t u r e */ 120 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 85

86 Rémy Malgouyres, Programmation 3D avec OpenGL 121 i f (! texid ) 122 e x i t (EXIT_FAILURE) ; /* **************************************** */ 125 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 126 GLint texturemap_loc = glgetuniformlocation ( programid, texturemap ) ; 127 gluniform1ui ( texturemap_loc, texid ) ; /* *****************************************************************\ 130 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 131 \***************************************************************** */ 132 bool terminer=f a l s e ; 133 SDL_Event evenements ; /* union contenant un évennement */ 134 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ GLint nbframes=0 ; /* compteur de frames */ 137 while (! terminer ) 138 { 139 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 140 { 141 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 142 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 143 terminer = true ; 144 break ; 145 } 146 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 149 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 152 { 153 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 154 A f f i c h a g e ( nbframes, programid ) ; /* on r a f f r a i c h i t l a vue */ 155 nbframes++ ; /* On incrémente l e compteur de frames */ 156 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 157 } 158 } // L i b é r a t i o n des r e s s o u r c e s SDL 161 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 162 SDL_DestroyWindow ( window ) ; 163 SDL_Quit ( ) ; 164 return 0 ; 165 } Le Vertex shader est un fichier texte comme suit : basicshaders/progc/vertexshader4.txt 1 #v e r s i o n uniform float temps ; 4 5 // coordonnée de t e x t u r e pour i n t e p o l a t i o n 6 varying vec4 tex_coord ; 7 86

87 Chapitre 6 : Initiation à GLSL 8 void main ( void ) 9 { 10 // On récupère l a coordonnée de t e x t u r e au sommet 11 tex_coord = gl_multitexcoord0 ; 12 vec3 tmppos = vec3 ( gl_ Vertex ) ; 13 gl_position = vec4 ( 0. 7 * tmppos. x *(1+0.25* s i n ( temps ) ), * tmppos. y *(1+0.25* s i n ( temps ) ), * tmppos. z *(1+0.25* s i n ( temps ) ), 1. 0 ) ; 16 } Le Fragment shader est un fichier texte comme suit : basicshaders/progc/fragmentshader4.txt 1 // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 2 uniform sampler2d texturemap ; 3 4 // coordonnée de t e x t u r e i n t e r p o l é e 5 varying vec4 tex_coord ; 6 7 void main ( void ) 8 { 9 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 10 vec4 t e x t u r e C o l o r = texture2d ( texturemap, tex_coord. s t ) ; 11 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 12 gl_fragcolor = vec4 ( t e x t u r e C o l o r. x, t e x t u r e C o l o r. y, t e x t u r e C o l o r. z, 1. 0 ) ; 13 } Figure 6.5 : Un triangle texturé qui évolue en fonction du temps 87

88 Chapitre 7 Matrices avec GLM La librairie GLM implémente les routines usuelles sur les vecteurs et matrices dont on peut avoir besoin en lien avec GLSL. Notamment, elle implémente des fonctions de substitution pour les fonctions obsolètes du type gluperspective ou glulookat, qui sont maintenant dans le mode de compatibilité d OpenGL 4. La documentation complète de la GLM est accessible sur : Dans l exemple suivant, nous donnons un point de vue et une perspective fixes dans le main. Nous faisons d abord tourner l objet (un tétraèdre) suir lui-même d un angle lié au numéro de frame au niveau de l affichage (voir figure 7.1). La matrice composée de toutes les transformations est envoyée vers le vertex shader via une variable uniform de type mat4. Au niveau du vertex shader, la transformation est appliquée aux coordonnées des sommets. glm/progc/exlookatperspective.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #define GLM_FORCE_RADIANS 9 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 10 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 11 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 16 GLushort l a r g e u r _ f e n e t r e =700 ; 17 GLushort hauteur_fenetre =700 ; /* ************************************ */ 20 /* S t r u c t u r e de m a i l l a g e d un t r i a n g l e */ GLint n v e r t i c e s =4, n f a c e s =4 ; GLfloat v e r t i c e s [ ] [ 3 ] = { 88

89 Chapitre 7 : Matrices avec GLM 25 { 0.5, 1. 0, 0. 0 }, 26 { 1. 0, 0.5, 0. 0 }, 27 { 1.0, 1.0, 0. 0 }, 28 { 0. 0, 0. 0, 1.0} 29 } ; GLfloat c o l o r s [ ] [ 3 ] = { 32 { 1. 0, 0. 0, 0. 0 }, 33 { 0. 0, 1. 0, 0. 0 }, 34 { 0. 0, 0. 0, 1. 0 }, 35 { 0. 0, 0. 0, 0.0} 36 } ; GLuint f a c e s [ ] [ 3 ] = { 39 {0, 1, 2}, 40 {2, 1, 3}, 41 {3, 1, 0}, 42 {2, 3, 0} 43 } ; /* *************************************** */ 47 /* a f f i c h a g e */ 48 void A f f i c h a g e ( glm : :mat4 totalviewtransform, GLint nbframes, GLuint programid ) 49 { 50 // On f a i t tourner l o b j e t sur l u i même : 51 glm : :mat4 totaltransform = totalviewtransform * glm : :r o t a t e ( 52 glm : :mat4 ( 1. 0 f ), // matrice i d e n t i t e 53 nbframes *0.2 f, // angle 54 glm : :vec3 ( 0. 0 f, 0. 0 f, 1. 0 f ) // axe de r o t a t i o n 55 ) ; 56 // envoi de l a matrice v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 57 GLint transformmatrix_loc = glgetuniformlocation ( programid, transformmatrix ) ; 58 gluniformmatrix4fv ( transformmatrix_loc, 1, GL_FALSE, glm : :value_ptr ( totaltransform ) ) ; int i, j ; 61 g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 62 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; 63 /* On u t i l i s e encore i c i l e mode de c o m p a t i b i l i t é */ 64 glbegin (GL_TRIANGLES) ; 65 for ( i =0 ; i<n f a c e s ; i++) 66 for ( j=0 ; j <3 ; j++){ 67 g l C o l o r 3 f v ( c o l o r s [ f a c e s [ i ] [ j ] ] ) ; 68 g l V e r t e x 3 f v ( v e r t i c e s [ f a c e s [ i ] [ j ] ] ) ; 69 } 70 glend ( ) ; 71 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 77 */ 78 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 89

90 79 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 80 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 81 SDL_Init (SDL_INIT_VIDEO) ; 82 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 83 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 84 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 85 return window ; 86 } int main ( int argc, char** argv ) 89 { 90 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 91 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 92 Un t é t r a è d r e qui tourne sur l u i même ) ; 93 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 94 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 97 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 98 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 101 /* c r é a t i o n des shaders */ 102 GLuint vertexid, fragmentid ; 103 GLuint programid ; 104 CreateShadersProgram(&programID, &vertexid, &fragmentid, 105 vertexshader1. txt, 106 fragmentshader1. txt ) ; 107 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* ************************************************* */ 110 /* D é f i n i t i o n de l a p e r s p e c t i v e */ 111 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, f, f ) ; glm : :mat4 modelviewmatrix = glm : :lookat ( 116 glm : :vec3 ( 2. 0, 2. 0, 2. 0 ), // eye p o s i t i o n 117 glm : :vec3 ( 0. 0, 0. 0, 0. 0 ), // c e n t e r p o s i t i o n 118 glm : :vec3 ( 0. 0, 0. 0, 1. 0 ) ) ; // v e r t i c a l apearing v e c t o r glm : :mat4 totalviewtransform = p r o j e c t i o n M a t r i x *modelviewmatrix ; glenable (GL_DEPTH_TEST) ; /* *****************************************************************\ 125 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 126 \***************************************************************** */ 127 bool terminer=f a l s e ; 128 SDL_Event evenements ; /* union contenant un évennement */ 129 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 132 while (! terminer ) 90

91 Chapitre 7 : Matrices avec GLM 133 { 134 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 135 { 136 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 137 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 138 terminer = true ; 139 break ; 140 } 141 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 144 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 147 { 148 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 149 A f f i c h a g e ( totalviewtransform, nbframes, programid ) ; /* on r a f f r a i c h i t l a vue */ 150 nbframes++ ; /* On incrémente l e compteur de frames */ 151 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 152 } 153 } // L i b é r a t i o n des r e s s o u r c e s SDL 156 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 157 SDL_DestroyWindow ( window ) ; 158 SDL_Quit ( ) ; 159 return 0 ; 160 } Le vertex shader est le suivant : glm/progc/vertexshader1.txt 1 #v e r s i o n uniform mat4 transformmatrix ; 4 5 void main ( void ) 6 { 7 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 8 gl_position = transformmatrix * gl_vertex ; 9 // D é f i n i t i o n de l a c o u l e u r au sommet 10 gl_ FrontColor = gl_ Color ; 11 } Le fragment shader est le suivant : 1 #v e r s i o n void main ( void ) 4 { 5 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 6 gl_ FragColor = gl_ Color ; 7 } glm/progc/fragmentshader1.txt 91

92 (a) Capture d écran 1 (b) Capture d écran 2 Figure 7.1 : Deux captures d écran d un tétraèdre en rotation 92

93 Chapitre 8 Vertex Buffer Objects (VBO) 8.1 Vertex Buffer Objects avec attributs prédéfinis Les Vertex Buffer Object, en permettant de stocker une fois pour toutes les maillages en mémoire vidéo, permettent un affichage beaucoup plus rapide que le mode de compatibilité que nous avons vu jusqu à présent. Le principe est de stocker toutes les coordonnées des sommets, toutes les coordonnées de textures, éventuellement les normales, etc. dans un seul tableau, ainsi que les indices des faces. Ces données spécifiées pour chaque sommets s appellent des attributs des sommets et sont alors accessibles dans le vertex shader. Les routines suivantes permettent par exemple de créer des VBOs avec coordonnées de position et de texture. vbo/progc/vbo_utils.h 1 #include <GLES3/ g l 3. h> /** Création des b u f f e r s contenant l e s i n f o r m a t i o n s sur l e m a i l l a g e 6 ( faces, sommets, e t l e u r s a t t r i v u t s t e l s que l e s coordonnées de t e x t u r e ). vertexarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des sommets elementarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des i n d i c e s des f a c e s nvertices nombre de sommets du maillage, ncomponents nombre de coordonnées par sommet n I n d i c e s nombre t o t a l d i n d i c e s de sommets dans l e s f a c e s vertexarray t a b l e a u des coordonnées des sommets texcoordarray t a b l e a u des coordonnées de t e x t u r e des sommets i n d i c e s t a b l e a u des i n d i c e s des sommets, l e s f a c e s l e s unes après l e s a u t r e s usage paramètre usage de g l B u f f e r D a t a ( v o i r l e s s p é c i f i c a t i o n s d OpenGL) 16 */ 17 void CreateFloatVBOs ( GLuint program, 18 GLuint * vertexarrayobj, GLuint * elementarrayobj, 19 GLint nvertices, GLint ncomponents, GLint nindices, 20 GLfloat * vertexarray, 21 GLfloat * texcoordarray, 22 GLuint * i n d i c e s, 23 GLenum usage 93

94 Rémy Malgouyres, Programmation 3D avec OpenGL 24 ) ; /** Permet d a c t i v e r des VBO avant l e u r u t i l i s a t i o n 28 pour a f f i c h a g e. program Le programme elementarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s i n d i c e s vertexarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s sommets e t l e u r s a t t r i b u t s ncomponents nombre de coordonnées par sommets nvertices nombre de sommets 34 */ 35 void enablevbo ( GLuint program, GLuint elementarrayobj, GLuint vertexarrayobj, 36 GLint ncomponents, GLint n V e r t i c e s ) ; vbo/progc/vbo_utils.cpp 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> #include vbo_utils. h 9 10 /** Création des b u f f e r s contenant l e s i n f o r m a t i o n s sur l e m a i l l a g e 12 ( faces, sommets, e t l e u r s a t t r i v u t s t e l s que l e s coordonnées de t e x t u r e ). vertexarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des sommets elementarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des i n d i c e s des f a c e s nvertices nombre de sommets du maillage, ncomponents nombre de coordonnées par sommet n I n d i c e s nombre t o t a l d i n d i c e s de sommets dans l e s f a c e s vertexarray t a b l e a u des coordonnées des sommets texcoordarray t a b l e a u des coordonnées de t e x t u r e des sommets i n d i c e s t a b l e a u des i n d i c e s des sommets, l e s f a c e s l e s unes après l e s a u t r e s usage paramètre usage de g l B u f f e r D a t a ( v o i r l e s s p é c i f i c a t i o n s d OpenGL) 22 */ 23 void CreateFloatVBOs ( GLuint program, 24 GLuint * vertexarrayobj, GLuint * elementarrayobj, 25 GLint nvertices, GLint ncomponents, GLint nindices, 26 GLfloat * vertexarray, 27 GLfloat * texcoordarray, 28 GLuint * i n d i c e s, 29 GLenum usage 30 ) { gluseprogram ( program ) ; // ///////////////////////////////////////////// 94

95 Chapitre 8 : Vertex Buffer Objects (VBO) 36 // Envoi des sommets e t coordonnées de t e x t u r e 37 // v e r s des B u f f e r s en mémoire v idéo 38 // ///////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 41 GLuint vertexarrayobject ; 42 glgenbuffers ( 1, &vertexarrayobject ) ; 43 * vertexarrayobj=vertexarrayobject ; 44 // S é l e c t i o n du b u f f e r 45 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobject ) ; // a l l o c a t i o n de mémoire vidéo pour l ensemble 48 // Sommets+Coordonnées de t e x t u r e 49 glbufferdata (GL_ARRAY_BUFFER, 50 ( ncomponents+2)* sizeof ( GLfloat ) * nvertices, 51 NULL, 52 usage ) ; // Transfer des sommets de l a RAM v e r s l e b u f f e r en mémoire v i d é o 55 glbuffersubdata (GL_ARRAY_BUFFER, 0, ncomponents* sizeof ( GLfloat ) * n V e r t i c e s, vertexarray ) ; // Transfer des coordonnées de t e x t u r e de l a RAM v e r s l e b u f f e r en mémoire vidéo 58 glbuffersubdata (GL_ARRAY_BUFFER, ncomponents* sizeof ( GLfloat ) * nvertices, 2* sizeof ( GLfloat ) * nvertices, texcoordarray ) ; // On i n d i q u e q u e l l e s données correspondent aux sommet 61 // e t q u e l l e s données correspondent aux coordonnées de t e x t u r e 62 g l V e r t e x P o i n t e r ( ncomponents, GL_FLOAT, 0, 0) ; 63 gltexcoordpointer ( 2, GL_FLOAT, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; // //////////////////////////////////////////////// 66 // Création des b u f f e r s pour l e s i n d i c e s de sommets d é f i n i s s a n t 67 // l e s f a c e s e t envoi de l a RAM v e r s des b u f f e r s en mémoire v i d é o 68 // //////////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 71 GLuint elementarrayobject ; 72 glgenbuffers ( 1, &elementarrayobject ) ; 73 * elementarrayobj=elementarrayobject ; 74 // s é l e c t i o n du b u f f e r 75 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobject ) ; // envoi des i n d i c e s de l a RAM v e r s l e b u f f e r en mémoire v i d é o 78 glbufferdata (GL_ELEMENT_ARRAY_BUFFER, n I n d i c e s * sizeof ( GLuint ), i n d i c e s, usage ) ; } /** Permet d a c t i v e r des VBO avant l e u r u t i l i s a t i o n 84 pour a f f i c h a g e. program Le programme elementarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s i n d i c e s vertexarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s sommets e t l e u r s 95

96 Rémy Malgouyres, Programmation 3D avec OpenGL a t t r i b u t s 88 */ 89 void enablevbo ( GLuint program, GLuint elementarrayobj, GLuint vertexarrayobj, 90 GLint ncomponents, GLint n V e r t i c e s ) { 91 // S é l e c t i o n du programme 92 gluseprogram ( program ) ; 93 // a c t i v a t i o n des v e r t e x array 94 g l E n a b l e C l i e n t S t a t e (GL_VERTEX_ARRAY) ; 95 // On i n d i q u e de q u e l b u f f e r proviennent l e s sommets 96 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobj ) ; 97 // A c t i v a t i o n des coordonnées de t e x t u r e 98 g l E n a b l e C l i e n t S t a t e (GL_TEXTURE_COORD_ARRAY) ; 99 // On i n d i q u e de q u e l b u f f e r proviennent l e s coodonnées de t e x t u r e 100 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobj ) ; 101 g l V e r t e x P o i n t e r ( ncomponents, GL_FLOAT, 0, 0) ; 102 gltexcoordpointer ( 2, GL_FLOAT, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; 103 } Dans l exemple suivant, nous affichons un tétraèdre tournant. Il faut noter que, pour la cohérence des coordonnées de textures, un sommet ne peut pas vraiment être partagé entre plusieurs faces dans le tétraèdre (voir figure 8.1), et nous avons dû éclater le tétraèdre pour qu il ait 12 sommets. vbo/progc/exsimplevbo.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #define GLM_FORCE_RADIANS 9 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 10 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 11 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h 14 #include vbo_utils. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 17 GLushort l a r g e u r _ f e n e t r e =700 ; 18 GLushort hauteur_fenetre =700 ; /* ************************************ */ 21 /* S t r u c t u r e de m a i l l a g e d un t é t r a è d r e */ GLint n v e r t i c e s =12, n f a c e s =4 ; GLfloat v e r t i c e s [ ] = { 26 // sommets de l a f a c e , 1. 0, 0. 0, , , 0. 0, , 0. 0, 0. 0, // sommets de l a f a c e 1 96

97 Chapitre 8 : Vertex Buffer Objects (VBO) , , 0. 0, , 0. 0, 0. 0, , 0. 0, 1. 0, // sommets de l a f a c e , 0. 0, 1. 0, , , 0. 0, , 1. 0, 0. 0, // sommets de l a f a c e , 0. 0, 0. 0, , 0. 0, 1. 0, , 1. 0, } ; GLfloat texcoord [ ] = { 48 // sommets de l a f a c e , 1. 0, , 0.5, , 1.0, // sommets de l a f a c e , 0.5, , 1.0, , 0. 0, // sommets de l a f a c e , 0. 0, , 0.5, , 1. 0, // sommets de l a f a c e , 1.0, , 0. 0, , } ; /* *************************************** */ GLuint f a c e s [ ] = { 73 0, 1, 2, 74 3, 4, 5, 75 6, 7, 8, 76 9, 10, } ; /* a f f i c h a g e */ 82 void A f f i c h a g e ( glm : :mat4 totalviewtransform, GLint nbframes, GLuint programid, 83 GLuint elementarrayobj, GLuint vertexarrayobj ) 84 { 85 // On f a i t tourner l o b j e t sur l u i même : 86 glm : :mat4 totaltransform = totalviewtransform * glm : :r o t a t e ( 87 glm : :mat4 ( 1. 0 f ), // matrice i d e n t i t e 97

98 Rémy Malgouyres, Programmation 3D avec OpenGL 88 nbframes *0.8 f, // a n g l e 89 glm : :vec3 ( 0. 0 f, 0. 0 f, 1. 0 f ) // axe de r o t a t i o n 90 ) ; 91 // envoi de l a matrice v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 92 GLint transformmatrix_loc = glgetuniformlocation ( programid, transformmatrix ) ; 93 gluniformmatrix4fv ( transformmatrix_loc, 1, GL_FALSE, 94 glm : :value_ptr ( totaltransform ) ) ; 95 enablevbo ( programid, elementarrayobj, vertexarrayobj, 3, 1 2) ; g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 98 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; gldrawelements (GL_TRIANGLES, 1 2, GL_UNSIGNED_INT, NULL) ; } GLuint loadbmptexture ( const char * f i l e n a m e ) 105 { 106 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 109 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 112 glgentextures ( 1, &tex_ id ) ; 113 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 116 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 117 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 120 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 121 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 124 return tex_id ; 125 } Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 131 */ 132 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 133 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 134 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 135 SDL_Init (SDL_INIT_VIDEO) ; 136 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 137 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 138 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 139 return window ; 98

99 Chapitre 8 : Vertex Buffer Objects (VBO) 140 } int main ( int argc, char** argv ) 143 { 144 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 145 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 146 Un t é t r a è d r e qui tourne sur l u i même ) ; 147 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 148 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 151 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 152 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 155 /* c r é a t i o n des shaders */ 156 GLuint vertexid, fragmentid ; 157 GLuint programid ; 158 CreateShadersProgram(&programID, &vertexid, &fragmentid, 159 vertexshader1. txt, 160 fragmentshader1. txt ) ; 161 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* ************************************************* */ 164 /* D é f i n i t i o n de l a p e r s p e c t i v e */ 165 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, f, f ) ; glm : :mat4 modelviewmatrix = glm : :lookat ( 170 glm : :vec3 ( 2. 0, 2. 0, 2. 0 ), // eye p o s i t i o n 171 glm : :vec3 ( 0. 0, 0. 0, 0. 0 ), // c e n t e r p o s i t i o n 172 glm : :vec3 ( 0. 0, 0. 0, 1. 0 ) ) ; // v e r t i c a l apearing v e c t o r glm : :mat4 totalviewtransform = p r o j e c t i o n M a t r i x * modelviewmatrix ; glenable (GL_DEPTH_TEST) ; /* ************************************ */ 179 /* Création des Vertex Buffer O b j e c t s */ GLuint vertexarrayobj, elementarrayobj ; 182 CreateFloatVBOs ( programid, 183 &vertexarrayobj, &elementarrayobj, , 3, 12, 185 v e r t i c e s, texcoord, f a c e s, 186 GL_STATIC_DRAW) ; /* ************************************* */ 189 /* Chargement de l a t e x t u r e */ 190 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 191 i f (! texid ) 192 e x i t (EXIT_FAILURE) ; /* **************************************** */ 195 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 99

100 Rémy Malgouyres, Programmation 3D avec OpenGL 196 GLint texturemap_loc = glgetuniformlocation ( programid, texturemap ) ; 197 gluniform1ui ( texturemap_loc, texid ) ; /* *****************************************************************\ 200 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 201 \***************************************************************** */ 202 bool terminer=f a l s e ; 203 SDL_Event evenements ; /* union contenant un évennement */ 204 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 207 while (! terminer ) 208 { 209 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 210 { 211 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 212 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 213 terminer = true ; 214 break ; 215 } 216 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 219 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 222 { 223 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 224 A f f i c h a g e ( totalviewtransform, nbframes, programid, 225 elementarrayobj, vertexarrayobj ) ; /* on r a f f r a i c h i t l a vue */ 226 nbframes++ ; /* On incrémente l e compteur de frames */ 227 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 228 } 229 } // L i b é r a t i o n des r e s s o u r c e s SDL 232 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 233 SDL_DestroyWindow ( window ) ; 234 SDL_Quit ( ) ; 235 return 0 ; 236 } Le vertex shader est le suivant : vbo/progc/vertexshader1.txt 1 #v e r s i o n uniform mat4 transformmatrix ; 5 6 // coordonnée de t e x t u r e pour i n t e p o l a t i o n 7 varying vec4 tex_coord ; 8 9 void main ( void ) 10 { 11 // On récupère l a coordonnée de t e x t u r e au sommet 100

101 Chapitre 8 : Vertex Buffer Objects (VBO) Figure 8.1 : Capture d écran d un tétraèdre texturé en rotation 12 tex_coord = gl_multitexcoord0 ; 13 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 14 gl_position = transformmatrix * gl_vertex ; 15 } Le fragment shader est le suivant : vbo/progc/fragmentshader1.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 6 // coordonnée de t e x t u r e i n t e r p o l é e 7 varying vec4 tex_coord ; 8 9 void main ( void ) 10 { 11 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 12 vec4 t e x t u r e C o l o r = texture2d ( texturemap, tex_coord. s t ) ; 13 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 14 gl_fragcolor = vec4 ( t e x t u r e C o l o r. x, t e x t u r e C o l o r. y, t e x t u r e C o l o r. z, 1. 0 ) ; 15 } 8.2 Attributs génériques Les attributs prédéfinis (position, normale, coordonnées de textures), définis au niveau du VBO par les fonctions ad-hoc glvertexpointer, glnormalpointer, gltexcoordpointer, activées avec des constantes ad-hoc par la fonction glenableclientstate puis accessible dans le vertex shader grace aux noms réservés gl_vertex, gl_normal, gl_multitexcoord*, ont été déclarée obsolètes dans la version 3.1 d OpenGL. Elles sont tolérées dans OpenGL 4 ne font 101

102 Rémy Malgouyres, Programmation 3D avec OpenGL plus partie du core d OpenGL. Notez que la vesrion d OpenGL a de l importance car selon la carte graphique la version la plus récente supportée varie! Il vaut donc mieux leur préférer les attributs génériques (qui comme leur nom l indique dont plus souples) que nous présentons ici. Pour cela, 1. On déclare les noms d attributs génériques avec l index qui leur correspond, par un appel de la fonction glbindattriblocation, juste avant l édition des liens du programme OpenGL. 2. On active cet attribut par un appel de glenablevertexattribarray qui prend en argument l index de l attribut. 3. On indique l emplacement mémoire et le format des données de cet attribut par un appel à glvertexattribpointer qui prend comme premier paramètre l index. 4. Au niveau du vertex shader, on déclare l attribut in avec le nom défini dans l appel de glbindattriblocation. Rassurez-vous, voici un exemple (le même que le précédent, mais aux normes pour GLSL 3.3) : vbo/progc/vbo_utils2.cpp 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include vbo_utils. h 5 6 /** Création des b u f f e r s contenant l e s i n f o r m a t i o n s sur l e m a i l l a g e 8 ( faces, sommets, e t l e u r s a t t r i v u t s t e l s que l e s coordonnées de t e x t u r e ). vertexarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des sommets elementarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des i n d i c e s des f a c e s nvertices nombre de sommets du maillage, ncomponents nombre de coordonnées par sommet n I n d i c e s nombre t o t a l d i n d i c e s de sommets dans l e s f a c e s vertexarray t a b l e a u des coordonnées des sommets texcoordarray t a b l e a u des coordonnées de t e x t u r e des sommets i n d i c e s t a b l e a u des i n d i c e s des sommets, l e s f a c e s l e s unes après l e s a u t r e s usage paramètre usage de g l B u f f e r D a t a ( v o i r l e s s p é c i f i c a t i o n s d OpenGL) 18 */ 19 void CreateFloatVBOs ( GLuint program, 20 GLuint * vertexarrayobj, GLuint * elementarrayobj, 21 GLint nvertices, GLint ncomponents, GLint nindices, 22 GLfloat * vertexarray, 23 GLfloat * texcoordarray, 24 GLuint * i n d i c e s, 25 GLenum usage 26 ) { gluseprogram ( program ) ;

103 Chapitre 8 : Vertex Buffer Objects (VBO) 31 // ///////////////////////////////////////////// 32 // Envoi des sommets e t coordonnées de t e x t u r e 33 // v e r s des B u f f e r s en mémoire v idéo 34 // ///////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 37 GLuint vertexarrayobject ; 38 glgenbuffers ( 1, &vertexarrayobject ) ; 39 * vertexarrayobj=vertexarrayobject ; 40 // S é l e c t i o n du b u f f e r 41 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobject ) ; // a l l o c a t i o n de mémoire vidéo pour l ensemble 44 // Sommets+Coordonnées de t e x t u r e 45 glbufferdata (GL_ARRAY_BUFFER, 46 ( ncomponents+2)* sizeof ( GLfloat ) * nvertices, 47 NULL, 48 usage ) ; // Transfer des sommets de l a RAM v e r s l e b u f f e r en mémoire v i d é o 51 glbuffersubdata (GL_ARRAY_BUFFER, 0, ncomponents* sizeof ( GLfloat ) * n V e r t i c e s, vertexarray ) ; // Transfer des coordonnées de t e x t u r e de l a RAM v e r s l e b u f f e r en mémoire vidéo 54 glbuffersubdata (GL_ARRAY_BUFFER, ncomponents* sizeof ( GLfloat ) * nvertices, 2* sizeof ( GLfloat ) * nvertices, texcoordarray ) ; // On i n d i q u e q u e l l e s données correspondent aux sommet 57 // e t q u e l l e s données correspondent aux coordonnées de t e x t u r e // 1) sommets, à l i n d i c e 0 60 g l V e r t e x A t t r i b P o i n t e r ( 0, ncomponents, GL_FLOAT, GL_FALSE, 0, 0) ; 61 // 2) Coordonnées de t e x t u r e s à l i n d i c e 1 62 g l V e r t e x A t t r i b P o i n t e r ( 1, 2, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; // //////////////////////////////////////////////// 65 // Création des b u f f e r s pour l e s i n d i c e s de sommets d é f i n i s s a n t 66 // l e s f a c e s e t envoi de l a RAM v e r s des b u f f e r s en mémoire v i d é o 67 // //////////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 70 GLuint elementarrayobject ; 71 glgenbuffers ( 1, &elementarrayobject ) ; 72 * elementarrayobj=elementarrayobject ; 73 // s é l e c t i o n du b u f f e r 74 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobject ) ; // envoi des i n d i c e s de l a RAM v e r s l e b u f f e r en mémoire v i d é o 77 glbufferdata (GL_ELEMENT_ARRAY_BUFFER, n I n d i c e s * sizeof ( GLuint ), i n d i c e s, usage ) ; } /** Permet d a c t i v e r des VBO avant l e u r u t i l i s a t i o n 103

104 Rémy Malgouyres, Programmation 3D avec OpenGL 83 pour a f f i c h a g e. program Le programme elementarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s i n d i c e s vertexarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s sommets e t l e u r s a t t r i b u t s 87 */ 88 void enablevbo ( GLuint program, GLuint elementarrayobj, GLuint vertexarrayobj, 89 GLint ncomponents, GLint n V e r t i c e s ) { 90 // S é l e c t i o n du programme 91 gluseprogram ( program ) ; // a c t i v a t i o n des v e r t e x array 94 glenablevertexattribarray ( 0 ) ; 95 // A c t i v a t i o n des coordonnées de t e x t u r e 96 glenablevertexattribarray ( 1 ) ; // On i n d i q u e de q u e l b u f f e r proviennent l e s sommets 99 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobj ) ; 100 // On i n d i q u e de q u e l b u f f e r proviennent l e s coodonnées de t e x t u r e 101 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobj ) ; // On i n d i q u e q u e l l e s données correspondent aux sommet 104 // e t q u e l l e s données correspondent aux coordonnées de t e x t u r e // 1) sommets, à l i n d i c e g l V e r t e x A t t r i b P o i n t e r ( 0, ncomponents, GL_FLOAT, GL_FALSE, 0, 0) ; 108 // 2) Coordonnées de t e x t u r e s à l i n d i c e g l V e r t e x A t t r i b P o i n t e r ( 1, 2, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; 110 } vbo/progc/exgenericattrib.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include <SDL2/SDL. h> 5 #include <SDL2/ SDL_opengl. h> 6 #include <GLES3/ g l 3. h> 7 8 #define GLM_FORCE_RADIANS 9 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 10 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 11 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h 14 #include vbo_utils. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 17 GLushort l a r g e u r _ f e n e t r e =700 ; 18 GLushort hauteur_fenetre =700 ; /* ************************************ */ 21 /* S t r u c t u r e de m a i l l a g e d un t é t r a è d r e */ GLint n v e r t i c e s =12, n f a c e s =4 ; 104

105 Chapitre 8 : Vertex Buffer Objects (VBO) GLfloat v e r t i c e s [ ] = { 26 // sommets de l a f a c e , 1. 0, 0. 0, , , 0. 0, , 0. 0, 0. 0, // sommets de l a f a c e , , 0. 0, , 0. 0, 0. 0, , 0. 0, 1. 0, // sommets de l a f a c e , 0. 0, 1. 0, , , 0. 0, , 1. 0, 0. 0, // sommets de l a f a c e , 0. 0, 0. 0, , 0. 0, 1. 0, , 1. 0, } ; GLfloat texcoord [ ] = { 48 // sommets de l a f a c e , 1. 0, , 0.5, , 1.0, // sommets de l a f a c e , 0.5, , 1.0, , 0. 0, // sommets de l a f a c e , 0. 0, , 0.5, , 1. 0, // sommets de l a f a c e , 1.0, , 0. 0, , } ; /* *************************************** */ GLuint f a c e s [ ] = { 73 0, 1, 2, 74 3, 4, 5, 75 6, 7, 8, 76 9, 10, } ;

106 Rémy Malgouyres, Programmation 3D avec OpenGL /* a f f i c h a g e */ 82 void A f f i c h a g e ( glm : :mat4 totalviewtransform, GLint nbframes, GLuint programid, 83 GLuint elementarrayobj, GLuint vertexarrayobj ) 84 { 85 // On f a i t tourner l o b j e t sur l u i même : 86 glm : :mat4 totaltransform = totalviewtransform * glm : :r o t a t e ( 87 glm : :mat4 ( 1. 0 f ), // matrice i d e n t i t e 88 nbframes *0.8 f, // a n g l e 89 glm : :vec3 ( 0. 0 f, 0. 0 f, 1. 0 f ) // axe de r o t a t i o n 90 ) ; 91 // envoi de l a matrice v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 92 GLint transformmatrix_loc = glgetuniformlocation ( programid, transformmatrix ) ; 93 gluniformmatrix4fv ( transformmatrix_loc, 1, GL_FALSE, 94 glm : :value_ptr ( totaltransform ) ) ; 95 enablevbo ( programid, elementarrayobj, vertexarrayobj, 3, 1 2) ; g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 98 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; gldrawelements (GL_TRIANGLES, 1 2, GL_UNSIGNED_INT, NULL) ; } GLuint loadbmptexture ( const char * f i l e n a m e ) 105 { 106 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 109 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 112 glgentextures ( 1, &tex_ id ) ; 113 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 116 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 117 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 120 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 121 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 124 return tex_id ; 125 } Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 131 */ 132 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 133 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 106

107 Chapitre 8 : Vertex Buffer Objects (VBO) 134 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 135 SDL_Init (SDL_INIT_VIDEO) ; 136 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 137 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 138 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 139 return window ; 140 } int main ( int argc, char** argv ) 143 { 144 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 145 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 146 Un t é t r a è d r e qui tourne sur l u i même ) ; 147 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 148 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 151 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 152 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 155 /* c r é a t i o n des shaders */ 156 GLuint vertexid, fragmentid ; 157 GLuint programid ; 158 CreateShadersProgram(&programID, &vertexid, &fragmentid, 159 vertexshader2. txt, 160 fragmentshader2. txt ) ; 161 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* ************************************************* */ 164 /* D é f i n i t i o n de l a p e r s p e c t i v e */ 165 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, f, f ) ; glm : :mat4 modelviewmatrix = glm : :lookat ( 170 glm : :vec3 ( 2. 0, 2. 0, 2. 0 ), // eye p o s i t i o n 171 glm : :vec3 ( 0. 0, 0. 0, 0. 0 ), // c e n t e r p o s i t i o n 172 glm : :vec3 ( 0. 0, 0. 0, 1. 0 ) ) ; // v e r t i c a l apearing v e c t o r glm : :mat4 totalviewtransform = p r o j e c t i o n M a t r i x * modelviewmatrix ; glenable (GL_DEPTH_TEST) ; /* ************************************ */ 179 /* Création des Vertex Buffer O b j e c t s */ GLuint vertexarrayobj, elementarrayobj ; 182 CreateFloatVBOs ( programid, 183 &vertexarrayobj, &elementarrayobj, , 3, 12, 185 v e r t i c e s, texcoord, f a c e s, 186 GL_STATIC_DRAW) ;

108 Rémy Malgouyres, Programmation 3D avec OpenGL 188 /* ************************************* */ 189 /* Chargement de l a t e x t u r e */ 190 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 191 i f (! texid ) 192 e x i t (EXIT_FAILURE) ; /* **************************************** */ 195 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 196 GLint texturemap_loc = glgetuniformlocation ( programid, texturemap ) ; 197 gluniform1ui ( texturemap_loc, texid ) ; /* *****************************************************************\ 200 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 201 \***************************************************************** */ 202 bool terminer=f a l s e ; 203 SDL_Event evenements ; /* union contenant un évennement */ 204 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 207 while (! terminer ) 208 { 209 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 210 { 211 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 212 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 213 terminer = true ; 214 break ; 215 } 216 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 219 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 222 { 223 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 224 A f f i c h a g e ( totalviewtransform, nbframes, programid, 225 elementarrayobj, vertexarrayobj ) ; /* on r a f f r a i c h i t l a vue */ 226 nbframes++ ; /* On incrémente l e compteur de frames */ 227 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 228 } 229 } // L i b é r a t i o n des r e s s o u r c e s SDL 232 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 233 SDL_DestroyWindow ( window ) ; 234 SDL_Quit ( ) ; 235 return 0 ; 236 } Le vertex shader est le suivant (notez le numéro de version de GLSL qui impose une norme) : 1 #v e r s i o n uniform mat4 transformmatrix ; vbo/progc/vertexshader2.txt 108

109 Chapitre 8 : Vertex Buffer Objects (VBO) 4 5 // d é c l a r a t i o n des a t t r i b u t s. 6 // Le nom des a t t r i b u t s e s t d é c l a r é dans l e g l B i n d A t t r i b L o c a t i o n 7 in vec3 P o s i t i o n ; 8 i n vec2 TexCoord ; 9 10 // coordonnée de t e x t u r e pour i n t e p o l a t i o n 11 out vec2 tex_coord ; void main ( void ) 14 { 15 // On récupère l a coordonnée de t e x t u r e au sommet 16 tex_ coord = TexCoord ; 17 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 18 gl_position = transformmatrix * vec4 ( P o s i t i o n. x, P o s i t i o n. y, P o s i t i o n. z, 1. 0 ) ; 19 } Le fragment shader est le suivant (notez le numéro de version de GLSL qui impose une norme) : vbo/progc/fragmentshader2.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 6 // coordonnée de t e x t u r e i n t e r p o l é e 7 i n vec2 tex_ coord ; 8 9 void main ( void ) 10 { 11 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 12 vec4 t e x t u r e C o l o r = texture2d ( texturemap, tex_coord ) ; 13 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 14 gl_fragcolor = vec4 ( t e x t u r e C o l o r. x, t e x t u r e C o l o r. y, t e x t u r e C o l o r. z, 1. 0 ) ; 15 } 109

110 Chapitre 9 Éclairement avec shaders et VBO 9.1 Sources dans le repère de la caméra La gestion de l éclairage du mode de compatibilité doit maintenant être remplacée par une gestion à la main dans les shaders. Cela peut paraitre beaucoup de travail mais le gros avantage est la rapidité, mais surtout la liberté que l on gagne. Dans la gestion des Vertex Buffer Objects (VBO) ci-dessous, on ajoute par rapport à la version précédente la gestion des normales. shadingvbo/progc/vbo_utils.cpp 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 4 #include vbo_utils. h 5 6 /** Création des b u f f e r s contenant l e s i n f o r m a t i o n s sur l e m a i l l a g e 8 ( faces, sommets, e t l e u r s a t t r i v u t s t e l s que l e s coordonnées de t e x t u r e ). vertexarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des sommets elementarrayobject passage par a d r e s s e de l i d e n t i f i a n t du b u f f e r des i n d i c e s des f a c e s nvertices nombre de sommets du maillage, ncomponents nombre de coordonnées par sommet n I n d i c e s nombre t o t a l d i n d i c e s de sommets dans l e s f a c e s vertexarray t a b l e a u des coordonnées des sommets texcoordarray t a b l e a u des coordonnées de t e x t u r e des sommets i n d i c e s t a b l e a u des i n d i c e s des sommets, l e s f a c e s l e s unes après l e s a u t r e s usage paramètre usage de g l B u f f e r D a t a ( v o i r l e s s p é c i f i c a t i o n s d OpenGL) 18 */ 19 void CreateFloatVBOs ( GLuint program, 20 GLuint * vertexarrayobj, GLuint * elementarrayobj, 21 GLint nvertices, GLint ncomponents, GLint nindices, 22 GLfloat * vertexarray, 23 GLfloat *normalarray, 24 GLfloat * texcoordarray, 25 GLuint * i n d i c e s, 26 GLenum usage 110

111 Chapitre 9 : Éclairement avec shaders et VBO 27 ) { gluseprogram ( program ) ; // ///////////////////////////////////////////// 33 // Envoi des sommets e t coordonnées de t e x t u r e 34 // v e r s des B u f f e r s en mémoire v idéo 35 // ///////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 38 GLuint vertexarrayobject ; 39 glgenbuffers ( 1, &vertexarrayobject ) ; 40 * vertexarrayobj=vertexarrayobject ; 41 // S é l e c t i o n du b u f f e r 42 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobject ) ; // a l l o c a t i o n de mémoire vidéo pour l ensemble 45 // Sommets+Coordonnées de t e x t u r e 46 glbufferdata (GL_ARRAY_BUFFER, 47 (2* ncomponents+2)* sizeof ( GLfloat ) * nvertices, 48 NULL, 49 usage ) ; // Transfer des sommets de l a RAM v e r s l e b u f f e r en mémoire v i d é o 52 glbuffersubdata (GL_ARRAY_BUFFER, 0, ncomponents* sizeof ( GLfloat ) * n V e r t i c e s, vertexarray ) ; // Transfer des normales de l a RAM v e r s l e b u f f e r en mémoire v i d é o 55 glbuffersubdata (GL_ARRAY_BUFFER, ncomponents* sizeof ( GLfloat ) * nvertices, ncomponents* sizeof ( GLfloat ) * nvertices, normalarray ) ; // Transfer des coordonnées de t e x t u r e de l a RAM v e r s l e b u f f e r en mémoire vidéo 58 glbuffersubdata (GL_ARRAY_BUFFER, 2*nComponents* sizeof ( GLfloat ) * nvertices, 2* sizeof ( GLfloat ) * nvertices, texcoordarray ) ; // On i n d i q u e q u e l l e s données correspondent aux sommet 61 // e t q u e l l e s données correspondent aux coordonnées de t e x t u r e // 1) sommets, à l i n d i c e 0 65 g l V e r t e x A t t r i b P o i n t e r ( 0, ncomponents, GL_FLOAT, GL_FALSE, 0, 0) ; 66 // 2) Normales à l i n d i c e 1 67 g l V e r t e x A t t r i b P o i n t e r ( 1, 3, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; 68 // 3) Coordonnées de t e x t u r e à l i n d i c e 2 69 g l V e r t e x A t t r i b P o i n t e r ( 2, 2, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+2*nComponents * sizeof ( GLfloat ) * n V e r t i c e s ) ; // //////////////////////////////////////////////// 72 // Création des b u f f e r s pour l e s i n d i c e s de sommets d é f i n i s s a n t 73 // l e s f a c e s e t envoi de l a RAM v e r s des b u f f e r s en mémoire v i d é o 74 // //////////////////////////////////////////////// // Création d un ( i d e n t i f i a n t de ) b u f f e r 111

112 Rémy Malgouyres, Programmation 3D avec OpenGL 77 GLuint elementarrayobject ; 78 glgenbuffers ( 1, &elementarrayobject ) ; 79 * elementarrayobj=elementarrayobject ; 80 // s é l e c t i o n du b u f f e r 81 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobject ) ; // envoi des i n d i c e s de l a RAM v e r s l e b u f f e r en mémoire v i d é o 84 glbufferdata (GL_ELEMENT_ARRAY_BUFFER, n I n d i c e s * sizeof ( GLuint ), i n d i c e s, usage ) ; } /** Permet d a c t i v e r des VBO avant l e u r u t i l i s a t i o n 90 pour a f f i c h a g e. program Le programme elementarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s i n d i c e s vertexarrayobj l i d e n t i f i a n t du b u f f e r contenant l e s sommets e t l e u r s a t t r i b u t s 94 */ 95 void enablevbo ( GLuint program, GLuint elementarrayobj, GLuint vertexarrayobj, 96 GLint ncomponents, GLint n V e r t i c e s ) { 97 // S é l e c t i o n du programme 98 gluseprogram ( program ) ; // a c t i v a t i o n des v e r t e x array 101 glenablevertexattribarray ( 0 ) ; 102 // A c t i v a t i o n des normales 103 glenablevertexattribarray ( 1 ) ; 104 // A c t i v a t i o n des coordonnées de t e x t u r e 105 glenablevertexattribarray ( 2 ) ; // On i n d i q u e de q u e l b u f f e r proviennent l e s sommets 108 glbindbuffer (GL_ARRAY_BUFFER, vertexarrayobj ) ; // On i n d i q u e de q u e l b u f f e r proviennent l e s coodonnées de t e x t u r e 111 glbindbuffer (GL_ELEMENT_ARRAY_BUFFER, elementarrayobj ) ; 112 // 1) sommets, à l i n d i c e g l V e r t e x A t t r i b P o i n t e r ( 0, ncomponents, GL_FLOAT, GL_FALSE, 0, 0) ; 114 // 2) Normales à l i n d i c e g l V e r t e x A t t r i b P o i n t e r ( 1, 3, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+nComponents* sizeof ( GLfloat ) * n V e r t i c e s ) ; 116 // 3) Coordonnées de t e x t u r e à l i n d i c e g l V e r t e x A t t r i b P o i n t e r ( 2, 2, GL_FLOAT, GL_FALSE, 0, ( ( char *)NULL)+2*nComponents * sizeof ( GLfloat ) * n V e r t i c e s ) ; 118 // g l V e r t e x P o i n t e r ( ncomponents, GL_FLOAT, 0, 0) ; 119 // glnormalpointer (GL_FLOAT, 0, ( ( char *)NULL)+nComponents* s i z e o f ( GLfloat ) * nvertices ) ; 120 // gltexcoordpointer (2, GL_FLOAT, 0, ( ( char *)NULL)+2*nComponents* s i z e o f ( GLfloat ) * nvertices ) ; 121 } Dans l exemple suivant, nous affichons une sphère tournant. Nous construisons tout d abord une sphère triangulée (construction du maillage à la main ), puis nous créons une variable normale pour interpoler les normales aux sommets suivant le modèle de phong. Au niveau des changement de repère, on doit ici séparer la projectiond de la transformation modelview. La transformation à appliquer à la normale se calcule en effet à partir du modelview. Nous 112

113 Chapitre 9 : Éclairement avec shaders et VBO mettrons ici la source lumineuse dans le repère de la caméra. Pour celà, la source lumineuse est fixe dans le fragment shader. shadingvbo/progc/mesh_utils.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 #include <math. h> 4 5 #include mesh_utils. h 6 #include vbo_utils. h 7 8 /** Construction d un m a i l l a g e t r i a n g u l é pour modéliser e t 10 a f f i c h e r une sphère ( pour remplacer l a f o n c t i o n GLU). r rayon de l a sphère nbparal nombre de p a r a l l è l e s pour découper l a sphère nbmerid nombre de méridiens pour découper l a sphère pnvertices passage par a d r e s s e du nombre de sommets pnfaces passage par a d r e s s e du nombre de f a c e s p V e r t i c e s passage par a d r e s s e du t a b l e a u des sommets ptexcoord passage par a d r e s s e du t a b l e a u des coordonnées de t e x t u r e pnormals passage par a d r e s s e du t a b l e a u des normales pfaces passage par a d r e s s e du t a b l e a u des f a c e s 20 */ 21 void maillagesphere ( GLfloat r, int nbparal, int nbmerid, 22 GLuint program, GLint * nvertices, GLint * nfaces, 23 GLuint * vertexarrayobj, GLuint * elementarrayobj ) { 24 int i, j, compteur ; 25 GLfloat teta, phi, s i n t e t a, sinphi, c o s t e t a, cosphi ; // c a l c u l du nombre de sommets du m a i l l a g e 28 // e t a l l o c a t i o n des sommets : 29 GLint nbsomm = ( nbmerid+1) * nbparal + 2 ; 30 * n V e r t i c e s = nbsomm ; 31 GLfloat *tabsomm = new GLfloat [ 3 *nbsomm ] ; // a l l o c a t i o n des normales : 34 GLfloat * tabnormals = new GLfloat [ 3 *nbsomm ] ; // a l l o c a t i o n des coordonnées de t e x t u r e : 37 GLfloat *tabtexcoord = new GLfloat [ 2 *nbsomm ] ; compteur = 0 ; // compteur de sommets GLfloat pi = M_PI; 43 // i n i t i a l i s a t i o n de l a p o s i t i o n des sommets, e t des normales 44 for ( i = 0 ; i <= nbmerid ; i ++){ 45 for ( j = 1 ; j <= nbparal ; j++){ 46 // c a l c u l des a n g l e s des coordonnees s p h e r i q u e s du sommets ( i, j ) 47 t e t a = 2*( GLfloat ) pi * ( ( GLfloat ) i / ( GLfloat ) nbmerid ) ; 48 c o s t e t a = ( GLfloat ) cos ( t e t a ) ; 49 s i n t e t a = ( GLfloat ) s i n ( t e t a ) ; 50 phi = ( GLfloat ) pi * ( ( GLfloat ) j / ( GLfloat ) ( nbparal +1) ) ; 51 cosphi = ( GLfloat ) cos ( phi ) ; 52 s i n p h i = ( GLfloat ) s i n ( phi ) ; 113

114 Rémy Malgouyres, Programmation 3D avec OpenGL // p o s i s t i o n du sommet ( i, j ) : 55 tabsomm [ 3 * compteur ] = r *( c o s t e t a * s i n p h i ) ; 56 tabsomm [ 3 * compteur +1] = r * cosphi ; 57 tabsomm [ 3 * compteur +2] = r *( s i n t e t a * s i n p h i ) ; 58 // normale en ce sommet 59 tabnormals [ 3 * compteur ] = c o s t e t a * s i n p h i ; 60 tabnormals [ 3 * compteur +1] = c osphi ; 61 tabnormals [ 3 * compteur +2] = s i n t e t a * s i n p h i ; tabtexcoord [ 2 * compteur ] = t e t a /(2* pi ) ; 64 tabtexcoord [ 2 * compteur +1] = phi / pi ; 65 compteur++ ; // sommet s u i v a n t 66 } 67 } // sommet correspondant au p o l e sud de l a sphere : 70 tabsomm [ 3 * compteur ] = 0. 0 ; 71 tabsomm [ 3 * compteur +1] = r ; 72 tabsomm [ 3 * compteur +2] = 0. 0 ; 73 // normale en ce sommet 74 tabnormals [ 3 * compteur ] = 0. 0 ; 75 tabnormals [ 3 * compteur +1] = 1 ; 76 tabnormals [ 3 * compteur +2] = 0. 0 ; tabtexcoord [ 2 * compteur ] = 0. 5 ; 79 tabtexcoord [ 2 * compteur +1] = 0. 0 ; 80 compteur++ ; // sommet correspondant au p o l e nord de l a sphere : 83 tabsomm [ 3 * compteur ] = 0. 0 ; 84 tabsomm [ 3 * compteur +1] = r ; 85 tabsomm [ 3 * compteur +2] = 0. 0 ; 86 // normale en ce sommet 87 tabnormals [ 3 * compteur ] = 0. 0 ; 88 tabnormals [ 3 * compteur +1] = 1 ; 89 tabnormals [ 3 * compteur +2] = 0. 0 ; tabtexcoord [ 2 * compteur ] = 0. 5 ; 92 tabtexcoord [ 2 * compteur +1] = 1. 0 ; 93 compteur++ ; GLint nbfaces = 2* nbparal * nbmerid ; // nombre de f a c e t t e s 96 * nfaces = nbfaces ; 97 GLuint * t a b f a c e s = new GLuint [ 3 * n b f a c e s ] ; // a l l o c a t i o n des f a c e t t e s compteur = 0 ; // compteur de f a c e s // i n i t i a l i s a t i o n des numeros de sommets de chaque f a c e t t e 102 for ( i = 0 ; i < nbmerid ; i ++){ 103 for ( int j = 1 ; j < nbparal ; j++){ 104 // numeros des sommets de l a f a c e t t e : 105 t a b f a c e s [ 3 * compteur ] = ( nbparal ) * i + j ; 106 t a b f a c e s [ 3 * compteur +1] = ( nbparal ) *( i +1) + j ; 107 t a b f a c e s [ 3 * compteur +2] = ( nbparal ) *( i +1) + j 1 ;

115 Chapitre 9 : Éclairement avec shaders et VBO 109 compteur++ ; // numeros des sommets de l a f a c e t t e : 112 t a b f a c e s [ 3 * compteur ] = ( nbparal ) * i + j ; 113 t a b f a c e s [ 3 * compteur +1] = ( nbparal ) *( i +1) + j 1 ; 114 t a b f a c e s [ 3 * compteur +2] = ( nbparal ) * i + j 1 ; compteur++ ; 117 } 118 } // f a c e t t e s t r i a n g u l a i r e s touchant l e p o l e nord 121 for ( i = 0 ; i < nbmerid ; i ++){ 122 // numeros des sommets de l a f a c e t t e : 123 t a b f a c e s [ 3 * compteur ] = ( i +1)* nbparal ; 124 t a b f a c e s [ 3 * compteur +1] = ( nbmerid+1) * nbparal + 1 ; 125 t a b f a c e s [ 3 * compteur +2] = i * nbparal ; 126 compteur++ ; 127 } // f a c e t t e s t r i a n g u l a i r e s touchant l e p o l e sud 130 for ( i = 0 ; i < nbmerid ; i ++){ 131 // numeros des sommets de l a f a c e t t e : 132 t a b f a c e s [ 3 * compteur ] = ( nbmerid+1)* nbparal ; 133 t a b f a c e s [ 3 * compteur +1] = i * nbparal + nbparal 1 ; 134 t a b f a c e s [ 3 * compteur +2] = ( i +1)* nbparal + nbparal 1 ; 135 compteur++ ; 136 } // /////////////////////////////////////////////////// 139 // On envoie l e t o u t v e r s des b u f f e r s en mémoire v i d é o 140 // //////////////////////////////////////////////////// 141 CreateFloatVBOs ( program, vertexarrayobj, elementarrayobj, 142 nbsomm, 3, 3* nbfaces, 143 tabsomm, tabnormals, tabtexcoord, t a b f a c e s, 144 GL_STATIC_DRAW 145 ) ; 146 // L i b é r a t i o n de l a mémoire RAM qui ne s e r t p l u s à r i e n 147 d e l e t e t a b f a c e s ; 148 d e l e t e tabsomm ; 149 d e l e t e tabnormals ; 150 d e l e t e tabtexcoord ; 151 } shadingvbo/progc/exspherevbo.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 #include <math. h> 4 5 #include <SDL2/SDL. h> 6 #include <SDL2/ SDL_opengl. h> 7 #include <GLES3/ g l 3. h> 8 9 #define GLM_FORCE_RADIANS 10 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 115

116 Rémy Malgouyres, Programmation 3D avec OpenGL 11 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 12 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h 15 #include vbo_utils. h 16 #include mesh_utils. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 19 GLushort l a r g e u r _ f e n e t r e =700 ; 20 GLushort hauteur_fenetre =700 ; /* ************************************ */ 23 /* S t r u c t u r e de m a i l l a g e */ GLint nverticessphere ; 26 GLint nfacessphere ; 27 GLuint vertexarrayobjsphere ; 28 GLuint elementarrayobjsphere ; /* a f f i c h a g e */ 31 void A f f i c h a g e ( glm : :mat4 viewmatrix, glm : :mat4 projectionmatrix, GLint nbframes, GLuint programid ) 32 { 33 // On f a i t tourner l o b j e t sur l u i même : 34 glm : :mat4 modelviewmatrix = viewmatrix * glm : :r o t a t e ( 35 glm : :mat4 ( 1. 0 f ), // matrice i d e n t i t e 36 nbframes *0.8 f, // a n g l e 37 glm : :vec3 ( 0. 0 f, 0. 0 f, 1. 0 f ) // axe de r o t a t i o n 38 ) ; 39 // envoi des matrices v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 40 GLint modelviewmatrix_loc = glgetuniformlocation ( programid, modelviewmatrix ) ; 41 gluniformmatrix4fv ( modelviewmatrix_loc, 1, GL_FALSE, 42 glm : :value_ptr ( modelviewmatrix ) ) ; 43 GLint p r o j e c t i o n M a t r i x _ l o c = glgetuniformlocation ( programid, p r o j e c t i o n M a t r i x ) ; 44 gluniformmatrix4fv ( projectionmatrix_loc, 1, GL_FALSE, 45 glm : :value_ptr ( p r o j e c t i o n M a t r i x ) ) ; 46 enablevbo ( programid, elementarrayobjsphere, vertexarrayobjsphere, 3, nverticessphere ) ; g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 49 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; gldrawelements (GL_TRIANGLES, 3* nfacessphere, GL_UNSIGNED_INT, NULL) ; } GLuint loadbmptexture ( const char * f i l e n a m e ) 56 { 57 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 60 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 116

117 Chapitre 9 : Éclairement avec shaders et VBO 63 glgentextures ( 1, &tex_ id ) ; 64 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 67 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 68 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 71 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 72 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 75 return tex_id ; 76 } Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 82 */ 83 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 84 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 85 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 86 SDL_Init (SDL_INIT_VIDEO) ; 87 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 88 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 89 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 90 return window ; 91 } int main ( int argc, char** argv ) 94 { 95 /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 96 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 97 Un t é t r a è d r e qui tourne sur l u i même ) ; 98 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 99 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 102 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 103 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 106 /* c r é a t i o n des shaders */ 107 GLuint vertexid, fragmentid ; 108 GLuint programid ; 109 CreateShadersProgram(&programID, &vertexid, &fragmentid, 110 vertexshader1. txt, 111 fragmentshader1. txt ) ; 112 gluseprogram ( programid ) ; // s é l e c t i o n du programme /* ************************************************* */ 115 /* D é f i n i t i o n de l a p e r s p e c t i v e */ 117

118 Rémy Malgouyres, Programmation 3D avec OpenGL 116 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, f, f ) ; glm : :mat4 modelviewmatrix = glm : :lookat ( 121 glm : :vec3 ( 2. 0, 2. 0, 2. 0 ), // eye p o s i t i o n 122 glm : :vec3 ( 0. 0, 0. 0, 0. 0 ), // c e n t e r p o s i t i o n 123 glm : :vec3 ( 0. 0, 0. 0, 1. 0 ) ) ; // v e r t i c a l apearing v e c t o r glenable (GL_DEPTH_TEST) ; /* ************************************ */ 128 /* Création des Vertex Buffer O b j e c t s */ 129 maillagesphere ( 1. 0, 100, 60, programid, 130 &nverticessphere, &nfacessphere, 131 &vertexarrayobjsphere, &elementarrayobjsphere ) ; /* ************************************* */ 134 /* Chargement de l a t e x t u r e */ 135 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 136 i f (! texid ) 137 e x i t (EXIT_FAILURE) ; /* **************************************** */ 140 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 141 GLint texturemap_loc = glgetuniformlocation ( programid, texturemap ) ; 142 gluniform1ui ( texturemap_loc, texid ) ; /* *****************************************************************\ 145 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 146 \***************************************************************** */ 147 bool terminer=f a l s e ; 148 SDL_Event evenements ; /* union contenant un évennement */ 149 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 152 while (! terminer ) 153 { 154 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 155 { 156 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 157 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 158 terminer = true ; 159 break ; 160 } 161 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 164 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 167 { 168 nextdueframedate = currenttime ; 169 A f f i c h a g e ( modelviewmatrix, projectionmatrix, nbframes, programid ) ; 170 nbframes++ ; /* On incrémente l e compteur de frames */ 171 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 118

119 Chapitre 9 : Éclairement avec shaders et VBO 172 } 173 } // L i b é r a t i o n des r e s s o u r c e s SDL 176 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 177 SDL_DestroyWindow ( window ) ; 178 SDL_Quit ( ) ; 179 return 0 ; 180 } Le vertex shader est le suivant : shadingvbo/progc/vertexshader1.txt 1 #v e r s i o n uniform mat4 modelviewmatrix ; 4 uniform mat4 p r o j e c t i o n M a t r i x ; 5 6 in vec3 P o s i t i o n ; 7 i n vec3 Normal ; 8 i n vec2 TexCoord ; // coordonnée de t e x t u r e pour i n t e p o l a t i o n 12 out vec2 tex_coord ; 13 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 14 out vec3 normale ; void main ( void ) 17 { 18 // On récupère l a coordonnée de t e x t u r e au sommet 19 tex_ coord = TexCoord ; 20 // On récupère l a normale au sommet 21 normale = ( modelviewmatrix* vec4 ( Normal. x, Normal. y, Normal. z, 0. 0 ) ). xyz ; 22 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 23 gl_position = p r o j e c t i o n M a t r i x *modelviewmatrix* vec4 ( P o s i t i o n. x, P o s i t i o n. y, P o s i t i o n. z, 1. 0 ) ; 24 } Le fragment shader est le suivant : shadingvbo/progc/fragmentshader1.txt 1 #v e r s i o n // TODO : c o r r i g e r l a d i r e c t i o n de l o b s e r v a t e u r dans l e c a l c u l de R qui ve d o i t pas t r e g a l e (0,0,1) maps ( posx, posy, posz ) / 4 // sampler 2D pour rcuprer l a c o u l e u r de t e x t u r e 5 uniform sampler2d texturemap ; 6 7 // coordonne de t e x t u r e i n t e r p o l e 8 i n vec2 tex_ coord ; 9 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 10 in vec3 normale ; void main ( void ) 13 { 119

120 Rémy Malgouyres, Programmation 3D avec OpenGL Figure 9.1 : Capture d écran d une sphère texturée et éclairée en rotation 14 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 15 vec4 t e x t u r e C o l o r = texture2d ( texturemap, tex_coord ) ; 16 // source lumineuse dans l a d i r e c t i o n (1, 1, 0) dans l e repère de l a caméra 17 vec3 l i g h t D i r = vec3 ( 1. 0 / s q r t ( 2. 0 ), 1. 0 / s q r t ( 2. 0 ), 0. 0 ) ; 18 vec3 normal = normalize ( normale ) ; 19 float diffuseterm = dot ( normal, l i g h t D i r ) ; 20 i f ( diffuseterm <0) 21 diffuseterm =0.0 ; 22 vec3 R = 2* dot ( normal, vec3 ( 0. 0, 0. 0, 1. 0 ) ) *normal vec3 ( 0. 0, 0. 0, 1. 0 ) ; 23 float dotspecular = dot (R, l i g h t D i r ) ; 24 i f ( dotspecular <0) 25 dotspecular =0.0 ; 26 float s h i n i n e s s = ; 27 float specularterm = 0.5*pow( dotspecular, s h i n i n e s s ) ; // On a f f i c h e l a c o u l e u r i n t e r p o l é e 30 gl_fragcolor = vec4 ( diffuseterm * t e x t u r e C o l o r. x+specularterm, 31 diffuseterm * t e x t u r e C o l o r. y+specularterm, 32 diffuseterm * t e x t u r e C o l o r. z+specularterm, 1. 0 ) ; 33 } 9.2 Sources dans le repère du monde Par rapport au programme précédent où la source lumineuse est fixée dans le repère de la caméra, on souhaite ici fixer la source lumineuse dans le repère du monde. Pour cela, nous devons, au niveau du vertex shader, faire subir à la poisition de la source lumineuse la matrice de changement du repère du monde vers le repère de la caméra (ici, cette matrice correspond au glulookat. Pour cela, nous ajoutons une variable uniform viewmatrix dans le vertex shader. Nous transmettons ensuite cette position de la source lumineuse au fragment shader via une variable varying pour le calcul d éclairage. 120

121 Chapitre 9 : Éclairement avec shaders et VBO Dans la fonction Affichage du programme C, nous devons transmettre la matrice du glukookat au vertex shader en ajoutant les lignes : GLint viewmatrix_loc = glgetuniformlocation(programid, "viewmatrix"); gluniformmatrix4fv(viewmatrix_loc, 1, GL_FALSE, glm::value_ptr(modelviewmatrix)); Le vertex shader est le suivant : shadingvbo/progc/vertexshader2.txt 1 #v e r s i o n uniform mat4 modelviewmatrix ; 4 uniform mat4 p r o j e c t i o n M a t r i x ; 5 uniform mat4 viewmatrix ; 6 7 in vec3 P o s i t i o n ; 8 i n vec3 Normal ; 9 i n vec2 TexCoord ; // coordonnée de t e x t u r e pour i n t e p o l a t i o n 12 out vec2 tex_coord ; 13 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 14 out vec3 normale ; 15 // p o s i t i o n de l a source lumineuse pour t r a n s m i s s i o n au fragment shader 16 out vec3 l i g h t D i r ; 17 // p o s i t i o n du sommet dans l e repère de l a caméra 18 out vec4 v e r t e x P o s i t i o n ; void main ( void ) 21 { 22 // On récupère l a coordonnée de t e x t u r e au sommet 23 tex_ coord = TexCoord ; 24 // On récupère l a normale au sommet 25 normale = ( modelviewmatrix* vec4 ( Normal. x, Normal. y, Normal. z, 0. 0 ) ). xyz ; 26 // p o s i t i o n de l a source lumineuse dans l e repère du monde 27 vec4 lightposworld = vec4 ( 7. 0, 7. 0, 7. 0, 1. 0 ) ; 28 // p o s i t i o n du sommet dans l e repère du monde 29 vec4 vertexpos = modelviewmatrix* vec4 ( P o s i t i o n. x, P o s i t i o n. y, P o s i t i o n. z, 1. 0 ) ; 30 v e r t e x P o s i t i o n = vertexpos ; 31 // d i r e c t i o n de l a source lumineuse dans l e repère de l a caméra. 32 l i g h t D i r = normalize ( ( viewmatrix * lightposworld vertexpos ). xyz ) ; // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 35 gl_position = p r o j e c t i o n M a t r i x * vertexpos ; 36 } Le fragment shader est le suivant : shadingvbo/progc/fragmentshader2.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 121

122 Rémy Malgouyres, Programmation 3D avec OpenGL 6 7 // coordonnée de t e x t u r e i n t e r p o l é e 8 i n vec2 tex_ coord ; 9 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 10 in vec3 normale ; 11 // p o s i t i o n de l a source lumineuse dans l e repère de l a caméra 12 in vec3 l i g h t D i r ; 13 // p o s i t i o n du sommet dans l e repère de l a caméra 14 in vec4 v e r t e x P o s i t i o n ; void main ( void ) 18 { 19 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 20 vec4 t e x t u r e C o l o r = texture2d ( texturemap, tex_coord ) ; vec3 normal = normalize ( normale ) ; 23 vec3 lightdirnorm = normalize ( l i g h t D i r ) ; 24 float diffuseterm = dot ( normal, lightdirnorm ) ; 25 i f ( diffuseterm <0) 26 diffuseterm =0.0 ; 27 vec3 i n c i d e n t = normalize ( v e r t e x P o s i t i o n. xyz ) ; 28 vec3 R = 2* dot ( normal, i n c i d e n t ) *normal i n c i d e n t ; 29 float dotspecular = dot (R, lightdirnorm ) ; 30 i f ( dotspecular <0.0) 31 dotspecular =0.0 ; 32 float s h i n i n e s s = ; 33 float specularterm = 0.5*pow( dotspecular, s h i n i n e s s ) ; // On a f f i c h e l a c o u l e u r i n t e r p o l é e 36 gl_fragcolor = vec4 ( diffuseterm * t e x t u r e C o l o r. x+specularterm, 37 diffuseterm * t e x t u r e C o l o r. y+specularterm, 38 diffuseterm * t e x t u r e C o l o r. z+specularterm, 1. 0 ) ; 39 } 9.3 Exemple d application : la bille, la goutte, la bulle Voici un exemple un peu plus compliqué : on a ici une carte d environnement (en latitudelongitude) et une bille réfléchissante dont les sommets sont déformés par le vertex shader. La carte d environnement et la bille de mercure ayant des propriétés matérielles très différentes, on doit utiliser deux programmes de shaders différents. La carte d environnement est juste une grande sphère (ici rayon 5), qui englobe la scène et la caméra et sur laquelle est plaquée une texture représentant le paysage avec le bon format. Pour la bille, elle est déformée au niveau du vertex shader pour donner un ellipsoïde un peu quelconque qui varie au cours du temps. Au niveau du fragment shader, on calcule pour chaque pixel un rayon réfléchi, puis l intersection de ce rayon avec la sphère d environnement. Un simple accès à la texture d environnement nous donne alors la couleur à afficher. Lorsqu on considère uniquement la réflexion, on obtient un matériaux semblable à l inox ou (puisque la bulle se déforme) au mercure. Lorsqu on considère aussi la réfraction avec la formule de Fresnel, on a une part de réfraction et une part de réflexion. Suivant l indice de réfraction (fixé dans le fragment shader de la bille), on obtient du verre (indice 1.6), de 122

123 Chapitre 9 : Éclairement avec shaders et VBO l eau (indice 1.33), une bulle d air sous l eau (indice 0.9), etc. Carte d environnement tirée de applications/progc/exbouleverre.c 1 #include <s t d l i b. h> 2 #include <SDL2/SDL. h> 3 #include <SDL2/ SDL_opengl. h> 4 #include <GLES3/ g l 3. h> 5 #include <s t d i o. h> 6 #include <math. h> 7 8 #define GLM_FORCE_RADIANS 9 10 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 11 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 12 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h 15 #include vbo_utils. h 16 #include mesh_utils. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 19 GLushort l a r g e u r _ f e n e t r e =700 ; 20 GLushort hauteur_fenetre =700 ; /* ************************************ */ 23 /* I d e n t i f i a n t s des VBOs */ GLint nverticessphere ; 26 GLint nfacessphere ; 27 GLuint vertexarrayobjsphere ; 28 GLuint elementarrayobjsphere ; GLint nverticessphereenviron ; 31 GLint nfacessphereenviron ; 32 GLuint vertexarrayobjsphereenviron ; 33 GLuint elementarrayobjsphereenviron ; /* a f f i c h a g e */ 36 void A f f i c h a g e ( glm : :mat4 projectionmatrix, 37 GLint nbframes, GLuint programid1, GLuint programid2, 38 GLfloat angle_elevation, 39 GLfloat angle_azimuth, GLfloat d i s t a n c e ) 40 { 41 glm : :mat4 modelviewmatrix ( 1. 0 f ) ; modelviewmatrix=glm : : t r a n s l a t e ( modelviewmatrix, 44 glm : :vec3 ( 0. 0, 0. 0, ( GLfloat ) d i s t a n c e ) ) ; 45 modelviewmatrix= glm : :r o t a t e ( modelviewmatrix, 46 angle_elevation, glm : :vec3 ( 1. 0, 0. 0, 0. 0 ) ) ; 47 modelviewmatrix=glm : :r o t a t e ( modelviewmatrix, 48 angle_azimuth, glm : :vec3 ( 0. 0, 1. 0, 0. 0 ) ) ; gluseprogram ( programid1 ) ; // s é l e c t i o n du programme /* On c a l c u l e l e temps e t on i n i t i a l i s e l a v a r i a b l e uniform */ 123

124 Rémy Malgouyres, Programmation 3D avec OpenGL 53 GLfloat temps = 0. 2 * ( GLfloat ) nbframes ; 54 /* On récupère l emplacement ( en mémoire v i d é o ) de l a v a r i a b l e */ 55 GLint temps_loc = glgetuniformlocation ( programid1, temps ) ; 56 /* On i n i t i a l i s e l a v a r i a b l e avant l a f f i c h a g e */ 57 gluniform1f ( temps_loc, temps ) ; // On f a i t tourner l o b j e t sur l u i même : 60 // glm : :mat4 modelviewmatrix = viewmatrix ; // envoi des matrices v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 63 GLint modelviewmatrix_loc = glgetuniformlocation ( programid1, modelviewmatrix ) ; 64 gluniformmatrix4fv ( modelviewmatrix_loc, 1, GL_FALSE, 65 glm : :value_ptr ( modelviewmatrix ) ) ; 66 GLint viewmatrix_loc = glgetuniformlocation ( programid1, viewmatrix ) ; 67 gluniformmatrix4fv ( viewmatrix_loc, 1, GL_FALSE, 68 glm : :value_ptr ( modelviewmatrix ) ) ; 69 GLint p r o j e c t i o n M a t r i x _ l o c = glgetuniformlocation ( programid1, p r o j e c t i o n M a t r i x ) ; 70 gluniformmatrix4fv ( projectionmatrix_loc, 1, GL_FALSE, 71 glm : :value_ptr ( p r o j e c t i o n M a t r i x ) ) ; GLint d i s t a n c e _ l o c = glgetuniformlocation ( programid1, d i s t a n c e ) ; 74 gluniform1f ( distance_loc, d i s t a n c e ) ; gluseprogram ( programid2 ) ; // s é l e c t i o n du programme GLint modelviewprojmatrix_loc = glgetuniformlocation ( programid2, modelviewprojmatrix ) ; gluniformmatrix4fv ( modelviewprojmatrix_loc, 1, GL_FALSE, 82 glm : :value_ptr ( p r o j e c t i o n M a t r i x * modelviewmatrix ) ) ; gluseprogram ( programid1 ) ; // s é l e c t i o n du programme g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 87 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; enablevbo ( programid1, elementarrayobjsphere, vertexarrayobjsphere, 90 3, nverticessphere ) ; gldrawelements (GL_TRIANGLES, 3* nfacessphere, GL_UNSIGNED_INT, NULL) ; gluseprogram ( programid2 ) ; // s é l e c t i o n du programme 97 enablevbo ( programid2, elementarrayobjsphereenviron, 98 vertexarrayobjsphereenviron, 3, nverticessphereenviron ) ; gldrawelements (GL_TRIANGLES, 3* nfacessphereenviron, GL_UNSIGNED_INT, NULL) ; 102 } GLuint loadbmptexture ( const char * f i l e n a m e ) 105 { 124

125 Chapitre 9 : Éclairement avec shaders et VBO 106 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 109 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 112 glgentextures ( 1, &tex_ id ) ; 113 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 116 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 117 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 120 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 121 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 124 return tex_id ; 125 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 131 */ 132 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 133 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 134 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 135 SDL_Init (SDL_INIT_VIDEO) ; 136 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 137 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 138 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 139 return window ; 140 } int main ( int argc, char** argv ) 143 { 144 GLfloat angle_twist =0 ; 145 GLfloat a n g l e _ e l e v a t i o n =30.0 ; 146 GLfloat angle_azimuth =30.0 ; 147 GLfloat d i s t a n c e =3.5 ; 148 GLfloat v i t e s s e =0.2 ; 149 GLushort mousex, mousey ; /* permet de mémoriser l a d e r n i è r e p o s i t i o n */ 150 /* de l a s o u r i s */ bool l e f t B u t t o n P r e s s e d = f a l s e ; 153 bool middlebuttonpressed = f a l s e ; /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 156 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 157 Boule t r a n s p a r e n t e qui se déforme ) ; 158 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 125

126 Rémy Malgouyres, Programmation 3D avec OpenGL 159 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n de GLEW, OpenGL e t GLSL d i s p o n i b l e */ 164 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 165 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 168 /* c r é a t i o n des shaders */ 169 GLuint vertexid1, fragmentid1 ; 170 GLuint programid1 ; 171 CreateShadersProgram(&programID1, &vertexid1, &fragmentid1, 172 vertexshader4. txt, 173 fragmentshader4_boule_verre. txt ) ; GLuint vertexid2, fragmentid2 ; 176 GLuint programid2 ; 177 CreateShadersProgram(&programID2, &vertexid2, &fragmentid2, 178 vertexshader3. txt, 179 fragmentshader3. txt ) ; 180 /* ************************************************* */ 181 /* D é f i n i t i o n de l a p e r s p e c t i v e */ 182 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, f, f ) ; /* ************************************************** */ 188 /* gldepthrange donne l i n t e r v a l l e des profondeurs p r i s e s en compte */ 189 gldepthrange ( 0. 1, ) ; 190 glenable (GL_DEPTH_TEST) ; /* ************************************ */ 194 /* Création des Vertex Buffer O b j e c t s */ 195 maillagesphere ( 1. 0, 100, 60, programid1, 196 &nverticessphere, &nfacessphere, 197 &vertexarrayobjsphere, &elementarrayobjsphere ) ; 198 maillagesphere ( , 100, 60, 199 programid2, 200 &nverticessphereenviron, &nfacessphereenviron, 201 &vertexarrayobjsphereenviron, 202 &elementarrayobjsphereenviron ) ; /* ************************************* */ 205 /* Chargement de l a t e x t u r e */ 206 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 207 i f (! texid ) 208 e x i t (EXIT_FAILURE) ; /* **************************************** */ 212 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 213 GLint texturemap_loc = glgetuniformlocation ( programid1, texturemap ) ; 214 gluniform1ui ( texturemap_loc, texid ) ; 126

127 Chapitre 9 : Éclairement avec shaders et VBO 215 GLint texturemap_loc2 = glgetuniformlocation ( programid2, texturemap ) ; 216 gluniform1ui ( texturemap_loc2, texid ) ; /* *****************************************************************\ 219 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 220 \***************************************************************** */ 221 bool terminer=f a l s e ; 222 SDL_Event evenements ; /* union contenant un évennement */ 223 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 226 while (! terminer ) 227 { 228 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 229 { 230 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 231 case SDL_MOUSEBUTTONDOWN : /* Enfoncement d un bouton s o u r i s */ 232 switch ( evenements. button. button ) { 233 case SDL_BUTTON_LEFT : /* Bouton gauche */ 234 l e f t B u t t o n P r e s s e d=true ; 235 mousex = evenements. button. x ; /* mémorisation coordonnées de l a s o u r i s */ 236 mousey = evenements. button. y ; /* mémorisation coordonnées de l a s o u r i s */ 237 break ; 238 case SDL_BUTTON_MIDDLE : /* Bouton gauche */ 239 middlebuttonpressed=true ; 240 mousex = evenements. button. x ; /* mémorisation coordonnées de l a s o u r i s */ 241 mousey = evenements. button. y ; /* mémorisation coordonnées de l a s o u r i s */ 242 break ; 243 } 244 break ; 245 case SDL_MOUSEBUTTONUP : /* Relachement d un bouton s o u r i s */ 246 switch ( evenements. button. button ) { 247 case SDL_BUTTON_LEFT : /* Bouton gauche */ 248 l e f t B u t t o n P r e s s e d=f a l s e ; 249 break ; 250 case SDL_BUTTON_MIDDLE : /* Bouton gauche */ 251 middlebuttonpressed=f a l s e ; 252 break ; 253 } 254 break ; 255 case SDL_MOUSEMOTION : /* Mouvement de l a s o u r i s */ 256 i f ( l e f t B u t t o n P r e s s e d ) { 257 a n g l e _ e l e v a t i o n += v i t e s s e *( evenements. motion. y mousey ) ; 258 angle_azimuth += v i t e s s e *( evenements. motion. x mousex ) ; 259 mousex = evenements. motion. x ; /* e n r e g i s t r e m e n t des n o u v e l l e s */ 260 mousey = evenements. motion. y ; /* coordonnées de l a s o u r i s */ 261 } 262 i f ( middlebuttonpressed ) { 263 d i s t a n c e += v i t e s s e *( evenements. motion. y mousey ) ; 264 mousex = evenements. motion. x ; /* e n r e g i s t r e m e n t des n o u v e l l e s */ 265 mousey = evenements. motion. y ; /* coordonnées de l a s o u r i s */ 266 } 127

128 Rémy Malgouyres, Programmation 3D avec OpenGL 267 break ; 268 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 269 terminer = true ; 270 break ; 271 } 272 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 275 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 278 { 279 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 280 A f f i c h a g e ( projectionmatrix, nbframes, 281 programid1, programid2, 282 angle_elevation, angle_azimuth, d i s t a n c e ) ; /* on r a f f r a i c h i t l a vue */ 283 nbframes++ ; /* On incrémente l e compteur de frames */ 284 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 285 } 286 } // L i b é r a t i o n des r e s s o u r c e s SDL 289 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 290 SDL_DestroyWindow ( window ) ; 291 SDL_Quit ( ) ; 292 return 0 ; 293 } Le vertex shader pour la bille est le suivant : applications/progc/vertexshader4.txt 1 #v e r s i o n uniform mat4 modelviewmatrix ; 4 uniform mat4 p r o j e c t i o n M a t r i x ; 5 uniform mat4 viewmatrix ; 6 uniform float temps ; 7 8 in vec3 P o s i t i o n ; 9 i n vec3 Normal ; 10 i n vec2 TexCoord ; // coordonnée de t e x t u r e pour i n t e p o l a t i o n 13 out vec2 tex_coord ; 14 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 15 out vec3 normale ; 16 // p o s i t i o n de l a source lumineuse pour t r a n s m i s s i o n au fragment shader 17 out vec3 l i g h t D i r ; 18 // p o s i t i o n du sommet pour t r a n s m i s s i o n au fragment shader 19 out vec4 f i n a l V e r t e x P o s i t i o n ; // On transmet l a déformation de l a sphère au fragment shader 22 out float scalex ; 23 out float scaley ; 24 out float s c a l e Z ;

129 Chapitre 9 : Éclairement avec shaders et VBO 26 void main ( void ) 27 { 28 // On récupère l a coordonnée de t e x t u r e au sommet 29 tex_ coord = TexCoord ; // Déformation du sommet dans l e r e p è r e du monde 32 scalex = (( *(1.0+ s i n ( temps ) ) ) *(0.5+( TexCoord. x*texcoord. x ) *(1.0 TexCoord. x ) *(1.0 TexCoord. x ) ) +0.5*(1.0+ s i n ( temps ) ) ) ; 33 scaley = (( *(1.0+ s i n ( 0. 3 * temps ) ) ) *(0.5+( TexCoord. x*texcoord. x ) *(1.0 TexCoord. x ) *(1.0 TexCoord. x ) ) +0.5*(1.0+ s i n ( 0. 3 * temps ) ) ) ; 34 s c a l e Z = (( *(1.0+ s i n ( 0. 6 * temps ) ) ) *(0.5+( TexCoord. y*texcoord. y ) *(1.0 TexCoord. y ) *(1.0 TexCoord. y ) ) +0.5*(1.0+ s i n ( 0. 6 * temps ) ) ) ; vec4 vertexdeforme = vec4 ( P o s i t i o n. x* scalex, 37 P o s i t i o n. y* scaley, 38 P o s i t i o n. z * scalez, ) ; 40 // Sommet dans l e repère de l a caméra 41 vec4 vertexpos = modelviewmatrix* vec4 ( vertexdeforme. x, 42 vertexdeforme. y, 43 vertexdeforme. z, 1. 0 ) ; 44 // On récupère l a normale au sommet dans l e repère de l a caméra 45 vec4 normalvertex = i n v e r s e ( t r a n s p o s e ( modelviewmatrix ) ) * vec4 ( Normal. x/ scalex, Normal. y/ scaley, Normal. z / scalez, 0. 0 ) ; 46 normale = vec3 ( normalvertex. x, 47 normalvertex. y, 48 normalvertex. z ) ; // p o s i t i o n du sommet après t r a n s f o r m a t i o n v e r s l e fragment shader 51 f i n a l V e r t e x P o s i t i o n=vertexpos ; 52 // Somme après p r o j e c t i o n pour r a s t e r i s a t i o n par OpenGL 53 gl_position = p r o j e c t i o n M a t r i x * f i n a l V e r t e x P o s i t i o n ; 54 } Le fragment shader pour la bille est le suivant : applications/progc/fragmentshader4_boule_verre.txt 1 #v e r s i o n uniform mat4 modelviewmatrix ; // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 7 uniform sampler2d texturemap ; 8 // d i s t a n c e du c e n t r e de l a sphère à l a p o s i t i o n de l a caméra 9 uniform float d i s t a n c e ; // coordonnée de t e x t u r e i n t e r p o l é e 12 i n vec2 tex_ coord ; 13 // v e c t e u r normal pour i n t e p o l a t i o n ( l i s s a g e de phong ) 14 in vec3 normale ; 15 in vec3 l i g h t D i r ; 16 in vec4 f i n a l V e r t e x P o s i t i o n ; in float scalex ; 19 in float scaley ; 129

130 Rémy Malgouyres, Programmation 3D avec OpenGL 20 in float s c a l e Z ; void main ( void ) 23 { 24 // v a l e u r de l i n d i c e de r é f r a c t i o n 25 float i n d i c e R e f r a c t i o n = 1. 6 ; // ///////////////////////////////////// 28 // Calcul du premier rayon r é f l é c h i 29 vec3 normal = normalize ( normale ) ; 30 vec3 i n c i d e n t V e c t o r=normalize( f i n a l V e r t e x P o s i t i o n. xyz ) ; 31 float c o s T h e t a i n c i d e n t=dot ( normal, i n c i d e n t V e c t o r ) ; 32 vec3 R = 2* c o s T h e t a i n c i d e n t *normal i n c i d e n t V e c t o r ; // /////////////////////////////////////// 35 // c a l c u l de l a l a t i t u d e e t l o n g i t u d e dans l environment map // On r e p a s s e R dans l e repère du monde 38 mat4 invmv = i n v e r s e ( modelviewmatrix ) ; 39 vec3 d i r H i t=normalize ( ( invmv* vec4 (R, 0. 0 ) ). xyz ) ; 40 // c a l c u l de l a l a t i t u d e e t l o n g i t u d e 41 d i r H i t = vec3( d i r H i t. z, d i r H i t. x, d i r H i t. y ) ; 42 vec2 coordsphe = vec2 ( 43 acos ( d i r H i t. z ) /3.1416, 44 acos ( d i r H i t. y/ s q r t ( d i r H i t. x* d i r H i t. x+ d i r H i t. y* d i r H i t. y ) ) / ) ; 46 i f ( d i r H i t. x < 0) 47 coordsphe. t = (2.0 coordsphe. t ) ; 48 coordsphe. t = coordsphe. t / 2. 0 ; 49 // On récupère l a c o u l e u r du t e x e l de l a c a r t e d environnement 50 vec4 t e x t u r e C o l o r = texture2d ( texturemap, vec2 ( coordsphe. t, coordsphe. s ) ) ; // //////////////////////////////////////// 53 // Calcul du premier rayon transmis 54 float gamma = 1.0/ i n d i c e R e f r a c t i o n ; // en prenant l i n d i c e du v e r r e float exprsousradical = 1.0+gamma*gamma* 56 ( c o s T h e t a i n c i d e n t * costhetaincident 1.0) ; 57 float rho =1.0 ; 58 float rho2 =1.0 ; 59 vec4 t e x t u r e C o l o r 2=vec4 ( 0. 0, 0. 0, 0. 0, 1. 0 ) ; vec3 T; 62 float costhetaincident2 =0.0 ; 63 vec3 normal2 ; 64 vec4 t e x t u r e C o l o r 3=vec4 ( 0. 0, 0. 0, 0. 0, 1. 0 ) ; 65 i f ( exprsousradical >=0){ // t e s t r é f l e x i o n t o t a l e 66 // Calcul du rayon transmis 67 float tau = 1.0/ i n d i c e R e f r a c t i o n * costhetaincident s q r t ( exprsousradical ) ; 68 // v e c t e u r d i r e c t e u r du rayon transmis 69 T = gamma* i n c i d e n t V e c t o r+tau * normal ; // On passe dans l e repère du monde pour annuler 72 // l e s a f f i n i t é s o r t h o g o n a l e s qui déforment l a sphère 73 // ( géométrie p l u s simple ) 74 vec3 worldt = normalize ( ( invmv* vec4 (T, 0. 0 ) ). xyz ) ; 75 worldt = vec3 ( worldt. x/ scalex, worldt. y/ scaley, worldt. z / s c a l e Z ) ; 130

131 Chapitre 9 : Éclairement avec shaders et VBO 76 vec4 vertexposworld = invmv* f i n a l V e r t e x P o s i t i o n ; 77 vertexposworld = vec4 ( vertexposworld. x/ scalex, 78 vertexposworld. y/ scaley, 79 vertexposworld. z / scalez, 1. 0 ) ; 80 // i n t e r s e c t i o n rayon sphere ( méthode a l g é b r i q u e ) 81 float At = 1. 0 ; 82 float Bt = 2*( worldt. x *( vertexposworld. x ) 83 + worldt. y *( vertexposworld. y ) 84 + worldt. z *( vertexposworld. z ) ) ; 85 f l o a t Ct = vertexposworld. x* vertexposworld. x 86 + vertexposworld. y* vertexposworld. y 87 + ( vertexposworld. z ) *( vertexposworld. z ) ; 89 float t t = ( Bt+s q r t ( Bt*Bt 4*At*Ct ) ) /(2*At ) ; 90 // p o i n t d i n t e r s e c t i o n 91 vec4 I t = vec4 ( vertexposworld. x+t t *worldt. x, 92 vertexposworld. y+t t *worldt. y, 93 vertexposworld. z+t t *worldt. z, 1. 0 ) ; // c a l c u l du c o e f f i c i e n t formule de Fresnel 96 float costhetat = dot (T, normal ) ; 97 float sinthetat = s q r t (1.0 costhetat * costhetat ) ; 98 float s i n T h e t a i n c i d e n t = s q r t (1.0 c o s T h e t a i n c i d e n t * c o s T h e t a i n c i d e n t ) ; 99 float sinamoinsb = s i n T h e t a i n c i d e n t * costhetat c o s T h e t a i n c i d e n t * sinthetat ; 100 float sinaplusb = s i n T h e t a i n c i d e n t * costhetat+c o s T h e t a i n c i d e n t * sinthetat ; 101 float cosamoinsb = c o s T h e t a i n c i d e n t * costhetat+s i n T h e t a i n c i d e n t * sinthetat ; 102 float cosaplusb = c o s T h e t a i n c i d e n t * costhetat s i n T h e t a i n c i d e n t * sinthetat ; 103 // c o e f f i c i e n t formule de Fresnel 104 rho = 0. 5 * ( ( sinamoinsb*sinamoinsb ) /( sinaplusb * sinaplusb ) ( ( sinamoinsb*sinamoinsb ) /( cosamoinsb*cosamoinsb ) ) 106 / ( ( sinaplusb * sinaplusb ) /( cosaplusb * cosaplusb ) ) ) ; 107 i f ( rho > 1. 0 ) 108 rho = 1. 0 ; // /////////////////////////////////////// 111 // Calcul du second rayon transmis ( s i m i l a i r e au précédent ) 112 costhetaincident2 =0.0 ; 113 float gamma2 = i n d i c e R e f r a c t i o n ; // en prenant l i n d i c e du v e r r e // on r e p a s s e l e p o i n t d i n t e r s e c t i o n précédent 116 // dans l e repère de l a caméra pour y f a i r e l e s c a l c u l s 117 normal2 = ( modelviewmatrix* vec4 ( I t. x/ scalex, 118 I t. y/ scaley, 119 I t. z / scalez, 1. 0 ) ). xyz ; // normale au p o i n t d i n t e r s e c t i o n 122 normal2. z=normal2. z d i s t a n c e ; 123 normal2 = normalize ( normal2 ) ; 124 costhetaincident2=dot ( normal2, T) ; float exprsousradical2 = 1.0+ i n d i c e R e f r a c t i o n * i n d i c e R e f r a c t i o n * 128 ( costhetaincident2 * costhetaincident2 1.0) ; i f ( exprsousradical2 >= 0. 0 ) { // t e s t r é f l e x i o n t o t a l e 131 float tau2 = i n d i c e R e f r a c t i o n * costhetaincident2 s q r t ( exprsousradical2 ) ; 131

132 Rémy Malgouyres, Programmation 3D avec OpenGL 132 // v e c t e u r d i r e c t e u r du rayon transmis 133 vec3 T2 = gamma2*( T)+tau2 * normal2 ; T2 = normalize (T2) ; // c a l c u l du c o e f f i c i e n t formule de Fresnel 138 float costhetat2 = dot (T2, normal2 ) ; 139 float sinthetat2 = s q r t (1.0 costhetat2 * costhetat2 ) ; 140 float s i n T h e t a i n c i d e n t 2 = s q r t (1.0 costhetaincident2 * c o s T h e t a i n c i d e n t 2 ) ; 141 float sinamoinsb2 = s i n T h e t a i n c i d e n t 2 * costhetat2 142 costhetaincident2 * sinthetat2 ; 143 float sinaplusb2 = s i n T h e t a i n c i d e n t 2 * costhetat costhetaincident2 * sinthetat2 ; 145 float cosamoinsb2 = costhetaincident2 * costhetat s i n T h e t a i n c i d e n t 2 * sinthetat2 ; 147 float cosaplusb2 = costhetaincident2 * costhetat2 148 s i n T h e t a i n c i d e n t 2 * sinthetat2 ; 149 // c o e f f i c i e n t formule de Fresnel 150 rho2 = 0. 5 * ( ( sinamoinsb2*sinamoinsb2 ) /( sinaplusb2 * sinaplusb2 ) ( ( sinamoinsb2*sinamoinsb2 ) /( cosamoinsb2*cosamoinsb2 ) ) 152 / ( ( sinaplusb2 * sinaplusb2 ) /( cosaplusb2 * cosaplusb2 ) ) ) ; 153 i f ( rho2 > 1. 0 ) 154 rho2 = 1. 0 ; // //////////////////////////////////////////// 157 // recherche du p o i n t de l a c a r t e d environnement a t t e i n 158 // On r e p a s s e dans l e repère du monde 159 vec3 d i r H i t 2=normalize ( ( invmv* vec4 (T2, 0. 0 ) ). xyz ) ; 160 d i r H i t 2 = vec3 ( d i r H i t 2. z, d i r H i t 2. x, d i r H i t 2. y ) ; 161 // c a l c u l l a t i t u d e l o n g i t u d e 162 vec2 coordsphe2 = vec2 ( 163 acos ( d i r H i t 2. z ) /3.1416, 164 acos ( d i r H i t 2. y/ s q r t ( d i r H i t 2. x* d i r H i t 2. x+d i r H i t 2. y* d i r H i t 2. y ) ) / ) ; 166 i f ( d i r H i t 2. x < 0) 167 coordsphe2. t = (2.0 coordsphe2. t ) ; 168 coordsphe2. t = coordsphe2. t / 2. 0 ; 169 // On récupère l a c o u l e u r du t e x e l de l a c a r t e d environnement 170 t e x t u r e C o l o r 2 = texture2d ( texturemap, vec2 (1.0 coordsphe2. t, coordsphe2. s ) ) ; 171 } else { // r é f l e c t i o n t o t a l e 172 rho2 =1.0 ; 173 } // rayon r é f l é c h i à l i n t é r i e u r de l a b o u l e 176 vec3 R2 = normalize ( 2. 0 * costhetaincident2 * normal2+t) ; // On n é g l i g e l a r é f r a c t i o n à ce s t a d e 179 // e t on va directement c a l c u l e r l e poinr de l a c a r t e d environnement 180 vec3 d i r H i t 3=normalize ( ( invmv* vec4 (R2, 0. 0 ) ). xyz ) ; 181 d i r H i t 3 = vec3( d i r H i t 3. z * scalez, d i r H i t 3. x* scalex, d i r H i t 3. y* scaley ) ; vec2 coordsphe3 = vec2 ( 184 acos ( d i r H i t 3. z ) /3.1416, 185 acos ( d i r H i t 3. y/ s q r t ( d i r H i t 3. x* d i r H i t 3. x+ d i r H i t 3. y* d i r H i t 3. y ) ) / ) ; 132

133 Chapitre 9 : Éclairement avec shaders et VBO 187 i f ( d i r H i t 3. x < 0) 188 coordsphe3. t = (2.0 coordsphe3. t ) ; 189 coordsphe3. t = coordsphe3. t / 2. 0 ; 190 // On récupère l a c o u l e u r du t e x e l de l a c a r t e d environnement 191 t e x t u r e C o l o r 3 = texture2d ( texturemap, vec2 ( coordsphe3. t, coordsphe3. s ) ) ; 192 } else { 193 rho =1.0 ; 194 } // On a f f i c h e f i n a l e m e n t l a combinaison des c o u l e u r s 197 // s u i v a n t l a formule de Fresnel. 198 gl_fragcolor = vec4 ( t e x t u r e C o l o r. x* rho+ 199 t e x t u r e C o l o r 3. x* rho2 *(1.0 rho )+ 200 t e x t u r e C o l o r 2. x*(1.0 rho2 ) *(1.0 rho ), 201 t e x t u r e C o l o r 3. y* rho2 *(1.0 rho )+ 202 t e x t u r e C o l o r. y* rho+ 203 t e x t u r e C o l o r 2. y*(1.0 rho2 ) *(1.0 rho ), t e x t u r e C o l o r 3. z * rho2 *(1.0 rho )+ 204 t e x t u r e C o l o r. z * rho+ 205 t e x t u r e C o l o r 2. z *(1.0 rho2 ) *(1.0 rho ), 1. 0 ) ; 206 } Le vertex shader pour la carte d environnement est le suivant : applications/progc/vertexshader3.txt 1 #v e r s i o n uniform mat4 modelviewprojmatrix ; 4 5 // d é c l a r a t i o n des a t t r i b u t s. 6 // Le nom des a t t r i b u t s e s t d é c l a r é dans l e g l B i n d A t t r i b L o c a t i o n 7 in vec3 P o s i t i o n ; 8 in vec3 normal ; 9 i n vec2 TexCoord ; // coordonnée de t e x t u r e pour i n t e p o l a t i o n 12 out vec2 tex_coord ; void main ( void ) 15 { 16 // On récupère l a coordonnée de t e x t u r e au sommet 17 tex_ coord = TexCoord ; 18 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 19 gl_position = modelviewprojmatrix * vec4 ( P o s i t i o n. x, P o s i t i o n. y, P o s i t i o n. z, 1. 0 ) ; 20 } Le fragment shader pour la carte d environnement est le suivant : applications/progc/fragmentshader3.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 6 // coordonnée de t e x t u r e i n t e r p o l é e 133

134 Rémy Malgouyres, Programmation 3D avec OpenGL (a) Bille de verre (b) Goutte d eau (c) Bille de mercure (d) Bulle d air sous l eau Figure 9.2 : Captures d écran de la bille pour différentes valeurs d indice de réfraction i n vec2 tex_coord ; void main ( void ) { // On r é c u p è r e l a c o u l e u r du t e x e l aux coordonnée tex_coord vec4 t e x t u r e C o l o r = texture2d ( texturemap, vec2 (1.0 tex_coord. s, tex_coord. t )); // On a f f i c h e l a c o u l e u r i n t e r p o l é e gl_fragcolor = vec4 ( t e x t u r e C o l o r. x, t e x t u r e C o l o r. y, t e x t u r e C o l o r. z, 1. 0 ) ; } 134

135 Chapitre 10 Frame Buffer Objects 10.1 Rendu dans une texture Les frame buffer objects (FBO) permettent d effectuer des rendus OpenGL dans des textures au lieu d effectuer le rendu à l écran. On peut alors utiliser cette texture pour un autre rendu, etc. Quelques exemples d applications des FBO sont : Effectivement plaquer la texture en sortie du FBO sur un objet, par exemple un tableau, un mirroir ou un écran de télévision dans la scène ; L ajout d ombres par la technique des shadow maps dans laquelle on effectue un rendu du point de vue de la source lumineuse et on utilise l information de profondeur pour déterminer si les objets sont à l ombre par rapport à cette source ; Le précalcul et la séparation de différentes composantes de l éclairage d une scène. Le post processing : traitement d image 2D effectué en sortie du rendu. Le General Purpose Graphical Processing Unit (GPGPU) dans lequel on n est pas vraiment intéressé par l image mais on doit enchaîner différents traitements parallèles sur des données codées dans des textures. fbo/progc/framebuffersutils.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 #include <SDL2/SDL. h> 4 #include <SDL2/ SDL_opengl. h> 5 #include <GLES3/ g l 3. h> 6 7 #include f r a m e B u f f e r s U t i l s. h 8 9 /** Crée un Framebuffer pour e f f e c t u e r un rendu dans une t e x t u r e pframebuffername passage par a d r e s s e de l i d e n t i f i a n t du Framebuffer idtexture i d e n t i f i a n t de l a t e x t u r e dans l a q u e l l e on d o i t e f f e c t u e r l e rendu piddepthtexture passage par a d r e s s e de l i d e n t i f i a n t de l a t e x t u r e de profondeur. 135

136 Rémy Malgouyres, Programmation 3D avec OpenGL 14 Peut s e r v i r par exemple pour l e s shadow maps width l a r g e u r ( en p i x e l s ) du frame b u f f e r h e i g h t hauteur ( en p i x e l s ) du frame b u f f e r 1 en cas d erreur, 0 sinon 18 */ 19 int createframebuffer ( GLuint * pframebufferid, GLuint idtexture, GLuint* piddepthtexture, GLuint width, GLuint h e i g h t ) { // i d e n t i f i a n t du Frame Buffer 22 GLuint framebufferid ; 23 // g é n é r a t i o n d un i d e n t i f i a n t 24 glgenframebuffers ( 1, &framebufferid ) ; 25 // S é l e c t i o n du frame b u f f e r pour t r a v a i l l e r dessus 26 glbindframebuffer (GL_FRAMEBUFFER, framebufferid ) ; 27 // passage par a d r e s s e 28 * pframebufferid=framebufferid ; // I d e n d i f i a n t de t e x t u r e pour c o n t e n i r l e s c o u l e u r s en s o r t i e du rendu 31 GLuint colortexture=idtexture ; // I d e n d i f i a n t de t e x t u r e pour c o n t e n i r l e s profondeurs en s o r t i e du rendu 34 GLuint depthtexture ; 35 glgentextures ( 1, &depthtexture ) ; 36 // passage par a d r e s s e 37 * piddepthtexture = depthtexture ; 38 // On s é l e c t i o n n e l a t e x t u r e de profondeur pour t r a v a i l l e r dessus 39 glbindtexture (GL_TEXTURE_2D, depthtexture ) ; // A l l o c a t i o n de mémoire pour l a t e x t u r e ( d e r n i e r paramètre = 0) 42 // format DEPTH_COMPONENT 24 b i t s 43 glteximage2d (GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24, width, h e i g h t, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0) ; // On a t t a c h e l a t e x t u r e de profondeur au frame b u f f e r 46 glframebuffertex ture2d (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthtexture, 0) ; // On s é l e c t i o n n e l a t e x t u r e de c o u l e u r pour t r a v a i l l e r dessus 49 glbindtexture (GL_TEXTURE_2D, colortexture ) ; // A l l o c a t i o n de mémoire pour l a t e x t u r e ( d e r n i e r paramètre = 0) 52 glteximage2d (GL_TEXTURE_2D, 0,GL_RGB, width, h e i g h t, 0,GL_RGB, GL_UNSIGNED_BYTE, 0) ; // Manière d approximer a r r o ndir l e s v a l e u r s coordonnées f l o t t a n t e s 55 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ; 56 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) ; // On a t t a c h e l a t e x t u r e de c o u l e u r au frame b u f f e r 59 glframebuffertex ture2d (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colortexture, 0) ; // L i s t e des b u f f e r s u t i l i s é s par ce frame b u f f e r 62 GLenum drawbuffers [ 2 ] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT} ; 63 gldrawbuffers ( 2, drawbuffers ) ; 64 // On t e s t e que t o u t a é t é créé correctement 136

137 Chapitre 10 : Frame Buffer Objects (a) Capture 1 (b) Capture 2 Figure 10.1 : Captures d écran d une surface de Bézier sur laquelle est plaquée une texture elle même issue d un premier rendu i f ( g l C h e c k F r a m e b u f f e r S t a t u s (GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE) { f p r i n t f ( s t d e r r, problème de c r é a t i o n du f r a m e b u f f e r \n ) ; return 1 ; } return 0 ; } Dans l exemple suivant, nous faisons le même rendu que dans la partie 9.3, mais au lieu d afficher le résultat à l écran, nous effectuons le rendu dans une texture que nous plaquons sur une surface de Bézier en mouvement (voir la figure 10.1). fbo/progc/mesh_utils.c #include < s t d l i b. h> #include <s t d i o. h> #include <math. h> #include <GLES3/ g l 3. h> #include s h a d e r s U t i l s. h #include v b o _ u t i l s. h #include m e s h _ u t i l s. h /* Création des b u f f e r s contenant l e s informations sur l e maillage ( f a c e s, sommets, e t l e u r s a t t r i v u t s t e l s que l e s c o o r d o n n é e s de t e x t u r e v e r t e x A r r a y O b j e c t p a s s a g e par a d r e s s e de l i d e n t i f i a n t du b u f f e r d e s e l e m e n t A r r a y O b j e c t p a s s a g e par a d r e s s e de l i d e n t i f i a n t du b u f f e r d e s i n d i c e s des f a c e s */ void m a i l l a g e P l a n ( G L f l o a t width, G L f l o a t h e i g h t, 137

138 Rémy Malgouyres, Programmation 3D avec OpenGL 19 int largeur_mesh, int hauteur_mesh, 20 GLuint program, GLint * nvertices, GLint * nfaces, 21 GLuint * vertexarrayobj, GLuint * elementarrayobj ) { 22 GLfloat step_larg = width /( GLfloat ) largeur_mesh ; 23 GLfloat step_haut = height /( GLfloat ) hauteur_mesh ; GLfloat * vertexarray ; 26 GLfloat * texcoordarray ; 27 GLfloat * normalarray ; 28 GLuint * i n d i c e s ; // ////////////////////////////////////////////////////// 31 // Création des sommets e t coordonnées de t e x t u r e en RAM 32 // ////////////////////////////////////////////////////// * n V e r t i c e s = 6* largeur_mesh *hauteur_mesh ; 35 * nfaces = 2* largeur_ mesh * hauteur_mesh ; 36 vertexarray = new GLfloat [18* largeur_mesh *hauteur_mesh ] ; 37 // normalarray n e s t pas u t i l i s é mais d o i t ê t r e a l l o u é 38 // pour u t i l i s e r notre f o n c t i o n CreateFloatVBOs 39 normalarray = new GLfloat [18* largeur_mesh *hauteur_mesh ] ; 40 texcoordarray = new GLfloat [12* largeur_mesh *hauteur_mesh ] ; 41 int counttexcoord=0 ; 42 int countvertexcoord =0 ; 43 int i, j ; 44 for ( i =0 ; i < largeur_ mesh ; i ++) 45 for ( j =0 ; j < 6* hauteur_mesh ; j ++){ 46 normalarray [ countvertexcoord++] = 0. 0 ; 47 normalarray [ countvertexcoord++] = 0. 0 ; 48 normalarray [ countvertexcoord++] = 1. 0 ; 49 } 50 countvertexcoord =0 ; 51 for ( i =0 ; i < largeur_ mesh ; i ++) 52 for ( j=0 ; j< hauteur_mesh ; j++){ 53 texcoordarray [ counttexcoord++]=i /( GLfloat ) largeur_mesh ; 54 texcoordarray [ counttexcoord++]=j /( GLfloat ) hauteur_mesh ; 55 vertexarray [ countvertexcoord++] = i * step_larg ; 56 vertexarray [ countvertexcoord++] = j * step_haut ; 57 vertexarray [ countvertexcoord++] = 0. 0 ; 58 texcoordarray [ counttexcoord++]=( i +1) /( GLfloat ) largeur_mesh ; 59 texcoordarray [ counttexcoord++]=j /( GLfloat ) hauteur_mesh ; 60 vertexarray [ countvertexcoord++] = ( i +1)* step_larg ; 61 vertexarray [ countvertexcoord++] = j * step_haut ; 62 vertexarray [ countvertexcoord++] = 0. 0 ; 63 texcoordarray [ counttexcoord++]=i /( GLfloat ) largeur_mesh ; 64 texcoordarray [ counttexcoord++]=( j +1) /( GLfloat ) hauteur_mesh ; 65 vertexarray [ countvertexcoord++] = i * step_larg ; 66 vertexarray [ countvertexcoord++] = ( j +1)* step_haut ; 67 vertexarray [ countvertexcoord++] = 0. 0 ; 68 texcoordarray [ counttexcoord++]= i /( GLfloat ) largeur_mesh ; 69 texcoordarray [ counttexcoord++]=( j +1) /( GLfloat ) hauteur_mesh ; 70 vertexarray [ countvertexcoord++] = i * step_larg ; 71 vertexarray [ countvertexcoord++] = ( j +1)* step_haut ; 72 vertexarray [ countvertexcoord++] = 0. 0 ; 73 texcoordarray [ counttexcoord++]=( i +1) /( GLfloat ) largeur_mesh ; 74 texcoordarray [ counttexcoord++]=( j +1) /( GLfloat ) hauteur_mesh ; 138

139 Chapitre 10 : Frame Buffer Objects 75 vertexarray [ countvertexcoord++] = ( i +1)* step_larg ; 76 vertexarray [ countvertexcoord++] = ( j +1)* step_haut ; 77 vertexarray [ countvertexcoord++] = 0. 0 ; 78 texcoordarray [ counttexcoord++]=( i +1) /( GLfloat ) largeur_mesh ; 79 texcoordarray [ counttexcoord++]=( j ) /( GLfloat ) hauteur_mesh ; 80 vertexarray [ countvertexcoord++] = ( i +1)* step_larg ; 81 vertexarray [ countvertexcoord++] = ( j ) * step_haut ; 82 vertexarray [ countvertexcoord++] = 0. 0 ; 83 } 84 // Création des i n d i c e s de sommets d é f i n i s s a n t l e s f a c e s 85 // //////////////////////////////////////////////// // Création des i n d i c e s en RAM 88 i n d i c e s = new GLuint [ 6 * largeur_mesh *hauteur_mesh ] ; for ( i =0 ; i <6* largeur_ mesh * hauteur_mesh ; i ++) 91 i n d i c e s [ i ]=( GLuint ) i ; // /////////////////////////////////////////////////// 94 // On envoie l e t o u t v e r s des b u f f e r s en mémoire v i d é o 95 // //////////////////////////////////////////////////// 96 CreateFloatVBOs ( program, vertexarrayobj, elementarrayobj, 97 6* largeur_ mesh * hauteur_mesh, 3, 6* largeur_ mesh * hauteur_mesh, 98 vertexarray, normalarray, texcoordarray, i n d i c e s, 99 GL_STATIC_DRAW 100 ) ; 101 // L i b é r a t i o n de l a mémoire RAM qui ne s e r t p l u s à r i e n 102 d e l e t e i n d i c e s ; 103 d e l e t e vertexarray ; 104 d e l e t e normalarray ; 105 d e l e t e texcoordarray ; 106 } // //////////////////////////////////////////////// /** Construction d un m a i l l a g e t r i a n g u l é pour modéliser e t 114 a f f i c h e r une sphère ( pour remplacer l a f o n c t i o n GLU). r rayon de l a sphère nbparal nombre de p a r a l l è l e s pour découper l a sphère nbmerid nombre de méridiens pour découper l a sphère pnvertices passage par a d r e s s e du nombre de sommets pnfaces passage par a d r e s s e du nombre de f a c e s p V e r t i c e s passage par a d r e s s e du t a b l e a u des sommets ptexcoord passage par a d r e s s e du t a b l e a u des coordonnées de t e x t u r e pnormals passage par a d r e s s e du t a b l e a u des normales pfaces passage par a d r e s s e du t a b l e a u des f a c e s 124 */ 125 void maillagesphere ( GLfloat r, int nbparal, int nbmerid, 126 GLuint program, GLint * nvertices, GLint * nfaces, 127 GLuint * vertexarrayobj, GLuint * elementarrayobj ) { 128 int i, j, compteur ; 129 GLfloat teta, phi, s i n t e t a, sinphi, c o s t e t a, c o sphi ;

140 Rémy Malgouyres, Programmation 3D avec OpenGL 131 // c a l c u l du nombre de sommets du m a i l l a g e 132 // e t a l l o c a t i o n des sommets : 133 GLint nbsomm = ( nbmerid+1) * nbparal + 2 ; 134 * n V e r t i c e s = nbsomm ; 135 GLfloat *tabsomm = new GLfloat [ 3 *nbsomm ] ; // a l l o c a t i o n des normales : 138 GLfloat * tabnormals = new GLfloat [ 3 *nbsomm ] ; // a l l o c a t i o n des coordonnées de t e x t u r e : 141 GLfloat *tabtexcoord = new GLfloat [ 2 *nbsomm ] ; compteur = 0 ; // compteur de sommets GLfloat pi = M_PI; 147 // i n i t i a l i s a t i o n de l a p o s i t i o n des sommets, e t des normales 148 for ( i = 0 ; i <= nbmerid ; i ++){ 149 for ( j = 1 ; j <= nbparal ; j++){ 150 // c a l c u l des a n g l e s des coordonnees s p h e r i q u e s du sommets ( i, j ) 151 t e t a = 2*( GLfloat ) pi * ( ( GLfloat ) i / ( GLfloat ) nbmerid ) ; 152 c o s t e t a = ( GLfloat ) cos ( t e t a ) ; 153 s i n t e t a = ( GLfloat ) s i n ( t e t a ) ; 154 phi = ( GLfloat ) pi * ( ( GLfloat ) j / ( GLfloat ) ( nbparal +1) ) ; 155 cosphi = ( GLfloat ) cos ( phi ) ; 156 s i n p h i = ( GLfloat ) s i n ( phi ) ; // p o s i s t i o n du sommet ( i, j ) : 159 tabsomm [ 3 * compteur ] = r *( c o s t e t a * s i n p h i ) ; 160 tabsomm [ 3 * compteur +1] = r * cosphi ; 161 tabsomm [ 3 * compteur +2] = r *( s i n t e t a * s i n p h i ) ; 162 // normale en ce sommet 163 tabnormals [ 3 * compteur ] = c o s t e t a * s i n p h i ; 164 tabnormals [ 3 * compteur +1] = c osphi ; 165 tabnormals [ 3 * compteur +2] = s i n t e t a * s i n p h i ; tabtexcoord [ 2 * compteur ] = t e t a /(2* pi ) ; 168 tabtexcoord [ 2 * compteur +1] = phi / pi ; 169 compteur++ ; // sommet s u i v a n t 170 } 171 } // sommet correspondant au p o l e sud de l a sphere : 174 tabsomm [ 3 * compteur ] = 0. 0 ; 175 tabsomm [ 3 * compteur +1] = r ; 176 tabsomm [ 3 * compteur +2] = 0. 0 ; 177 // normale en ce sommet 178 tabnormals [ 3 * compteur ] = 0. 0 ; 179 tabnormals [ 3 * compteur +1] = 1 ; 180 tabnormals [ 3 * compteur +2] = 0. 0 ; tabtexcoord [ 2 * compteur ] = 0. 5 ; 183 tabtexcoord [ 2 * compteur +1] = 1. 0 ; 184 compteur++ ; // sommet correspondant au p o l e nord de l a sphere : 140

141 Chapitre 10 : Frame Buffer Objects 187 tabsomm [ 3 * compteur ] = 0. 0 ; 188 tabsomm [ 3 * compteur +1] = r ; 189 tabsomm [ 3 * compteur +2] = 0. 0 ; 190 // normale en ce sommet 191 tabnormals [ 3 * compteur ] = 0. 0 ; 192 tabnormals [ 3 * compteur +1] = 1 ; 193 tabnormals [ 3 * compteur +2] = 0. 0 ; tabtexcoord [ 2 * compteur ] = 0. 5 ; 196 tabtexcoord [ 2 * compteur +1] = 0. 0 ; 197 compteur++ ; GLint nbfaces = 2* nbparal * nbmerid ; // nombre de f a c e t t e s 200 * nfaces = nbfaces ; 201 GLuint * t a b f a c e s = new GLuint [ 3 * n b f a c e s ] ; // a l l o c a t i o n des f a c e t t e s compteur = 0 ; // compteur de f a c e s // i n i t i a l i s a t i o n des numeros de sommets de chaque f a c e t t e 206 for ( i = 0 ; i < nbmerid ; i ++){ 207 for ( int j = 1 ; j < nbparal ; j++){ 208 // numeros des sommets de l a f a c e t t e : 209 t a b f a c e s [ 3 * compteur ] = ( nbparal ) * i + j ; 210 t a b f a c e s [ 3 * compteur +1] = ( nbparal ) *( i +1) + j ; 211 t a b f a c e s [ 3 * compteur +2] = ( nbparal ) *( i +1) + j 1 ; compteur++ ; // numeros des sommets de l a f a c e t t e : 216 t a b f a c e s [ 3 * compteur ] = ( nbparal ) * i + j ; 217 t a b f a c e s [ 3 * compteur +1] = ( nbparal ) *( i +1) + j 1 ; 218 t a b f a c e s [ 3 * compteur +2] = ( nbparal ) * i + j 1 ; compteur++ ; 221 } 222 } // f a c e t t e s t r i a n g u l a i r e s touchant l e p o l e nord 225 for ( i = 0 ; i < nbmerid ; i ++){ 226 // numeros des sommets de l a f a c e t t e : 227 t a b f a c e s [ 3 * compteur ] = ( i +1)* nbparal ; 228 t a b f a c e s [ 3 * compteur +1] = ( nbmerid+1) * nbparal + 1 ; 229 t a b f a c e s [ 3 * compteur +2] = i * nbparal ; 230 compteur++ ; 231 } // f a c e t t e s t r i a n g u l a i r e s touchant l e p o l e sud 234 for ( i = 0 ; i < nbmerid ; i ++){ 235 // numeros des sommets de l a f a c e t t e : 236 t a b f a c e s [ 3 * compteur ] = ( nbmerid+1)* nbparal ; 237 t a b f a c e s [ 3 * compteur +1] = i * nbparal + nbparal 1 ; 238 t a b f a c e s [ 3 * compteur +2] = ( i +1)* nbparal + nbparal 1 ; 239 compteur++ ; 240 } // /////////////////////////////////////////////////// 141

142 Rémy Malgouyres, Programmation 3D avec OpenGL 243 // On envoie l e t o u t v e r s des b u f f e r s en mémoire v i d é o 244 // //////////////////////////////////////////////////// 245 CreateFloatVBOs ( program, vertexarrayobj, elementarrayobj, 246 nbsomm, 3, 3* nbfaces, 247 tabsomm, tabnormals, tabtexcoord, t a b f a c e s, 248 GL_STATIC_DRAW 249 ) ; 250 // L i b é r a t i o n de l a mémoire RAM qui ne s e r t p l u s à r i e n 251 d e l e t e t a b f a c e s ; 252 d e l e t e tabsomm ; 253 d e l e t e tabnormals ; 254 d e l e t e tabtexcoord ; 255 } Pour le premier rendu dans la texture, les vertex et fragment shaders sont les mêmes que dans la partie 9.3, puisque il s agit du même rendu. fbo/progc/exflag.c 1 #include <s t d l i b. h> 2 #include <s t d i o. h> 3 #include <math. h> 4 5 #include <SDL2/SDL. h> 6 #include <SDL2/ SDL_opengl. h> 7 #include <GLES3/ g l 3. h> 8 9 #define GLM_FORCE_RADIANS 10 #include <glm/glm. hpp> /* l i b r a i r i e maths pour matrices */ 11 #include <glm/ gtc / matrix_transform. hpp> /* p e r s p e c t i v e, l o o k a t... */ 12 #include <glm/ gtc / type_ptr. hpp> /* accès bas niveau aux données */ #include s h a d e r s U t i l s. h 15 #include vbo_utils. h 16 #include mesh_utils. h 17 #include f r a m e B u f f e r s U t i l s. h /* Dimension i n i t i a l e de l a f e n ê t r e graphique */ 20 GLushort l a r g e u r _ f e n e t r e =700 ; 21 GLushort hauteur_fenetre =700 ; /* ************************************ */ 24 /* I d e n t i f i a n t s des VBOs */ GLint nverticessphere ; 27 GLint nfacessphere ; 28 GLuint vertexarrayobjsphere ; 29 GLuint elementarrayobjsphere ; GLint nverticessphereenviron ; 32 GLint nfacessphereenviron ; 33 GLuint vertexarrayobjsphereenviron ; 34 GLuint elementarrayobjsphereenviron ; GLint nverticesplan ; 37 GLint nfacesplan ; 38 GLuint vertexarrayobjplan ; 142

143 Chapitre 10 : Frame Buffer Objects 39 GLuint elementarrayobjplan ; /* ***************************************** */ 42 /* Rendu dans l e frame b u f f e r */ 43 /* ***************************************** */ 44 void AffichageDansFrameBuffer ( GLuint framebufferid, glm : :mat4 projectionmatrix, 45 GLint nbframes, GLuint programid1, GLuint programid2, 46 GLfloat angle_elevation, 47 GLfloat angle_azimuth, GLfloat distance, 48 GLuint texid ) 49 { 50 /* ******************************************* */ 51 /* S é l e c t i o n du frame b u f f e r pour l e rendu */ 52 glbindframebuffer (GL_FRAMEBUFFER, framebufferid ) ; 53 // S é l e c t i o n de l a t e x t u r e de l a c a r t e d environnement pour p l a q u e r 54 glbindtexture (GL_TEXTURE_2D, texid ) ; gluseprogram ( programid1 ) ; // s é l e c t i o n du programme glm : :mat4 modelviewmatrix ( 1. 0 f ) ; modelviewmatrix=glm : : t r a n s l a t e ( modelviewmatrix, 61 glm : :vec3 ( 0. 0, 0. 0, ( GLfloat ) d i s t a n c e ) ) ; 62 modelviewmatrix= glm : :r o t a t e ( modelviewmatrix, 63 angle_elevation, glm : :vec3 ( 1. 0, 0. 0, 0. 0 ) ) ; 64 modelviewmatrix=glm : :r o t a t e ( modelviewmatrix, 65 angle_azimuth, glm : :vec3 ( 0. 0, 1. 0, 0. 0 ) ) ; /* On c a l c u l e l e temps e t on i n i t i a l i s e l a v a r i a b l e uniform */ 68 GLfloat temps = 0. 2 * ( GLfloat ) nbframes ; 69 /* On récupère l emplacement ( en mémoire v i d é o ) de l a v a r i a b l e */ 70 GLint temps_loc = glgetuniformlocation ( programid1, temps ) ; 71 /* On i n i t i a l i s e l a v a r i a b l e avant l a f f i c h a g e */ 72 gluniform1f ( temps_loc, temps ) ; // On f a i t tourner l o b j e t sur l u i même : 75 // glm : :mat4 modelviewmatrix = viewmatrix ; // envoi des matrices v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 78 GLint modelviewmatrix_loc = glgetuniformlocation ( programid1, modelviewmatrix ) ; 79 gluniformmatrix4fv ( modelviewmatrix_loc, 1, GL_FALSE, 80 glm : :value_ptr ( modelviewmatrix ) ) ; 81 GLint viewmatrix_loc = glgetuniformlocation ( programid1, viewmatrix ) ; 82 gluniformmatrix4fv ( viewmatrix_loc, 1, GL_FALSE, 83 glm : :value_ptr ( modelviewmatrix ) ) ; 84 GLint p r o j e c t i o n M a t r i x _ l o c = glgetuniformlocation ( programid1, p r o j e c t i o n M a t r i x ) ; 85 gluniformmatrix4fv ( projectionmatrix_loc, 1, GL_FALSE, 86 glm : :value_ptr ( p r o j e c t i o n M a t r i x ) ) ; gluseprogram ( programid2 ) ; // s é l e c t i o n du programme GLint modelviewprojmatrix_loc = glgetuniformlocation ( programid2, modelviewprojmatrix ) ;

144 Rémy Malgouyres, Programmation 3D avec OpenGL 92 gluniformmatrix4fv ( modelviewprojmatrix_loc, 1, GL_FALSE, 93 glm : :value_ptr ( p r o j e c t i o n M a t r i x * modelviewmatrix ) ) ; gluseprogram ( programid1 ) ; // s é l e c t i o n du programme de shaders g l C l e a r C o l o r ( 1. 0, 1. 0, 1. 0, 1. 0 ) ; 98 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; // on d e s s i n e l a b i l l e 101 enablevbo ( programid1, elementarrayobjsphere, vertexarrayobjsphere, 102 3, nverticessphere ) ; 103 gldrawelements (GL_TRIANGLES, 3* nfacessphere, GL_UNSIGNED_INT, NULL) ; gluseprogram ( programid2 ) ; // s é l e c t i o n du programme de shaders // On d e s s i n e l a sphère d environnement 108 enablevbo ( programid2, elementarrayobjsphereenviron, 109 vertexarrayobjsphereenviron, 3, nverticessphereenviron ) ; 110 gldrawelements (GL_TRIANGLES, 3* nfacessphereenviron, GL_UNSIGNED_INT, NULL) ; 111 } /* ************************************ */ 114 /* A f f i c h a g e à l écran */ 115 /* ************************************ */ 116 void A f f i c h a g e ( GLint nbframes, GLuint programid3, GLuint texframebufferid ) { 117 /* ************************************************* */ 118 /* S é l e c t i o n du frame b u f f e r de l écran (ID = 0) */ 119 glbindframebuffer (GL_FRAMEBUFFER, 0) ; 120 gluseprogram ( programid3 ) ; // s é l e c t i o n du programme de shaders 121 // On plaque l a t e x t u r e qui e s t s o r t i e du rendu dans l e frame b u f f e r 122 glbindtexture (GL_TEXTURE_2D, texframebufferid ) ; // On ne bouge pas pendant l e s premières frames 125 i f ( nbframes < 250) 126 nbframes=0 ; 127 else 128 nbframes = 250 ; // p r o j e c t i o n o r t h o g o n a l e 131 glm : :mat4 modelviewmatrix = glm : :ortho ( f, ( GLfloat ) l a r g e u r _ f e n e t r e, 0. 0 f, ( GLfloat ) hauteur_fenetre, f, f ) ; 134 // Rotation autour d un axe passant pas l e c e n t r e de l image 135 glm : :mat4 r o t a t i o n M a t r i x=glm : : t r a n s l a t e ( glm : :mat4 ( 1. 0 f ), glm : :vec3 ( ( GLfloat ) l a r g e u r _ f e n e t r e /2.0 f, ( GLfloat ) hauteur_fenetre /2.0 f, 0. 0 ) ) * 136 glm : :r o t a t e ( glm : :mat4 ( 1. 0 f ), f *nbframes, glm : :vec3 ( s i n ( * nbframes ), cos ( * nbframes ), 0. 0 ) ) * 138 glm : : t r a n s l a t e ( glm : :mat4 ( 1. 0 f ), glm : :vec3 ( ( GLfloat ) l a r g e u r _ f e n e t r e /2.0, ( GLfloat ) hauteur_fenetre /2.0 f, 0. 0 ) ) ; // on t r a n s l a t e en profondeur pour pas t rop que l e plan passe d e r r i è r e 141 modelviewmatrix=glm : : t r a n s l a t e ( modelviewmatrix, 142 glm : :vec3 ( 0. 0, 0.0, ( GLfloat ) l a r g e u r _ f e n e t r e ) /2.0 f ) ; // On f a i t l a r o t a t i o n en premier 145 modelviewmatrix = modelviewmatrix * r o t a t i o n M a t r i x ; 144

145 Chapitre 10 : Frame Buffer Objects /* On c a l c u l e l e temps e t on i n i t i a l i s e l a v a r i a b l e uniform */ 148 GLfloat temps = 0. 2 * ( GLfloat ) nbframes ; /* On récupère l emplacement ( en mémoire v i d é o ) de l a v a r i a b l e */ 151 GLint temps_loc = glgetuniformlocation ( programid3, temps ) ; 152 /* On i n i t i a l i s e l a v a r i a b l e avant l a f f i c h a g e */ 153 gluniform1f ( temps_loc, temps ) ; // envoi des matrices v e r s l e v e r t e x shader v i a une v a r i a b l e uniform 156 GLint modelviewprojmatrix_loc = glgetuniformlocation ( programid3, 157 modelviewprojmatrix ) ; 158 gluniformmatrix4fv ( modelviewprojmatrix_loc, 1, GL_FALSE, 159 glm : :value_ptr ( modelviewmatrix ) ) ; g l C l e a r C o l o r ( 0. 8, 0. 6, 0. 4, 1. 0 ) ; 162 g l C l e a r (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT) ; 163 // on d e s s i n e un r e c t a n g l e t e x t u r é 164 enablevbo ( programid3, elementarrayobjplan, 165 vertexarrayobjplan, 3, nverticesplan ) ; 166 gldrawelements (GL_TRIANGLES, 3* nfacesplan, GL_UNSIGNED_INT, NULL) ; } GLuint loadbmptexture ( const char * f i l e n a m e ) 171 { 172 GLuint tex_ id = 0 ; /* Chargement d une image à p a r t i r d un f i c h i e r avec l a SDL */ 175 SDL_Surface * s d l S u r f a c e = SDL_LoadBMP( f i l e n a m e ) ; /* Generate t e x t u r e */ 178 glgentextures ( 1, &tex_ id ) ; 179 glbindtexture (GL_TEXTURE_2D, tex_id ) ; /* Setup some parameters f o r t e x t u r e f i l t e r s and mipmapping */ 182 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 183 gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; glteximage2d (GL_TEXTURE_2D, 0, GL_RGB, 186 s d l S u r f a c e >w, s d l S u r f a c e >h, 0, GL_BGR, 187 GL_UNSIGNED_BYTE, s d l S u r f a c e >p i x e l s ) ; SDL_FreeSurface ( s d l S u r f a c e ) ; 190 return tex_id ; 191 } brief Fonction d i n i t i a l i s a t i o n de l a f e n ê t r e SDL windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowwidth l a r g e u r de l a f e n ê t r e en p i x e l s windowtitle T i t r e de l a f e n ê t r e dans sa barre de t i t r e 197 */ 198 SDL_Window * init_sdl_window ( int windowwidth, int windowheight, const char* windowtitle ) { 199 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3 ) ; 200 SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 3 ) ; 145

146 Rémy Malgouyres, Programmation 3D avec OpenGL 201 SDL_Init (SDL_INIT_VIDEO) ; 202 /* Le double b u f f e r i n g permet l e s animations temps r é e l */ 203 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1) ; 204 SDL_Window * window = SDL_CreateWindow ( windowtitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowwidth, windowheight, SDL_WINDOW_SHOWN SDL_WINDOW_OPENGL) ; 205 return window ; 206 } int main ( int argc, char** argv ) 209 { 210 GLfloat angle_twist =0 ; 211 GLfloat a n g l e _ e l e v a t i o n =30.0 ; 212 GLfloat angle_azimuth =30.0 ; 213 GLfloat d i s t a n c e =3.5 ; 214 GLfloat v i t e s s e =0.2 ; 215 GLushort mousex, mousey ; /* permet de mémoriser l a d e r n i è r e p o s i t i o n */ 216 /* de l a s o u r i s */ bool l e f t B u t t o n P r e s s e d = f a l s e ; 219 bool middlebuttonpressed = f a l s e ; /* I n i t i a l i s a t i o n d une f e n ê t r e SDL */ 222 SDL_Window *window =init_sdl_window ( l a r g e u r _ f e n e t r e, hauteur_fenetre, 223 Un t é t r a è d r e qui tourne sur l u i même ) ; 224 /* d é f i n i t i o n du c o n t e x t e OpenGL a s s o c i é à c e t t e f e n ê t r e */ 225 SDL_GLContext g l c o n t e x t ( SDL_GL_CreateContext ( window ) ) ; /* A f f i c h a g e c o n s o l e de l a v e r s i o n d OpenGL e t GLSL d i s p o n i b l e */ 228 p r i n t f ( OpenGL %s, GLSL %s \n, g l G e t S t r i n g (GL_VERSION), 229 g l G e t S t r i n g (GL_SHADING_LANGUAGE_VERSION) ) ; /* ************************************* */ 232 /* c r é a t i o n des shaders */ 233 GLuint vertexid1, fragmentid1 ; 234 GLuint programid1 ; 235 CreateShadersProgram(&programID1, &vertexid1, &fragmentid1, 236 vertexshader4. txt, 237 fragmentshader4_boule_verre. txt ) ; GLuint vertexid2, fragmentid2 ; 240 GLuint programid2 ; 241 CreateShadersProgram(&programID2, &vertexid2, &fragmentid2, 242 vertexshader3. txt, 243 fragmentshader3. txt ) ; GLuint vertexid3, fragmentid3 ; 246 GLuint programid3 ; 247 CreateShadersProgram(&programID3, &vertexid3, &fragmentid3, 248 vertexshader_bezier. txt, 249 fragmentshader_bezier. txt ) ; /* *************************************************************** */ 252 /* D é f i n i t i o n de l a p e r s p e c t i v e pour rendu dans l e frame b u f f e r */ 253 glm : :mat4 p r o j e c t i o n M a t r i x = glm : :p e r s p e c t i v e ( f, ( ( GLfloat ) l a r g e u r _ f e n e t r e ) / hauteur_fenetre, 146

147 Chapitre 10 : Frame Buffer Objects f, f ) ; /* ************************************************** */ 258 /* gldepthrange donne l i n t e r v a l l e des profondeurs p r i s e s en compte */ 259 gldepthrange ( 200.0,1500.0) ; 260 glenable (GL_DEPTH_TEST) ; /* ************************************ */ 264 /* Création des Vertex Buffer O b j e c t s */ 265 maillagesphere ( 1. 0, 100, 60, programid1, 266 &nverticessphere, &nfacessphere, 267 &vertexarrayobjsphere, &elementarrayobjsphere ) ; 268 maillagesphere ( , 100, 60, 269 programid2, 270 &nverticessphereenviron, &nfacessphereenviron, 271 &vertexarrayobjsphereenviron, 272 &elementarrayobjsphereenviron ) ; maillageplan ( l a r g e u r _ f e n e t r e, hauteur_fenetre, , 10, 276 programid3, &nverticesplan, &nfacesplan, 277 &vertexarrayobjplan, &elementarrayobjplan ) ; /* ************************************* */ 280 /* Chargement de l a t e x t u r e */ 281 GLuint texid = loadbmptexture ( argv [ 1 ] ) ; 282 i f (! texid ) 283 e x i t (EXIT_FAILURE) ; /* ************************************** */ 286 /* Création du Frame Buffer Object */ 287 GLuint framebufferid ; 288 GLuint texidframebuffer, texiddepth ; 289 glgentextures ( 1, &texidframebuffer ) ; 290 createframebuffer(&framebufferid, texidframebuffer, &texiddepth, l a r g e u r _ f e n e t r e, hauteur_fenetre ) ; /* **************************************** */ 293 /* A s s o c i a t i o n de l a t e x t u r e au sampler2d */ 294 /* dans programid1, l a t e x t u r e e s t l a c a r t e d environnement */ 295 GLint texturemap_loc = glgetuniformlocation ( programid1, texturemap ) ; 296 gluniform1ui ( texturemap_loc, texid ) ; 297 /* dans programid2, l a t e x t u r e e s t l a c a r t e d environnement */ 298 GLint texturemap_loc2 = glgetuniformlocation ( programid2, texturemap ) ; 299 gluniform1ui ( texturemap_loc2, texid ) ; /* Dans programid3, on plaque l a t e x t u r e en s o r t i e du frame b u f f e r */ 302 GLint texturemap_loc3 = glgetuniformlocation ( programid3, texturemap ) ; 303 gluniform1ui ( texturemap_loc3, texidframebuffer ) ; /* *****************************************************************\ 306 Boucle récupérant l e s évennements SDL e t a f f i c h a n t périodiquement 307 \***************************************************************** */ 308 bool terminer=f a l s e ; 309 SDL_Event evenements ; /* union contenant un évennement */ 147

148 Rémy Malgouyres, Programmation 3D avec OpenGL 310 GLint currenttime, nextdueframedate = 0 ; /* pour timer a f f i c h a g e */ int nbframes=0 ; /* compteur de frames */ 313 while (! terminer ) 314 { 315 while ( SDL_PollEvent(&evenements ) ) /* on d é f i l e l e s évennements */ 316 { 317 switch ( evenements. type ) { /* s u i v a n t l e type d évennement */ 318 case SDL_MOUSEBUTTONDOWN : /* Enfoncement d un bouton s o u r i s */ 319 switch ( evenements. button. button ) { 320 case SDL_BUTTON_LEFT : /* Bouton gauche */ 321 l e f t B u t t o n P r e s s e d=true ; 322 mousex = evenements. button. x ; /* mémorisation coordonnées de l a s o u r i s */ 323 mousey = evenements. button. y ; /* mémorisation coordonnées de l a s o u r i s */ 324 break ; 325 case SDL_BUTTON_MIDDLE : /* Bouton gauche */ 326 middlebuttonpressed=true ; 327 mousex = evenements. button. x ; /* mémorisation coordonnées de l a s o u r i s */ 328 mousey = evenements. button. y ; /* mémorisation coordonnées de l a s o u r i s */ 329 break ; 330 } 331 break ; 332 case SDL_MOUSEBUTTONUP : /* Relachement d un bouton s o u r i s */ 333 switch ( evenements. button. button ) { 334 case SDL_BUTTON_LEFT : /* Bouton gauche */ 335 l e f t B u t t o n P r e s s e d=f a l s e ; 336 break ; 337 case SDL_BUTTON_MIDDLE : /* Bouton gauche */ 338 middlebuttonpressed=f a l s e ; 339 break ; 340 } 341 break ; 342 case SDL_MOUSEMOTION : /* Mouvement de l a s o u r i s */ 343 i f ( l e f t B u t t o n P r e s s e d ) { 344 a n g l e _ e l e v a t i o n += v i t e s s e *( evenements. motion. y mousey ) ; 345 angle_azimuth += v i t e s s e *( evenements. motion. x mousex ) ; 346 mousex = evenements. motion. x ; /* e n r e g i s t r e m e n t des n o u v e l l e s */ 347 mousey = evenements. motion. y ; /* coordonnées de l a s o u r i s */ 348 } 349 i f ( middlebuttonpressed ) { 350 // d i s t a n c e += v i t e s s e *( evenements. motion. y mousey ) ; 351 // mousex = evenements. motion. x ; /* e n r e g i s t r e m e n t des n o u v e l l e s */ 352 //mousey = evenements. motion. y ; /* coordonnées de l a s o u r i s */ 353 } 354 break ; 355 case SDL_QUIT : /* fermeture de l a f e n ê t r e */ 356 terminer = true ; 357 break ; 358 } 359 } /* g e s t i o n des frames par secondes ( i c i 50 f p s ) */ 148

149 Chapitre 10 : Frame Buffer Objects 362 currenttime = SDL_GetTicks ( ) ; /* date courante en m i l l i s e c o n d e */ i f ( currenttime > nextdueframedate ) 365 { 366 nextdueframedate = currenttime + 20 ; /* t o u t e s l e s 20 m i l l i s e c o n d e s */ 367 // On f a i t un rendu dans l e frame b u f f e r 368 AffichageDansFrameBuffer ( framebufferid, projectionmatrix, nbframes, 369 programid1, programid2, 370 angle_elevation, angle_azimuth, distance, texid ) ; 371 // On f a i t un autre rendu v e r s l écran 372 A f f i c h a g e ( nbframes, programid3, texidframebuffer ) ; 373 nbframes++ ; /* On incrémente l e compteur de frames */ 374 SDL_GL_SwapWindow( window ) ; /* On envoie l e b u f f e r à l écran */ 375 } 376 } // L i b é r a t i o n des r e s s o u r c e s SDL 379 SDL_GL_DeleteContext ( g l c o n t e x t ) ; 380 SDL_DestroyWindow ( window ) ; 381 SDL_Quit ( ) ; 382 return 0 ; 383 } Dans le vertex shader, nous calculons la surface de Bézier au point dont les paramètres (u, v) sont les coordonnées de texture (qui sont dans [0; 1]). Nous déplaçons ensuite notre sommet (uniquement la coordonnée z) du point de la surface de Bézier. (notons qu ici le fragment shader renvoie simplement la couleur de la texture mais si l on souhaitait faire un éclairage il faudrait calculer les dérivées partielles de la surface de Bézier pour calculer le vecteur normal). Le vertex shader est le suivant : fbo/progc/vertexshader_bezier.txt 1 #v e r s i o n uniform mat4 modelviewprojmatrix ; 4 uniform float temps ; 5 6 // d é c l a r a t i o n des a t t r i b u t s. 7 // Le nom des a t t r i b u t s e s t d é c l a r é dans l e g l B i n d A t t r i b L o c a t i o n 8 in vec3 P o s i t i o n ; 9 in vec3 normal ; 10 i n vec2 TexCoord ; // coordonnée de t e x t u r e pour i n t e p o l a t i o n 13 out vec2 tex_coord ; void main ( void ) 17 { 18 float [ 2 5 ] xcoord ; 19 float [ 2 5 ] ycoord ; 20 float [ 2 5 ] zcoord ; // c a l c u l des p o i n t s de c o n t r ô l e de l a s u r f a c e de Bézier 23 // ( uniquement coordonnée z ) ; 24 for ( int i =0 ; i <5 ; i++) 149

150 Rémy Malgouyres, Programmation 3D avec OpenGL 25 for ( int j=0 ; j <5 ; j++){ 26 zcoord [ 5 * i+j ] = s i n ( 0. 2 * temps ) *4000.0*( i /4.0* i /4.0*(1.0 i / 4. 0 ) * 27 (1.0 i / 4. 0 ) ) 28 +s i n ( 0. 5 * temps ) *4000.0*( j /4.0* j /4.0*(1.0 j / 4. 0 ) * 29 (1.0 j / 4. 0 ) ) ; 30 } 31 float s = TexCoord. s ; 32 float t = TexCoord. t ; // Algorithme de C a s t e l j a u 35 float tmp01z ; 36 float tmp10z ; 37 for ( int l =1 ; l <5 ; l++) 38 for ( int i =0 ; i <4 ; i++) 39 for ( int j=0 ; j <4 ; j++){ 40 i f ( i <5 l && j <5 l ) { 41 tmp01z=(1 t ) *zcoord [ 5 * i+j ]+ t *zcoord [ 5 * i+j +1] ; 42 tmp10z=(1 t ) *zcoord [ 5 * ( i +1)+j ]+ t *zcoord [ 5 * ( i +1)+j +1] ; 43 zcoord [ 5 * i+j ] = (1 s ) *tmp01z + s *tmp10z ; 44 } 45 } 46 vec3 r e s u l t a t = vec3 ( 0. 0, 0. 0, zcoord [ 0 ] ) ; // On d é p l a c e l a p o s i t i o n de l a s u r f a c e de Bézier 49 vec3 newposition = P o s i t i o n + r e s u l t a t ; // On récupère l a coordonnée de t e x t u r e au sommet 52 tex_ coord = TexCoord ; 53 // p o s i t i o n du sommet après transformation e t p r o j e c t i o n 54 gl_position = modelviewprojmatrix * vec4 ( newposition. x, newposition. y, newposition. z, 1. 0 ) ; 55 // On r é d u i t l i n t e r v a l l e de profondeur pour é v i t e r l e s c l i p p i n g p l a n e s 56 // g l _ P o s i t i o n. z = g l _ P o s i t i o n. z / 2. 0 ; 57 } Le fragment shader est le suivant : fbo/progc/fragmentshader_bezier.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 6 // coordonnée de t e x t u r e i n t e r p o l é e 7 i n vec2 tex_ coord ; 8 9 void main ( void ) 10 { 11 // On récupère l a c o u l e u r du t e x e l aux coordonnée tex_coord 12 vec4 t e x t u r e C o l o r = texture2d ( texturemap, vec2 (1.0 tex_coord. s, tex_coord. t ) ) ; 13 // On a f f i c h e l a c o u l e u r i n t e r p o l é e 14 gl_fragcolor = vec4 ( t e x t u r e C o l o r. x, t e x t u r e C o l o r. y, t e x t u r e C o l o r. z, 1. 0 ) ; 15 } 150

151 Chapitre 10 : Frame Buffer Objects 10.2 Exemple d application : post-processing Cartoon Voici un fragment shader qui applique un filtre de lissage binômial de taille 7 7 en temps réel puis échantillonne la luminance sur 7 couleurs. fbo/progc/fragmentshader_postprocess.txt 1 #v e r s i o n // sampler 2D pour récupérer l a c o u l e u r de t e x t u r e 4 uniform sampler2d texturemap ; 5 6 // coordonnée de t e x t u r e i n t e r p o l é e 7 i n vec2 tex_ coord ; 8 9 void main ( void ) 10 { 11 float binom [7]= float [ 7 ] ( 1. 0, 6. 0, , , , 6. 0, 1. 0 ) ; 12 // a p p l i c a t i o n du masque de l i s s a g e 13 vec3 c o u l e u r = vec3 ( 0. 0, 0. 0, 0. 0 ) ; 14 for ( int i = 0 ; i <7 ; i ++) 15 for ( int j=0 ; j <7 ; j++){ 16 vec4 t e x t u r e C o l o r = texture2d ( texturemap, 17 vec2 (1.0 tex_coord. s+(i 3) * , 18 tex_coord. t+(j 3) * ) ) ; 19 c o u l e u r = c o u l e u r + binom [ i ] * binom [ j ] * ( t e x t u r e C o l o r. xyz ) ; 20 } 21 // n o r m a l i s a t i o n 22 c o u l e u r = ( 1. 0 / ( * ) ) * c o u l e u r ; // luminance 25 float YY = 0.299* c o u l e u r. x+0.587* c o u l e u r. y+0.114* c o u l e u r. z ; 26 // on a r r o n d i t 27 float l e v e l = f l o o r (7*YY) ; gl_fragcolor = vec4 ( l e v e l / 6. 0, l e v e l / 6. 0, l e v e l / 6. 0, 1. 0 ) ; 30 } On imagine aisément comment ce type de traitement 2D sur les textures peut être utilisé pour faire du traitement d image par GPGPU. 151

152 Rémy Malgouyres, Programmation 3D avec OpenGL Figure 10.2 : Rendu avec post-processing pour rendu non réaliste 152

TPs Architecture des ordinateurs DUT Informatique - M4104c SUJETS. R. Raffin Aix-Marseille Université romain.raffin-at-univ-amu.fr

TPs Architecture des ordinateurs DUT Informatique - M4104c SUJETS. R. Raffin Aix-Marseille Université romain.raffin-at-univ-amu.fr TPs Architecture des ordinateurs DUT Informatique - M4104c SUJETS R. Raffin Aix-Marseille Université romain.raffin-at-univ-amu.fr 2015 Table des matières 1 TP 1 : prise en main 2 1.1 Introduction.......................................................

Plus en détail

Chapitre II : Infographie et bibliothèques graphiques

Chapitre II : Infographie et bibliothèques graphiques Chapitre II : Infographie et bibliothèques graphiques Le premier chapitre a posé les bases perceptives et techniques de la production et de l'affichage d'images, ou plus globalement d'objets graphiques.

Plus en détail

Synthèse d'images I. Venceslas BIRI IGM Université de Marne La

Synthèse d'images I. Venceslas BIRI IGM Université de Marne La Synthèse d'images I Venceslas BIRI IGM Université de Marne La La synthèse d'images II. Rendu & Affichage 1. Introduction Venceslas BIRI IGM Université de Marne La Introduction Objectif Réaliser une image

Plus en détail

IMAGES NUMÉRIQUES MATRICIELLES EN SCILAB

IMAGES NUMÉRIQUES MATRICIELLES EN SCILAB IMAGES NUMÉRIQUES MATRICIELLES EN SCILAB Ce document, écrit par des animateurs de l IREM de Besançon, a pour objectif de présenter quelques unes des fonctions du logiciel Scilab, celles qui sont spécifiques

Plus en détail

Développement mobile MIDP 2.0 Mobile 3D Graphics API (M3G) JSR 184. Frédéric BERTIN fbertin@neotilus.com

Développement mobile MIDP 2.0 Mobile 3D Graphics API (M3G) JSR 184. Frédéric BERTIN fbertin@neotilus.com Développement mobile MIDP 2.0 Mobile 3D Graphics API (M3G) JSR 184 Frédéric BERTIN fbertin@neotilus.com Présentaion : Mobile 3D Graphics API JSR 184 M3G :présentation Package optionnel de l api J2ME. Prend

Plus en détail

point On obtient ainsi le ou les points d inter- entre deux objets».

point On obtient ainsi le ou les points d inter- entre deux objets». Déplacer un objet Cliquer sur le bouton «Déplacer». On peut ainsi rendre la figure dynamique. Attraper l objet à déplacer avec la souris. Ici, on veut déplacer le point A du triangle point ABC. A du triangle

Plus en détail

Les algorithmes de base du graphisme

Les algorithmes de base du graphisme Les algorithmes de base du graphisme Table des matières 1 Traçage 2 1.1 Segments de droites......................... 2 1.1.1 Algorithmes simples.................... 3 1.1.2 Algorithmes de Bresenham (1965).............

Plus en détail

TP Blender n 2 : Importation d un modèle SketchUp et animation

TP Blender n 2 : Importation d un modèle SketchUp et animation TP Blender n 2 : Importation d un modèle SketchUp et animation Service de Conception Géométrique Université de Liège Aérospatiale et Mécanique Conçu avec Blender 2.66 et SketchUp 8 De SketchUp à Blender

Plus en détail

Opérations de base sur ImageJ

Opérations de base sur ImageJ Opérations de base sur ImageJ TPs d hydrodynamique de l ESPCI, J. Bico, M. Reyssat, M. Fermigier ImageJ est un logiciel libre, qui fonctionne aussi bien sous plate-forme Windows, Mac ou Linux. Initialement

Plus en détail

Introduction au langage C

Introduction au langage C Introduction au langage C Cours 1: Opérations de base et premier programme Alexis Lechervy Alexis Lechervy (UNICAEN) Introduction au langage C 1 / 23 Les premiers pas Sommaire 1 Les premiers pas 2 Les

Plus en détail

Découverte du logiciel ordinateur TI-n spire / TI-n spire CAS

Découverte du logiciel ordinateur TI-n spire / TI-n spire CAS Découverte du logiciel ordinateur TI-n spire / TI-n spire CAS Mémento Ouvrir TI-Nspire CAS. Voici la barre d outils : L insertion d une page, d une activité, d une page où l application est choisie, pourra

Plus en détail

Vision industrielle et télédétection - Détection d ellipses. Guillaume Martinez 17 décembre 2007

Vision industrielle et télédétection - Détection d ellipses. Guillaume Martinez 17 décembre 2007 Vision industrielle et télédétection - Détection d ellipses Guillaume Martinez 17 décembre 2007 1 Table des matières 1 Le projet 3 1.1 Objectif................................ 3 1.2 Les choix techniques.........................

Plus en détail

LA PHYSIQUE DES MATERIAUX. Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE

LA PHYSIQUE DES MATERIAUX. Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE LA PHYSIQUE DES MATERIAUX Chapitre 1 LES RESEAUX DIRECT ET RECIPROQUE Pr. A. Belayachi Université Mohammed V Agdal Faculté des Sciences Rabat Département de Physique - L.P.M belayach@fsr.ac.ma 1 1.Le réseau

Plus en détail

L espace de travail de Photoshop

L espace de travail de Photoshop L espace de travail de Photoshop 1 Au cours de cette leçon, vous apprendrez à : ouvrir les fichiers Photoshop ; sélectionner et employer certains des outils dans le panneau Outils ; définir les options

Plus en détail

Calcul intégral élémentaire en plusieurs variables

Calcul intégral élémentaire en plusieurs variables Calcul intégral élémentaire en plusieurs variables PC*2 2 septembre 2009 Avant-propos À part le théorème de Fubini qui sera démontré dans le cours sur les intégrales à paramètres et qui ne semble pas explicitement

Plus en détail

Cours de Mécanique du point matériel

Cours de Mécanique du point matériel Cours de Mécanique du point matériel SMPC1 Module 1 : Mécanique 1 Session : Automne 2014 Prof. M. EL BAZ Cours de Mécanique du Point matériel Chapitre 1 : Complément Mathématique SMPC1 Chapitre 1: Rappels

Plus en détail

TUTORIAL 1 ETUDE D UN MODELE SIMPLIFIE DE PORTIQUE PLAN ARTICULE

TUTORIAL 1 ETUDE D UN MODELE SIMPLIFIE DE PORTIQUE PLAN ARTICULE TUTORIAL 1 ETUDE D UN MODELE SIMPLIFIE DE PORTIQUE PLAN ARTICULE L'objectif de ce tutorial est de décrire les différentes étapes dans CASTOR Concept / FEM permettant d'effectuer l'analyse statique d'une

Plus en détail

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2

Manuel d utilisation 26 juin 2011. 1 Tâche à effectuer : écrire un algorithme 2 éducalgo Manuel d utilisation 26 juin 2011 Table des matières 1 Tâche à effectuer : écrire un algorithme 2 2 Comment écrire un algorithme? 3 2.1 Avec quoi écrit-on? Avec les boutons d écriture........

Plus en détail

Adobe Illustrator Logiciel de dessin vectoriel et de Cartographie Assistée par Ordinateur

Adobe Illustrator Logiciel de dessin vectoriel et de Cartographie Assistée par Ordinateur Adobe Illustrator Logiciel de dessin vectoriel et de Cartographie Assistée par Ordinateur I- Ouverture d une nouvelle feuille de travail Fichier / Nouveau (ou ctrl + N) Indiquer dans la fenêtre qui s ouvre

Plus en détail

Réalisation de cartes vectorielles avec Word

Réalisation de cartes vectorielles avec Word Réalisation de cartes vectorielles avec Word Vectorisation de la carte Après avoir scanné ou avoir récupéré un fond de carte sur Internet, insérez-la dans votre fichier Word : Commencez par rendre visible

Plus en détail

Représentation géométrique d un nombre complexe

Représentation géométrique d un nombre complexe CHAPITRE 1 NOMBRES COMPLEXES 1 Représentation géométrique d un nombre complexe 1. Ensemble des nombres complexes Soit i le nombre tel que i = 1 L ensemble des nombres complexes est l ensemble des nombres

Plus en détail

Analyse de la vidéo. Chapitre 4.1 - La modélisation pour le suivi d objet. 10 mars 2015. Chapitre 4.1 - La modélisation d objet 1 / 57

Analyse de la vidéo. Chapitre 4.1 - La modélisation pour le suivi d objet. 10 mars 2015. Chapitre 4.1 - La modélisation d objet 1 / 57 Analyse de la vidéo Chapitre 4.1 - La modélisation pour le suivi d objet 10 mars 2015 Chapitre 4.1 - La modélisation d objet 1 / 57 La représentation d objets Plan de la présentation 1 La représentation

Plus en détail

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles) 1/4 Objectif de ce cours /4 Objectifs de ce cours Introduction au langage C - Cours Girardot/Roelens Septembre 013 Du problème au programme I passer d un problème exprimé en français à la réalisation d

Plus en détail

Initiation. àl algorithmique et à la programmation. en C

Initiation. àl algorithmique et à la programmation. en C Initiation àl algorithmique et à la programmation en C Initiation àl algorithmique et à la programmation en C Cours avec 129 exercices corrigés Illustration de couverture : alwyncooper - istock.com Dunod,

Plus en détail

COMMENCER AVEC VUE. Chapitre 1

COMMENCER AVEC VUE. Chapitre 1 Chapitre 1 COMMENCER AVEC VUE Traduction en français du premier chapitre du manuel d'utilisation du logiciel VUE. Traduit de l'américain par Bernard Aubanel. CRÉER UNE NOUVELLE CARTE Pour ouvrir VUE: 1.

Plus en détail

Utilisation de la plateforme VIA ecollaboration

Utilisation de la plateforme VIA ecollaboration Entrer sur la plateforme L invitation que vous avez reçue comporte un lien vers la plateforme VIA ecollaboration (salle privée de François Guérin de Communagir). Pour y accéder, cliquez simplement sur

Plus en détail

Infolettre #18 : Les graphiques avec Excel 2010

Infolettre #18 : Les graphiques avec Excel 2010 Infolettre #18 : Les graphiques avec Excel 2010 Table des matières Introduction... 1 Hourra! Le retour du double-clic... 1 Modifier le graphique... 4 Onglet Création... 4 L onglet Disposition... 7 Onglet

Plus en détail

Programmation linéaire

Programmation linéaire 1 Programmation linéaire 1. Le problème, un exemple. 2. Le cas b = 0 3. Théorème de dualité 4. L algorithme du simplexe 5. Problèmes équivalents 6. Complexité de l Algorithme 2 Position du problème Soit

Plus en détail

Mise en scène d un modèle dans l espace 3D

Mise en scène d un modèle dans l espace 3D CHAPITRE 3 Mise en scène d un modèle dans l espace 3D Blender permet de construire des espaces à la manière d une scène de théâtre. Pour cela, il présente dès l ouverture tout ce dont on a besoin : un

Plus en détail

Projet de traitement d'image - SI 381 reconstitution 3D d'intérieur à partir de photographies

Projet de traitement d'image - SI 381 reconstitution 3D d'intérieur à partir de photographies Projet de traitement d'image - SI 381 reconstitution 3D d'intérieur à partir de photographies Régis Boulet Charlie Demené Alexis Guyot Balthazar Neveu Guillaume Tartavel Sommaire Sommaire... 1 Structure

Plus en détail

Création WEB avec DreamweaverMX

Création WEB avec DreamweaverMX Creation Web avec DreamweaverMX MX Initiation Sommaire.preparation.mise en forme.liens hypertextes.images.liens sur images.images avec zones sensibles.images survolees.liens de type courriel.apercu dans

Plus en détail

Fonctions linéaires et affines. 1 Fonctions linéaires. 1.1 Vocabulaire. 1.2 Représentation graphique. 3eme

Fonctions linéaires et affines. 1 Fonctions linéaires. 1.1 Vocabulaire. 1.2 Représentation graphique. 3eme Fonctions linéaires et affines 3eme 1 Fonctions linéaires 1.1 Vocabulaire Définition 1 Soit a un nombre quelconque «fixe». Une fonction linéaire associe à un nombre x quelconque le nombre a x. a s appelle

Plus en détail

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP COURS PROGRAMMATION INITIATION AU LANGAGE C SUR MICROCONTROLEUR PIC page 1 / 7 INITIATION AU LANGAGE C SUR PIC DE MICROSHIP I. Historique du langage C 1972 : naissance du C dans les laboratoires BELL par

Plus en détail

Guide de l utilisateur. Faites connaissance avec la nouvelle plateforme interactive de

Guide de l utilisateur. Faites connaissance avec la nouvelle plateforme interactive de Guide de l utilisateur Faites connaissance avec la nouvelle plateforme interactive de Chenelière Éducation est fière de vous présenter sa nouvelle plateforme i+ Interactif. Conçue selon vos besoins, notre

Plus en détail

www.imprimermonlivre.com

www.imprimermonlivre.com 0 www.imprimermonlivre.com Composition d une couverture avec Word L objectif de ce guide est de vous proposer un mode opératoire pour créer une couverture avec Word. Nous vous rappelons toutefois que Word

Plus en détail

Optimisation, traitement d image et éclipse de Soleil

Optimisation, traitement d image et éclipse de Soleil Kléber, PCSI1&3 014-015 I. Introduction 1/8 Optimisation, traitement d image et éclipse de Soleil Partie I Introduction Le 0 mars 015 a eu lieu en France une éclipse partielle de Soleil qu il était particulièrement

Plus en détail

GUIDE Excel (version débutante) Version 2013

GUIDE Excel (version débutante) Version 2013 Table des matières GUIDE Excel (version débutante) Version 2013 1. Créer un nouveau document Excel... 3 2. Modifier un document Excel... 3 3. La fenêtre Excel... 4 4. Les rubans... 4 5. Saisir du texte

Plus en détail

Licence ST Université Claude Bernard Lyon I LIF1 : Algorithmique et Programmation C Bases du langage C 1 Conclusion de la dernière fois Introduction de l algorithmique générale pour permettre de traiter

Plus en détail

Le langage C. Séance n 4

Le langage C. Séance n 4 Université Paris-Sud 11 Institut de Formation des Ingénieurs Remise à niveau INFORMATIQUE Année 2007-2008 Travaux pratiques d informatique Le langage C Séance n 4 But : Vous devez maîtriser à la fin de

Plus en détail

Introduction à MATLAB R

Introduction à MATLAB R Introduction à MATLAB R Romain Tavenard 10 septembre 2009 MATLAB R est un environnement de calcul numérique propriétaire orienté vers le calcul matriciel. Il se compose d un langage de programmation, d

Plus en détail

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/

Souad EL Bernoussi. Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/ Recherche opérationnelle Les démonstrations et les exemples seront traités en cours Souad EL Bernoussi Groupe d Analyse Numérique et Optimisation Rabat http ://www.fsr.ac.ma/ano/ Table des matières 1 Programmation

Plus en détail

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation impérative et structures de données simples Introduction au langage C Sandrine Blazy - 1ère année 24 octobre 2007 Cours d Algorithmique-Programmation

Plus en détail

ESPACE MULTIMEDIA DU CANTON DE ROCHESERVIERE

ESPACE MULTIMEDIA DU CANTON DE ROCHESERVIERE ESPACE MULTIMEDIA DU CANTON DE ROCHESERVIERE Atelier «pour approfondir» Montage vidéo avec Windows Live Movie Maker 1 Présentation de Windows Live Movie Maker Windows Live Movie Maker est le logiciel de

Plus en détail

C.F.A.O. : Conception et Fabrication Assistées par Ordinateur.

C.F.A.O. : Conception et Fabrication Assistées par Ordinateur. C.F.A.O. : Conception et Fabrication Assistées par Ordinateur. La CFAO réunit dans une même démarche informatique les actions de conception et de fabrication d un objet. La technique utilisée permet à

Plus en détail

RIE LE RENDU THEO. 2 e trim ÉTAPE DE FINITION BOÎTE DE DIALOGUE. remarques

RIE LE RENDU THEO. 2 e trim ÉTAPE DE FINITION BOÎTE DE DIALOGUE. remarques THEO RIE LE RENDU 2 e trim JANVIER 2008 remarques ÉTAPE DE FINITION Le rendu est la partie finale de notre création, à ce moment on décide que notre 3D est finie et l on en réalise une image 2D Cette image

Plus en détail

INTRODUCTION À L ANALYSE FACTORIELLE DES CORRESPONDANCES

INTRODUCTION À L ANALYSE FACTORIELLE DES CORRESPONDANCES INTRODUCTION À L ANALYSE FACTORIELLE DES CORRESPONDANCES Dominique LAFFLY Maître de Conférences, Université de Pau Laboratoire Société Environnement Territoire UMR 5603 du CNRS et Université de Pau Domaine

Plus en détail

Maîtriser les fonctionnalités d un traitement de texte (Word OpenOffice)

Maîtriser les fonctionnalités d un traitement de texte (Word OpenOffice) Utilisation de l'ordinateur et apport des TIC en enseignement (1NP) Module 03 Maîtriser les fonctionnalités d un traitement de texte. Sens du Module De nombreux documents remis aux enfants sont réalisés

Plus en détail

Tp_chemins..doc. Dans la barre "arche 2" couleur claire 1/5 21/01/13

Tp_chemins..doc. Dans la barre arche 2 couleur claire 1/5 21/01/13 TP de création : utilisation des chemins vectoriels Finis les mauvais rêves : vous aurez enfin votre dreamcatcher (Indienss des Grands Lacs) 1 ) Créez une nouvelle image de 300 pixels sur 600 pixels en

Plus en détail

Création d une SIGNATURE ANIMÉE avec PHOTOFILTRE 7

Création d une SIGNATURE ANIMÉE avec PHOTOFILTRE 7 Création d une SIGNATURE ANIMÉE avec PHOTOFILTRE 7 L animation est obtenue par défilement des images décomposant le mouvement de traçage de la signature. Les étapes successives seront : 1. Choix de la

Plus en détail

PRISE EN MAIN D ILLUSTRATOR

PRISE EN MAIN D ILLUSTRATOR CHAPITRE 1 PRISE EN MAIN D ILLUSTRATOR Présentation... 13 Contenu du livre... 13 Les nouveautés... 14 Composants de l interface... 15 Afficher les documents... 20 Organiser son espace de travail... 21

Plus en détail

COURS EULER: PROGRAMME DE LA PREMIÈRE ANNÉE

COURS EULER: PROGRAMME DE LA PREMIÈRE ANNÉE COURS EULER: PROGRAMME DE LA PREMIÈRE ANNÉE Le cours de la première année concerne les sujets de 9ème et 10ème années scolaires. Il y a bien sûr des différences puisque nous commençons par exemple par

Plus en détail

pcon.planner 6 Préparer et présenter une implantation en toute simplicité

pcon.planner 6 Préparer et présenter une implantation en toute simplicité pcon.planner 6 Préparer et présenter une implantation en toute simplicité Sommaire 1. Installation :... 3 2. Démarrer le logiciel :... 3 3. Interface :... 3 4. Naviguer :... 4 5. Réaliser une implantation

Plus en détail

Projet Matlab : un logiciel de cryptage

Projet Matlab : un logiciel de cryptage Projet Matlab : un logiciel de cryptage La stéganographie (du grec steganos : couvert et graphein : écriture) consiste à dissimuler une information au sein d'une autre à caractère anodin, de sorte que

Plus en détail

TOUT CE QU IL FAUT SAVOIR POUR LE BREVET

TOUT CE QU IL FAUT SAVOIR POUR LE BREVET TOUT E QU IL FUT SVOIR POUR LE REVET NUMERIQUE / FONTIONS eci n est qu un rappel de tout ce qu il faut savoir en maths pour le brevet. I- Opérations sur les nombres et les fractions : Les priorités par

Plus en détail

a et b étant deux nombres relatifs donnés, une fonction affine est une fonction qui a un nombre x associe le nombre ax + b

a et b étant deux nombres relatifs donnés, une fonction affine est une fonction qui a un nombre x associe le nombre ax + b I Définition d une fonction affine Faire l activité 1 «une nouvelle fonction» 1. définition générale a et b étant deux nombres relatifs donnés, une fonction affine est une fonction qui a un nombre x associe

Plus en détail

PR OC E D U RE S D E B A S E

PR OC E D U RE S D E B A S E Photofiltre Préparé par Philipe Lampron, auxiliaire du cours FPE 7650 en 2004-2005. *** Pour optimiser une image : enregistrer sous et augmenter la compression PR OC E D U RE S D E B A S E PhotoFiltre

Plus en détail

UTILISATION D'UN RADIOCHRONOMETRE POUR DATER DES GRANITES

UTILISATION D'UN RADIOCHRONOMETRE POUR DATER DES GRANITES Fiche sujet-candidat Les géologues s interrogent sur la chronologie de mise en place de deux granites du Massif Central. On cherche à savoir si une méthode de radiochronologie permettrait de déterminer

Plus en détail

05/09/2015. M Ponctualité : CM TD TP & Projet Æ En cas d absence : récupérer!!! 3 05/09/2015

05/09/2015. M Ponctualité : CM TD TP & Projet Æ En cas d absence : récupérer!!! 3 05/09/2015 Synthèse d images L3 Présentation du module Sandrine LANQUETIN Bureau G08 sandrine.lanquetin@u-bourgogne.fr Qui? Quand? Mode d emploi M Intervenants : Æ S. Lanquetin sandrine.lanquetin@u-bourgogne.fr M

Plus en détail

VOS PREMIERS PAS AVEC TRACENPOCHE

VOS PREMIERS PAS AVEC TRACENPOCHE Vos premiers pas avec TracenPoche page 1/16 VOS PREMIERS PAS AVEC TRACENPOCHE Un coup d'oeil sur l'interface de TracenPoche : La zone de travail comporte un script, une figure, un énoncé, une zone d analyse,

Plus en détail

Fête de la science Initiation au traitement des images

Fête de la science Initiation au traitement des images Fête de la science Initiation au traitement des images Détection automatique de plaques minéralogiques à partir d'un téléphone portable et atelier propose de créer un programme informatique pour un téléphone

Plus en détail

Avant-propos FICHES PRATIQUES EXERCICES DE PRISE EN MAIN CAS PRATIQUES

Avant-propos FICHES PRATIQUES EXERCICES DE PRISE EN MAIN CAS PRATIQUES Avant-propos Conçu par des pédagogues expérimentés, son originalité est d être à la fois un manuel de formation et un manuel de référence complet présentant les bonnes pratiques d utilisation. FICHES PRATIQUES

Plus en détail

Aide GeoGebra. Manuel Officiel 3.2. Markus Hohenwarter et Judith Hohenwarter www.geogebra.org

Aide GeoGebra. Manuel Officiel 3.2. Markus Hohenwarter et Judith Hohenwarter www.geogebra.org Aide GeoGebra Manuel Officiel 3.2 Markus Hohenwarter et Judith Hohenwarter www.geogebra.org 1 Aide GeoGebra 3.2 Auteurs Markus Hohenwarter, markus@geogebra.org Judith Hohenwarter, judith@geogebra.org Traduction

Plus en détail

Correction des Travaux Pratiques Organiser son espace de travail

Correction des Travaux Pratiques Organiser son espace de travail Module 01 Correction des Travaux Pratiques Organiser son espace de travail Correction de l exercice N 1 Organiser son espace de travail Objectif de l exercice : 1. Comprendre le dock 2. Afficher les règles

Plus en détail

2013 Pearson France Adobe Illustrator CC Adobe Press

2013 Pearson France Adobe Illustrator CC Adobe Press Au cours de cette démonstration d Adobe Illustrator CC, vous découvrirez les nouvelles fonctionnalités du logiciel, comme les outils de retouche et la sélection du texte, ainsi que d autres aspects fondamentaux

Plus en détail

L environnement de travail de Windows 8

L environnement de travail de Windows 8 4 L environnement de travail de Windows 8 Mais où est donc passé le bouton Démarrer? L écran d accueil joue le rôle de l ancien bouton Démarrer. Si l icône de l application que vous voulez lancer n est

Plus en détail

LPP SAINT JOSEPH BELFORT MODE OPERATOIRE ACTIVINSPIRE. Bonne utilisation à toutes et tous! UTILISATION DES TBI LE LOGICIEL ACTIVINSPIRE

LPP SAINT JOSEPH BELFORT MODE OPERATOIRE ACTIVINSPIRE. Bonne utilisation à toutes et tous! UTILISATION DES TBI LE LOGICIEL ACTIVINSPIRE LPP SAINT JOSEPH BELFORT MODE OPERATOIRE ACTIVINSPIRE Utilisation des TBI UTILISATION DES TBI LE LOGICIEL ACTIVINSPIRE T B utoriel de base, ce mode d emploi a pour objectif de vous présenter les principales

Plus en détail

Création de maquette web

Création de maquette web Création de maquette web avec Fireworks Il faut travailler en 72dpi et en pixels, en RVB Fireworks étant un logiciel dédié à la création de maquettes pour le web il ne propose que les pixels pour le texte

Plus en détail

1 Introduction C+ + Algorithm e. languag. Algorigramm. machine binaire. 1-1 Chaîne de développement. Séance n 4

1 Introduction C+ + Algorithm e. languag. Algorigramm. machine binaire. 1-1 Chaîne de développement. Séance n 4 1 Introduction 1-1 Chaîne de développement Algorithm e C+ + Algorigramm e languag e machine binaire Le programme est écrit à l aide de Multiprog sous forme d algorigramme puis introduit dans le microcontrôleur

Plus en détail

Programmation C++ (débutant)/instructions for, while et do...while

Programmation C++ (débutant)/instructions for, while et do...while Programmation C++ (débutant)/instructions for, while et do...while 1 Programmation C++ (débutant)/instructions for, while et do...while Le cours du chapitre 4 : le for, while et do...while La notion de

Plus en détail

Niveau 1. Atelier d'initiation à l'ordinateur ... Fondation de la Bibliothèque Memphrémagog inc. Magog (Québec) J1X 2E7 Tél.

Niveau 1. Atelier d'initiation à l'ordinateur ... Fondation de la Bibliothèque Memphrémagog inc. Magog (Québec) J1X 2E7 Tél. . Fondation de la Bibliothèque Memphrémagog inc. Magog (Québec) J1X 2E7 Tél. : 843-1330 Atelier d'initiation à l'ordinateur Niveau 1.......... JB septembre 20085 1 Section I : Introduction à l ordinateur

Plus en détail

Premiers Pas avec OneNote 2013

Premiers Pas avec OneNote 2013 Premiers Pas avec OneNote 2 Présentation de OneNote 3 Ouverture du logiciel OneNote 4 Sous Windows 8 4 Sous Windows 7 4 Création de l espace de travail OneNote 5 Introduction 5 Présentation des différentes

Plus en détail

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

INTRODUCTION A JAVA. Fichier en langage machine Exécutable INTRODUCTION A JAVA JAVA est un langage orienté-objet pur. Il ressemble beaucoup à C++ au niveau de la syntaxe. En revanche, ces deux langages sont très différents dans leur structure (organisation du

Plus en détail

Excel 2007 Niveau 3 Page 1 www.admexcel.com

Excel 2007 Niveau 3 Page 1 www.admexcel.com Excel 2007 Niveau 3 Page 1 TABLE DES MATIERES UTILISATION DE LISTES DE DONNEES... 4 REMARQUES PREALABLES SUR LES LISTES DE DONNEES... 4 METTRE EN FORME LE TABLEAU... 6 METTRE LA LISTE A JOUR... 7 a/ Directement

Plus en détail

AC AB. A B C x 1. x + 1. d où. Avec un calcul vu au lycée, on démontre que cette solution admet deux solutions dont une seule nous intéresse : x =

AC AB. A B C x 1. x + 1. d où. Avec un calcul vu au lycée, on démontre que cette solution admet deux solutions dont une seule nous intéresse : x = LE NOMBRE D OR Présentation et calcul du nombre d or Euclide avait trouvé un moyen de partager en deu un segment selon en «etrême et moyenne raison» Soit un segment [AB]. Le partage d Euclide consiste

Plus en détail

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java Info0101 Intro. à l'algorithmique et à la programmation Cours 3 Le langage Java Pierre Delisle, Cyril Rabat et Christophe Jaillet Université de Reims Champagne-Ardenne Département de Mathématiques et Informatique

Plus en détail

MAILING KOMPOZER... 2 CREEZ UNE PAGE... 2 FORMAT DE LA PAGE... 2 AJOUTER DU TEXTE SUR UNE PAGE... 4

MAILING KOMPOZER... 2 CREEZ UNE PAGE... 2 FORMAT DE LA PAGE... 2 AJOUTER DU TEXTE SUR UNE PAGE... 4 MAILING Table des matières KOMPOZER... 2 CREEZ UNE PAGE... 2 FORMAT DE LA PAGE... 2 AJOUTER DU TEXTE SUR UNE PAGE... 4 INSERER UNE IMAGE (OU UNE PHOTO) PAS DE COPIER / COLLER... 5 INSERER UN TABLEAU...

Plus en détail

Celestia. 1. Introduction à Celestia (2/7) 1. Introduction à Celestia (1/7) Université du Temps Libre - 08 avril 2008

Celestia. 1. Introduction à Celestia (2/7) 1. Introduction à Celestia (1/7) Université du Temps Libre - 08 avril 2008 GMPI*EZVI0EFSVEXSMVIH%WXVSTL]WMUYIHI&SVHIEY\ 1. Introduction à Celestia Celestia 1.1 Généralités 1.2 Ecran d Ouverture 2. Commandes Principales du Menu 3. Exemples d Applications 3.1 Effet de l atmosphère

Plus en détail

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing 3/4/27 Programmation Avancée Multimédia Multithreading Benoît Piranda Équipe SISAR Université de Marne La Vallée Besoin Programmes à traitements simultanés Réseau Réseau Afficher une animation en temps

Plus en détail

Cours de numérisation sur Epson Perfection

Cours de numérisation sur Epson Perfection Cours de numérisation sur Epson Perfection 1- Vérifiez la propreté de la vitre, placez l original sur celle-ci. À savoir, on peut numériser des transparents avec ce scanner ; il a un capteur CCD dans le

Plus en détail

Baccalauréat ES Pondichéry 7 avril 2014 Corrigé

Baccalauréat ES Pondichéry 7 avril 2014 Corrigé Baccalauréat ES Pondichéry 7 avril 204 Corrigé EXERCICE 4 points Commun à tous les candidats. Proposition fausse. La tangente T, passant par les points A et B d abscisses distinctes, a pour coefficient

Plus en détail

Utilisation de XnView

Utilisation de XnView http://www.rakforgeron.fr 27/02/2015 Utilisation de XnView Les photos d'actes généalogiques, les scans de documents réalisés par vous, ou vos saisies d'écran de documents téléchargés sur Internet, au-delà

Plus en détail

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3. 1. Structure d un programme C Un programme est un ensemble de fonctions. La fonction "main" constitue le point d entrée pour l exécution. Un exemple simple : #include int main() { printf ( this

Plus en détail

Designer d escalier GUIDE DE L UTILISATEUR. Stair Designer-1

Designer d escalier GUIDE DE L UTILISATEUR. Stair Designer-1 Designer d escalier GUIDE DE L UTILISATEUR Stair Designer-1 Stair Designer-2 Designer d escalier Le Designer d escalier rend facile la réalisation et la mise en place d escaliers sur mesure dans votre

Plus en détail

Dans l idéal, ceci devrait être fait en amont pour chaque image envoyée sur l espace de stockage de votre site internet.

Dans l idéal, ceci devrait être fait en amont pour chaque image envoyée sur l espace de stockage de votre site internet. 1- Optimiser le poids de votre image : Dans l idéal, ceci devrait être fait en amont pour chaque image envoyée sur l espace de stockage de votre site internet. Tous les types d utilisateurs (auteur, publicateur,

Plus en détail

INSERER DES OBJETS - LE RUBAN INSERTION... 3 TABLEAUX

INSERER DES OBJETS - LE RUBAN INSERTION... 3 TABLEAUX TABLE DES MATIERES Livret Utilisateur Excel 2007 Niveau 2 INSERER DES OBJETS - LE RUBAN INSERTION... 3 TABLEAUX... 4 Les tableaux croisés dynamiques... 4 Création d un tableau croisé... 5 Comparer des

Plus en détail

TP : Gestion d une image au format PGM

TP : Gestion d une image au format PGM TP : Gestion d une image au format PGM Objectif : L objectif du sujet est de créer une classe de manipulation d images au format PGM (Portable GreyMap), et de programmer des opérations relativement simples

Plus en détail

AGASC / BUREAU INFORMATION JEUNESSE 06700 Saint Laurent du Var Tel : 04.93.07.00.66 bij@agasc.fr www.agasc.fr. Word: Les tableaux.

AGASC / BUREAU INFORMATION JEUNESSE 06700 Saint Laurent du Var Tel : 04.93.07.00.66 bij@agasc.fr www.agasc.fr. Word: Les tableaux. Word: Les tableaux Introduction 6 ième partie Il est préférable par moments de présenter de l'information sous forme de tableau. Les instructions qui suivent démontrent comment créer un tableau et comment

Plus en détail

La programmation orientée objet et le langage C++

La programmation orientée objet et le langage C++ Cours précédents La programmation orientée objet et le langage C++ Pablo Rauzy rauzy @ enst fr pablo.rauzy.name/teaching.html#epu-cpp EISE4 @ Polytech UPMC 22 octobre 2014 Cours 5 Nouveautés du C++ par

Plus en détail

Note de cours. Introduction à Excel 2007

Note de cours. Introduction à Excel 2007 Note de cours Introduction à Excel 2007 par Armande Pinette Cégep du Vieux Montréal Excel 2007 Page: 2 de 47 Table des matières Comment aller chercher un document sur CVMVirtuel?... 8 Souris... 8 Clavier

Plus en détail

Planifier et contrôler un projet avec Microsoft Project

Planifier et contrôler un projet avec Microsoft Project Planifier et contrôler un projet avec Microsoft Project Martin Schmidt Anteo-consulting.fr 27/02/2009 Principes de base Copyright Anteo-Consulting Page 2 Saisir des tâches Tout nouveau projet commence

Plus en détail

Sujet proposé par Yves M. LEROY. Cet examen se compose d un exercice et de deux problèmes. Ces trois parties sont indépendantes.

Sujet proposé par Yves M. LEROY. Cet examen se compose d un exercice et de deux problèmes. Ces trois parties sont indépendantes. Promotion X 004 COURS D ANALYSE DES STRUCTURES MÉCANIQUES PAR LA MÉTHODE DES ELEMENTS FINIS (MEC 568) contrôle non classant (7 mars 007, heures) Documents autorisés : polycopié ; documents et notes de

Plus en détail

Saisissez le login et le mot de passe (attention aux minuscules et majuscules) qui vous ont

Saisissez le login et le mot de passe (attention aux minuscules et majuscules) qui vous ont I Open Boutique Sommaire : I Open Boutique... 1 Onglet «Saisie des Produits»... 3 Création d'une nouvelle fiche boutique :... 3 Création d'une nouvelle fiche lieux de retraits :... 10 Création d'une nouvelle

Plus en détail

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013 Rendu Temps Réel - OpenGL 4 et compute shaders December 18, 2013 résumé des épisodes précédents... création des objets opengl, organisation des données, configuration du pipeline, draw,... opengl 4.3 :

Plus en détail

Sommaire. Images Actives Logiciel libre développé par le CRDP de l académie de Versailles 2 Rue Pierre Bourdan Marly le Roi - 78160

Sommaire. Images Actives Logiciel libre développé par le CRDP de l académie de Versailles 2 Rue Pierre Bourdan Marly le Roi - 78160 Sommaire Choisir son image... 2 Enregistrer son travail... 3 Créer les détails... 4 Supprimer une zone ou un détail... 6 Les commentaires... 6 Créer un lien hypertexte... 8 Appliquer un modèle... 8 Personnaliser

Plus en détail

Cours 7 : Utilisation de modules sous python

Cours 7 : Utilisation de modules sous python Cours 7 : Utilisation de modules sous python 2013/2014 Utilisation d un module Importer un module Exemple : le module random Importer un module Exemple : le module random Importer un module Un module est

Plus en détail

Solutions du chapitre 4

Solutions du chapitre 4 Solutions du chapitre 4 Structures de contrôle: première partie 4.9 Identifiez et corrigez les erreurs (il peut y en avoir plus d une par segment de code) de chacune des proposition suivantes: a) if (

Plus en détail

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51 DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51 PLAN DU COURS Introduction au langage C Notions de compilation Variables, types, constantes, tableaux, opérateurs Entrées sorties de base Structures de

Plus en détail

DURÉE DU JOUR EN FONCTION DE LA DATE ET DE LA LATITUDE

DURÉE DU JOUR EN FONCTION DE LA DATE ET DE LA LATITUDE DURÉE DU JUR E FCTI DE LA DATE ET DE LA LATITUDE ous allons nous intéresser à la durée du jour, prise ici dans le sens de période d éclairement par le Soleil dans une journée de 4 h, en un lieu donné de

Plus en détail

Programmation système I Les entrées/sorties

Programmation système I Les entrées/sorties Programmation système I Les entrées/sorties DUT 1 re année Université de Marne La vallée Les entrées-sorties : E/O Entrées/Sorties : Opérations d échanges d informations dans un système informatique. Les

Plus en détail