gKit2 light
tuto5GL_dynamic_cubemap.cpp
Go to the documentation of this file.
1 
3 
4 #include <stdio.h>
5 
6 #include "window.h"
7 #include "vec.h"
8 #include "mat.h"
9 
10 #include "program.h"
11 #include "uniforms.h"
12 
13 #include "mesh.h"
14 #include "wavefront.h"
15 
16 #include "orbiter.h"
17 #include "image_io.h"
18 
19 
20 GLuint program;
21 GLuint program_cubemap;
22 GLuint program_render_cubemap;
23 
24 GLuint texture_cubemap;
25 GLuint depth_cubemap;
26 GLuint framebuffer;
27 
28 GLuint vao;
29 GLuint vao_null;
30 GLuint vertex_buffer;
31 GLuint normal_buffer;
32 int vertex_count;
33 
34 Orbiter camera;
35 
36 int init( )
37 {
38  // etape 1 : shaders
39  // . dessiner le reflet de la cubemap sur un objet
40  program= read_program("tutos/cubemap.glsl");
41  program_print_errors(program);
42 
43  // . dessiner la cubemap a l'infini
44  program_cubemap= read_program("tutos/cubemap.glsl");
45  program_print_errors(program_cubemap);
46 
47  // . dessiner dans une cube map
48  program_render_cubemap= read_program("tutos/render_cubemap.glsl");
49  program_print_errors(program_render_cubemap);
50 
51  // etape 2 : charger un mesh, (avec des normales), vao + vertex buffer
52  Mesh mesh= read_mesh("data/bigguy.obj");
53  //~ Mesh mesh= read_mesh("data/cube.obj");
54  if(mesh.vertex_count() == 0)
55  return -1; // gros probleme, pas de sommets...
56 
57  vertex_count= mesh.vertex_count();
58 
59  Point pmin, pmax;
60  mesh.bounds(pmin, pmax);
61  camera.lookat(pmin, pmax);
62 
63  // vertex format : position + normal,
64  glGenVertexArrays(1, &vao);
65  glBindVertexArray(vao);
66 
67  // vertex buffer
68  glGenBuffers(1, &vertex_buffer);
69  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
70  glBufferData(GL_ARRAY_BUFFER, mesh.vertex_buffer_size(), mesh.vertex_buffer(), GL_STATIC_DRAW);
71 
72  // configurer l'attribut position, cf declaration dans le vertex shader : in vec3 position;
73  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
74  glEnableVertexAttribArray(0);
75 
76  // normal buffer
77  if(!mesh.has_normal())
78  {
79  printf("[oops] pas de normales...\n");
80  return -1;
81  }
82 
83  glGenBuffers(1, &normal_buffer);
84  glBindBuffer(GL_ARRAY_BUFFER, normal_buffer);
85  glBufferData(GL_ARRAY_BUFFER, mesh.normal_buffer_size(), mesh.normal_buffer(), GL_STATIC_DRAW);
86 
87  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
88  glEnableVertexAttribArray(1);
89 
90  // nettoyage
91  mesh.release();
92  glBindVertexArray(0);
93  glBindBuffer(GL_ARRAY_BUFFER, 0);
94 
95  // etape 3 : textures + framebuffer
96  {
97  int w= 1024;
98  int h= 1024;
99 
100  // 6 faces couleur
101  glGenTextures(1, &texture_cubemap);
102  glBindTexture(GL_TEXTURE_CUBE_MAP, texture_cubemap);
103  for(int i= 0; i < 6; i++)
104  {
105  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
106  GL_RGBA, w, h, 0,
107  GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
108  }
109  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
110 
111  // 6 faces profondeur
112  glGenTextures(1, &depth_cubemap);
113  glBindTexture(GL_TEXTURE_CUBE_MAP, depth_cubemap);
114  for(int i= 0; i < 6; i++)
115  {
116  glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
117  GL_DEPTH_COMPONENT, w, h, 0,
118  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
119  }
120 
121  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
122  }
123 
124  // framebuffer, attache les 6 faces couleur + profondeur
125  glGenFramebuffers(1, &framebuffer);
126  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
127  glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_cubemap, 0);
128  glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_cubemap, 0);
129 
130  glBindFramebuffer(GL_FRAMEBUFFER, 0);
131 
132 
133  // filtrage "correct" sur les bords du cube...
134  glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
135  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
136 
137  // etape 4 : vao pour dessiner la cubemap a l'infini
138  glGenVertexArrays(1, &vao_null);
139  glBindVertexArray(vao_null);
140  // pas de buffer, c'est le vertex shader qui genere directement les positions des sommets
141 
142  glUseProgram(0);
143  glBindVertexArray(0);
144 
145  // etat par defaut
146  glClearColor(0.2f, 0.2f, 0.2f, 1);
147  glClearDepthf(1);
148 
149  glDepthFunc(GL_LEQUAL); // !! attention !! le support de la cube map est dessine exactement sur le plan far
150  // et le test "classique" GL_LESS est toujours faux, la cubemap ne sera pas dessinee.
151 
152  glEnable(GL_DEPTH_TEST);
153 
154  glFrontFace(GL_CCW);
155  glCullFace(GL_BACK);
156  //~ glEnable(GL_CULL_FACE);
157  glDisable(GL_CULL_FACE);
158  return 0;
159 }
160 
161 int quit( )
162 {
163  release_program(program);
164  release_program(program_cubemap);
165  release_program(program_render_cubemap);
166  glDeleteVertexArrays(1, &vao);
167  glDeleteVertexArrays(1, &vao_null);
168  glDeleteBuffers(1, &vertex_buffer);
169  glDeleteBuffers(1, &normal_buffer);
170  glDeleteTextures(1, &texture_cubemap);
171  glDeleteTextures(1, &depth_cubemap);
172  glDeleteFramebuffers(1, &framebuffer);
173  return 0;
174 }
175 
176 int draw( )
177 {
178  // partie 1 : dessiner dans la cubemap dynamique
179  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
180  glViewport(0, 0, 1024, 1024);
181 
182  // efface les 6 faces couleur + profondeur attachees au framebuffer
183  //~ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
184  float black[4]= { 0, 0, 0, 0 };
185  glClearBufferfv(GL_COLOR, 0, black);
186 
187  float one= 1;
188  glClearBufferfv(GL_DEPTH, 0, &one);
189 
190  {
191  // prepare les 6 matrices view, une par face de la cubemap
192  // !! attention a la direction 'up' de lookat... rappel : orientation des textures des cubemaps...
193  Transform faces[6];
194  faces[0]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(1, 0, 0), /* up */ Vector(0, -1, 0)); // +X
195  faces[1]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(-1, 0, 0), /* up */ Vector(0, -1, 0)); // -X
196 
197  faces[2]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 1, 0), /* up */ Vector(0, 0, 1)); // +Y
198  faces[3]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, -1, 0), /* up */ Vector(0, 0, -1)); // -Y
199 
200  faces[4]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, 1), /* up */ Vector(0, -1, 0)); // +Z
201  faces[5]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, -1), /* up */ Vector(0, -1, 0)); // -Z
202 
203  Transform model= Identity();
204  Transform projection= Perspective(45, 1, 0.01, 100);
205 
206  // dessine 6 fois la scene
207  glBindVertexArray(vao);
208  glUseProgram(program_render_cubemap);
209  glUniformMatrix4fv(glGetUniformLocation(program_render_cubemap, "projectionMatrix"), 1, GL_TRUE, projection.buffer());
210  glUniformMatrix4fv(glGetUniformLocation(program_render_cubemap, "modelMatrix"), 1, GL_TRUE, model.buffer());
211  glUniformMatrix4fv(glGetUniformLocation(program_render_cubemap, "viewMatrix"), 6, GL_TRUE, faces[0].buffer());
212 
213  // mais avec un seul draw... qui dessine chaque triangle 6 fois, une fois par face de la cubemap, avec les 6 transformations correspondantes
214  glDrawArraysInstanced(GL_TRIANGLES, 0, vertex_count, 6);
215  }
216 
217  // mise a jour des mipmaps des faces de la cubemap
218  glBindFramebuffer(GL_FRAMEBUFFER, 0);
219  glBindTexture(GL_TEXTURE_CUBE_MAP, texture_cubemap);
220  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
221 
222  // partie 2 : dessiner avec la cubemap dynamique
223  glBindFramebuffer(GL_FRAMEBUFFER, 0);
224  glViewport(0, 0, window_width(), window_height());
225 
226  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
227 
228  // recupere les mouvements de la souris, utilise directement SDL2
229  int mx, my;
230  unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
231 
232  // deplace la camera
233  if(mb & SDL_BUTTON(1)) // le bouton gauche est enfonce
234  // tourne autour de l'objet
235  camera.rotation(mx, my);
236 
237  else if(mb & SDL_BUTTON(3)) // le bouton droit est enfonce
238  // approche / eloigne l'objet
239  camera.move(mx);
240 
241  else if(mb & SDL_BUTTON(2)) // le bouton du milieu est enfonce
242  // deplace le point de rotation
243  camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height());
244 
245  /* config pipeline :
246  vertex array object
247  program
248  uniforms
249  texture
250  */
251  // recupere le point de vue et la projection de la camera
252  Transform model= Identity();
253  Transform view= camera.view();
254  Transform projection= camera.projection(window_width(), window_height(), 45);
255 
256  // compose les matrices pour passer du repere local de l'objet au repere projectif
257  Transform mvp= projection * view * model;
258 
259  // dessine l'objet avec le reflet de la cubemap
260  {
261  glBindVertexArray(vao);
262  glUseProgram(program);
263 
264  program_uniform(program, "mvpMatrix", mvp);
265  program_uniform(program, "modelMatrix", model);
266  program_uniform(program, "camera_position", Inverse(view)(Point(0, 0, 0)));
267 
268  // texture
269  glBindTexture(GL_TEXTURE_CUBE_MAP, texture_cubemap);
270 
271  // sampler2D declare par le fragment shader
272  GLint location= glGetUniformLocation(program, "texture0");
273  glUniform1i(location, 0);
274  // ou program_uniform(program, "texture0", texture);
275 
276  glDrawArrays(GL_TRIANGLES, 0, vertex_count);
277  }
278 
279  // dessine la cubemap sur les autres pixels...
280  {
281  glBindVertexArray(vao_null);
282  glUseProgram(program_cubemap);
283 
284  // texture
285  glBindTexture(GL_TEXTURE_CUBE_MAP, texture_cubemap);
286 
287  // sampler2D declare par le fragment shader
288  GLint location= glGetUniformLocation(program_cubemap, "texture0");
289  glUniform1i(location, 0);
290  // ou program_uniform(program, "texture0", texture);
291 
292  program_uniform(program_cubemap, "vpInvMatrix", Inverse(projection * view));
293  program_uniform(program_cubemap, "camera_position", Inverse(view)(Point(0, 0, 0)));
294 
295  // dessine un triangle qui couvre tous les pixels de l'image
296  glDrawArrays(GL_TRIANGLES, 0, 3);
297  }
298 
299  // nettoyage
300  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
301  glUseProgram(0);
302  glBindVertexArray(0);
303 
304  return 1;
305 }
306 
307 
308 int main( int argc, char **argv )
309 {
310  // etape 1 : creer la fenetre
311  Window window= create_window(1024, 640);
312  if(window == NULL)
313  return 1; // erreur lors de la creation de la fenetre ou de l'init de sdl2
314 
315  // etape 2 : creer un contexte opengl pour pouvoir dessiner
316  Context context= create_context(window);
317  if(context == NULL)
318  return 1; // erreur lors de la creation du contexte opengl
319 
320  // verifier que l'extension est disponible
321  if(GLEW_ARB_shader_viewport_layer_array)
322  printf("ARB_shader_viewport_layer_array supported\n");
323 
324  else
325  {
326  printf("[error] ARB_shader_viewport_layer_array NOT supported...\n");
327  return 1;
328  }
329 
330  // etape 3 : creation des objets
331  if(init() < 0)
332  {
333  printf("[error] init failed.\n");
334  return 1;
335  }
336 
337  // etape 4 : affichage de l'application, tant que la fenetre n'est pas fermee. ou que draw() ne renvoie pas 0
338  run(window, draw);
339 
340  // etape 5 : nettoyage
341  quit();
342  release_context(context);
343  release_window(window);
344  return 0;
345 }
representation d'un objet / maillage.
Definition: mesh.h:112
const float * vertex_buffer() const
renvoie l'adresse de la position du premier sommet. permet de construire les vertex buffers openGL....
Definition: mesh.h:296
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
std::size_t vertex_buffer_size() const
renvoie la longueur (en octets) du vertex buffer.
Definition: mesh.h:298
int vertex_count() const
renvoie le nombre de sommets.
Definition: mesh.h:291
void release()
detruit les objets openGL.
Definition: mesh.cpp:64
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:303
const float * normal_buffer() const
renvoie l'adresse de la normale du premier sommet. par convention, la normale est un vec3,...
Definition: mesh.h:301
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
Definition: orbiter.h:17
void lookat(const Point &center, const float size)
observe le point center a une distance size.
Definition: orbiter.cpp:7
void move(const float z)
rapproche / eloigne la camera du centre.
Definition: orbiter.cpp:33
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
void translation(const float x, const float y)
deplace le centre / le point observe.
Definition: orbiter.cpp:27
void rotation(const float x, const float y)
change le point de vue / la direction d'observation.
Definition: orbiter.cpp:21
Transform view() const
renvoie la transformation vue.
Definition: orbiter.cpp:40
Context create_context(Window window)
cree et configure un contexte opengl
Definition: window.cpp:356
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:29
void release_window(Window window)
destruction de la fenetre.
Definition: window.cpp:325
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
Window create_window(const int w, const int h, const int major, const int minor, const int samples)
creation d'une fenetre pour l'application.
Definition: window.cpp:259
void release_context(Context context)
detruit le contexte openGL.
Definition: window.cpp:422
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition: window.cpp:25
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 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 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
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
int init(std::vector< const char * > &options)
Definition: shader_kit.cpp:96
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
representation d'un vecteur 3d.
Definition: vec.h:59
int run(Window window, int(*draw)())
boucle de gestion des evenements de l'application.
Definition: window.cpp:147