gKit2 light
tuto_dynamic_cubemap.cpp
Go to the documentation of this file.
1 
3 
4 #include <memory>
5 
6 #include "wavefront.h"
7 #include "texture.h"
8 
9 #include "orbiter.h"
10 #include "program.h"
11 #include "uniforms.h"
12 #include "draw.h"
13 
14 #include "app_camera.h" // classe Application a deriver
15 
16 
18 GLuint read_cubemap( const int unit, const char *filename, const GLenum texel_type = GL_RGBA )
19 {
20  // les 6 faces sur une croix
21  ImageData image= read_image_data(filename);
22  if(image.pixels.empty())
23  return 0;
24 
25  int w= image.width / 4;
26  int h= image.height / 3;
27  assert(w == h);
28 
29  GLenum data_format;
30  GLenum data_type= GL_UNSIGNED_BYTE;
31  if(image.channels == 3)
32  data_format= GL_RGB;
33  else // par defaut
34  data_format= GL_RGBA;
35 
36  // creer la texture
37  GLuint texture= 0;
38  glGenTextures(1, &texture);
39  glActiveTexture(GL_TEXTURE0 + unit);
40  glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
41 
42  // creer les 6 faces
43  // chaque face de la cubemap est un rectangle [image.width/4 x image.height/3] dans l'image originale
44  struct { int x, y; } faces[]= {
45  {0, 1}, // X+
46  {2, 1}, // X-
47  {1, 2}, // Y+
48  {1, 0}, // Y-
49  {1, 1}, // Z+
50  {3, 1}, // Z-
51  };
52 
53  for(int i= 0; i < 6; i++)
54  {
55  ImageData face= flipX(flipY(copy(image, faces[i].x*w, faces[i].y*h, w, h)));
56 
57  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
58  texel_type, w, h, 0,
59  data_format, data_type, face.data());
60  }
61 
62  // parametres de filtrage
63  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
64  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
65  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
66  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
67  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
68 
69  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
70 
71  // filtrage "correct" sur les bords du cube...
72  glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
73  //~ glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
74 
75  printf(" cubemap faces %dx%d\n", w, h);
76 
77  return texture;
78 }
79 
80 
81 // utilitaire. creation d'une grille / repere.
82 Mesh make_grid( const int n= 10 )
83 {
84  Mesh grid= Mesh(GL_LINES);
85 
86  // grille
87  grid.color(White());
88  for(int x= 0; x < n; x++)
89  {
90  float px= float(x) - float(n)/2 + .5f;
91  grid.vertex(Point(px, 0, - float(n)/2 + .5f));
92  grid.vertex(Point(px, 0, float(n)/2 - .5f));
93  }
94 
95  for(int z= 0; z < n; z++)
96  {
97  float pz= float(z) - float(n)/2 + .5f;
98  grid.vertex(Point(- float(n)/2 + .5f, 0, pz));
99  grid.vertex(Point(float(n)/2 - .5f, 0, pz));
100  }
101 
102  // axes XYZ
103  grid.color(Red());
104  grid.vertex(Point(0, .1, 0));
105  grid.vertex(Point(1, .1, 0));
106 
107  grid.color(Green());
108  grid.vertex(Point(0, .1, 0));
109  grid.vertex(Point(0, 1, 0));
110 
111  grid.color(Blue());
112  grid.vertex(Point(0, .1, 0));
113  grid.vertex(Point(0, .1, 1));
114 
115  return grid;
116 }
117 
118 
119 class TP : public AppCamera
120 {
121 public:
122  // constructeur : donner les dimensions de l'image, et eventuellement la version d'openGL.
123  TP( ) : AppCamera(1024, 640) {}
124 
125  void init_dynamic_cubemap( const int w, const int h )
126  {
127  // 6 faces couleur
128  glGenTextures(1, &m_texture_cubemap);
129  glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
130  for(int i= 0; i < 6; i++)
131  {
132  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
133  GL_RGBA, w, h, 0,
134  GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
135  }
136 
137  // parametres de filtrage
138  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
139  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
140  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
141  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
142  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
143  //+ mipmaps
144  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
145 
146  // 6 faces profondeur
147  glGenTextures(1, &m_depth_cubemap);
148  glBindTexture(GL_TEXTURE_CUBE_MAP, m_depth_cubemap);
149  for(int i= 0; i < 6; i++)
150  {
151  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
152  GL_DEPTH_COMPONENT, w, h, 0,
153  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
154  }
155 
156  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
157 
158  // framebuffer, attache les 6 faces couleur + profondeur
159  glGenFramebuffers(1, &m_framebuffer);
160  glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
161  glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cubemap, 0);
162  glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depth_cubemap, 0);
163 
164  glBindFramebuffer(GL_FRAMEBUFFER, 0);
165  }
166 
167  // creation des objets de l'application
168  int init( )
169  {
170  m_object= read_mesh("data/bigguy.obj");
171  m_cube= read_mesh("data/cube.obj");
172  m_ground= make_grid(20);
173 
174  m_program_render= read_program("tutos/render_cubemap.glsl");
175  program_print_errors(m_program_render);
176  m_program_draw= read_program("tutos/draw_cubemap.glsl");
177  program_print_errors(m_program_draw);
178  m_program= read_program("tutos/cubemap.glsl");
179  program_print_errors(m_program);
180 
181  // init camera
182  Point pmin, pmax;
183  m_object.bounds(pmin, pmax);
184  camera().lookat(pmin*2, pmax*2);
185 
186  // cubemap dynamique / framebuffer
187  init_dynamic_cubemap(1024, 1024);
188 
189  // etat openGL par defaut
190  glGenVertexArrays(1, &m_vao); // un vao sans attributs, pour dessiner la cubemap
191 
192  glClearColor(0.2f, 0.2f, 0.2f, 1.f); // couleur par defaut de la fenetre
193 
194  glClearDepth(1.f); // profondeur par defaut
195  glDepthFunc(GL_LEQUAL); // !! ztest, conserver l'intersection la plus proche de la camera !!
196  glEnable(GL_DEPTH_TEST); // activer le ztest
197  glLineWidth(1.5);
198 
199  return 0; // ras, pas d'erreur
200  }
201 
202 
203  struct Object
204  {
205  Transform model;
206  Color color;
207  };
208 
209  void scene( std::vector<Object>& objects )
210  {
211  objects.resize(100);
212 
213  // place quelques cubes dans la scene
214  float offset= global_time() / 200;
215  for(int i= 0; i < 100; i++)
216  {
217  float x= (i % 10 - 4.5) * 4;
218  float z= (i / 10 - 4.5) * 4;
219  float y= std::cos(x * z + offset);
220 
221  objects[i].color= Color(White() * std::abs(y));
222  objects[i].model= Translation(x, y, z) * RotationY(y*180);
223  }
224  }
225 
226  // dessiner une nouvelle image
227  int render( )
228  {
229  Transform view= camera().view();
230  Transform projection= camera().projection();
231  Transform viewport= camera().viewport();
232  Transform mvp= projection * view;
233 
234  // "animer" les cubes du "decor"...
235  std::vector<Object> objects;
236  scene(objects);
237 
238  // partie 1 : dessiner le decor dans la cubemap dynamique
239  {
240  // ... dans le framebuffer
241  glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
242  glViewport(0, 0, 1024, 1024); // dimension des faces de la cubemap
243 
244  // efface les 6 faces couleur + profondeur attachees au framebuffer
245  float black[4]= { 0.6, 0.6, 0.6, 1 };
246  glClearBufferfv(GL_COLOR, 0, black);
247 
248  float one= 1;
249  glClearBufferfv(GL_DEPTH, 0, &one);
250 
251  // prepare les 6 matrices view, une par face de la cubemap
252  // !! attention a la direction 'up' de lookat... rappel : orientation des textures des cubemaps !!
253  Transform faces[6];
254  faces[0]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(1, 0, 0), /* up */ Vector(0, -1, 0)); // +X
255  faces[1]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(-1, 0, 0), /* up */ Vector(0, -1, 0)); // -X
256 
257  faces[2]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 1, 0), /* up */ Vector(0, 0, 1)); // +Y
258  faces[3]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, -1, 0), /* up */ Vector(0, 0, -1)); // -Y
259 
260  faces[4]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, 1), /* up */ Vector(0, -1, 0)); // +Z
261  faces[5]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, -1), /* up */ Vector(0, -1, 0)); // -Z
262 
263  // dessine chaque objet du decor
264  GLuint vao= m_cube.create_buffers( /* texcoord */ false, /* normal */ true, /* color */ false, /* material */ false);
265  glBindVertexArray(vao);
266 
267  glUseProgram(m_program_render);
268  int location_mvp= glGetUniformLocation(m_program_render, "mvpMatrix");
269  int location_model= glGetUniformLocation(m_program_render, "modelMatrix");
270 
271  for(int i= 0; i < int(objects.size()); i++)
272  {
273  Transform model= objects[i].model;
274  Transform projection= Perspective(45, 1, 0.01, 100);
275 
276  // recalcule les 6 transformations, model est different pour chaque objet
277  Transform mvp[6];
278  for(int i= 0; i < 6; i++)
279  mvp[i]= projection * faces[i] * model;
280 
281  // go !!
282  glUniformMatrix4fv(location_mvp, 6, GL_TRUE, mvp[0].data());
283  glUniformMatrix4fv(location_model, 1, GL_TRUE, model.data());
284  glDrawArraysInstanced(GL_TRIANGLES, 0, m_object.vertex_count(), 6);
285  }
286 
287  // mise a jour des mipmaps des faces de la cubemap
288  glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
289  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
290  }
291 
292  // partie 2 : dessiner avec la cubemap dynamique...
293  {
294  // ... dans le framebuffer de la fenetre de l'application
295  glBindFramebuffer(GL_FRAMEBUFFER, 0);
296  glViewport(0, 0, window_width(), window_height());
297  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
298 
299  Transform viewInv= Inverse(view);
300  Point camera_position= viewInv(Point(0, 0, 0)); // coordonnees de la camera, dans le repere camera... c'est l'origine
301 
302  // affiche l'objet principal, utilise la cubemap pour calculer les reflets
303  Transform model= Identity();
304 
305  glUseProgram(m_program);
306  program_uniform(m_program, "mvpMatrix", mvp * model);
307  program_uniform(m_program, "modelMatrix", model);
308  program_uniform(m_program, "camera_position", camera_position);
309 
310  glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
311  program_uniform(m_program, "texture0", int(0));
312 
313  // dessine l'objet, les attributs position et normale sont necessaires a l'execution du shader.
314  m_object.draw(m_program, /* position */ true, /* texcoord */ false, /* normal */ true, /* color */ false, /* material */ false );
315 
316  // et le reste
317  draw(m_ground, Identity(), view, projection);
318  for(int i= 0; i < int(objects.size()); i++)
319  draw(m_cube, objects[i].model, view, projection);
320 
321  // etape 2 : affiche la cube map
322  // inverse de la transformation repere monde vers repere image
323  Transform inv= Inverse(viewport * projection * view);
324 
325  glUseProgram(m_program_draw);
326  glBindVertexArray(m_vao);
327  program_uniform(m_program_draw, "invMatrix", inv);
328  program_uniform(m_program_draw, "camera_position", camera_position);
329 
330  glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
331  program_uniform(m_program_draw, "texture0", int(0));
332 
333  glDrawArrays(GL_TRIANGLES, 0, 3);
334  }
335 
336  // nettoyage
337  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
338  glUseProgram(0);
339  glBindVertexArray(0);
340 
341  if(key_state('r'))
342  {
343  clear_key_state('r');
344 
345  reload_program(m_program_render, "tutos/render_cubemap.glsl");
346  program_print_errors(m_program_render);
347  reload_program(m_program_draw, "tutos/draw_cubemap.glsl");
348  program_print_errors(m_program_draw);
349  reload_program(m_program, "tutos/cubemap.glsl");
350  program_print_errors(m_program);
351  }
352 
353  if(key_state('s'))
354  {
355  clear_key_state('s');
356  static int calls= 0;
357  screenshot("cubemap_brdf", ++calls);
358  printf("screenshot %d\n", calls);
359  }
360 
361  return 1;
362  }
363 
364  // destruction des objets de l'application
365  int quit( )
366  {
367  m_object.release();
368  m_cube.release();
369  m_ground.release();
370 
371  release_program(m_program_render);
372  release_program(m_program_draw);
373  release_program(m_program);
374 
375  glDeleteVertexArrays(1, &m_vao);
376 
377  glDeleteTextures(1, &m_texture_cubemap);
378  glDeleteTextures(1, &m_depth_cubemap);
379  glDeleteFramebuffers(1, &m_framebuffer);
380  return 0;
381  }
382 
383 protected:
384  Mesh m_object;
385  Mesh m_cube;
386  Mesh m_ground;
387 
388  GLuint m_program_render;
389  GLuint m_program_draw;
390  GLuint m_program;
391  GLuint m_vao;
392  GLuint m_texture_cubemap;
393  GLuint m_depth_cubemap;
394  GLuint m_framebuffer;
395 };
396 
397 
398 int main( int argc, char **argv )
399 {
400  TP tp;
401  tp.run();
402 
403  return 0;
404 }
classe application.
Definition: app_camera.h:19
const Orbiter & camera() const
renvoie l'orbiter gere par l'application.
Definition: app_camera.h:37
int run()
execution de l'application.
Definition: app.cpp:36
representation d'un objet / maillage.
Definition: mesh.h:112
unsigned int vertex(const vec3 &p)
insere un sommet de position p, et ses attributs (s'ils sont definis par color(), texcoord(),...
Definition: mesh.cpp:111
GLuint create_buffers(const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index)
construit les buffers et le vertex array object necessaires pour dessiner l'objet avec openGL....
Definition: mesh.cpp:581
void bounds(Point &pmin, Point &pmax) const
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:503
void draw(const GLuint program, const bool use_position, const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index)
dessine l'objet avec un shader program.
Definition: mesh.cpp:770
int vertex_count() const
renvoie le nombre de sommets.
Definition: mesh.h:291
void release()
detruit les objets openGL.
Definition: mesh.cpp:64
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
Definition: mesh.cpp:80
void lookat(const Point &center, const float size)
observe le point center a une distance size.
Definition: orbiter.cpp:7
Transform viewport() const
renvoie la transformation viewport actuelle. doit etre initialise par projection(width,...
Definition: orbiter.cpp:83
Transform projection(const int width, const int height, const float fov)
fixe la projection reglee pour une image d'aspect width / height, et une demi ouverture de fov degres...
Definition: orbiter.cpp:47
Transform view() const
renvoie la transformation vue.
Definition: orbiter.cpp:40
Definition: alpha.cpp:59
int render()
a deriver pour afficher les objets. renvoie 1 pour continuer, 0 pour fermer l'application.
int quit()
a deriver pour detruire les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int init()
a deriver pour creer les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:29
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition: window.cpp:48
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
Definition: window.cpp:42
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition: window.cpp:25
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition: window.cpp:128
ImageData read_image_data(const char *filename)
charge les donnees d'un fichier png. renvoie une image initialisee par defaut en cas d'echec.
Definition: image_io.cpp:216
Color Red()
utilitaire. renvoie une couleur rouge.
Definition: color.cpp:57
Color Blue()
utilitaire. renvoie une couleur bleue.
Definition: color.cpp:67
Image flipY(const Image &image)
retourne l'image
Definition: image_io.cpp:295
Image flipX(const Image &image)
retourne l'image
Definition: image_io.cpp:312
Color Green()
utilitaire. renvoie une couleur verte.
Definition: color.cpp:62
Image copy(const Image &image, const int xmin, const int ymin, const int width, const int height)
renvoie un bloc de l'image
Definition: image_io.cpp:328
Color White()
utilitaire. renvoie une couleur blanche.
Definition: color.cpp:52
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Definition: mat.cpp:197
Transform Identity()
construit la transformation identite.
Definition: mat.cpp:187
Transform RotationY(const float a)
renvoie la matrice representation une rotation de a degree autour de l'axe Y.
Definition: mat.cpp:242
Transform Perspective(const float fov, const float aspect, const float znear, const float zfar)
renvoie la matrice representant une transformation projection perspective.
Definition: mat.cpp:329
Transform Translation(const Vector &v)
renvoie la matrice representant une translation par un vecteur.
Definition: mat.cpp:216
Transform Lookat(const Point &from, const Point &to, const Vector &up)
renvoie la matrice representant le placement et l'orientation d'une camera pour observer le point to.
Definition: mat.cpp:369
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
Definition: wavefront.cpp:14
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
Definition: texture.cpp:188
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:204
void program_uniform(const GLuint program, const char *uniform, const std::vector< unsigned > &v)
affecte un tableau de valeurs a un uniform du shader program.
Definition: uniforms.cpp:94
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition: program.cpp:432
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:211
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
stockage temporaire des donnees d'une image.
Definition: image_io.h:38
representation d'un point 3d.
Definition: vec.h:21
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:21
const float * data() const
renvoie l'adresse de la premiere valeur de la matrice.
Definition: mat.h:75
representation d'un vecteur 3d.
Definition: vec.h:59
GLuint read_cubemap(const int unit, const char *filename, const GLenum texel_type=GL_RGBA)
charge une image, decoupe les 6 faces et renvoie une texture cubemap.