gKit2 light
Loading...
Searching...
No Matches
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
18GLuint 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.
82Mesh make_grid( const int n= 10 )
83{
84 Mesh grid= Mesh(GL_LINES);
85
86 // grille
87 grid.color(White());
88 float w= float(n-1) / 2;
89 for(int x= 0; x < n; x++)
90 {
91 grid.vertex(x -w, 0, -w);
92 grid.vertex(x -w, 0, w);
93 }
94
95 for(int z= 0; z < n; z++)
96 {
97 grid.vertex(-w, 0, z -w);
98 grid.vertex( w, 0, z -w);
99 }
100
101 // axes XYZ
102 grid.color(Red());
103 grid.vertex(Point(0, .1, 0));
104 grid.vertex(Point(1, .1, 0));
105
106 grid.color(Green());
107 grid.vertex(Point(0, .1, 0));
108 grid.vertex(Point(0, 1, 0));
109
110 grid.color(Blue());
111 grid.vertex(Point(0, .1, 0));
112 grid.vertex(Point(0, .1, 1));
113
114 return grid;
115}
116
117
118class TP : public AppCamera
119{
120public:
121 // constructeur : donner les dimensions de l'image, et eventuellement la version d'openGL.
122 TP( ) : AppCamera(1024, 640) {}
123
124 void init_dynamic_cubemap( const int w, const int h )
125 {
126 // 6 faces couleur
127 glGenTextures(1, &m_texture_cubemap);
128 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
129 for(int i= 0; i < 6; i++)
130 {
131 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
132 GL_RGBA, w, h, 0,
133 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
134 }
135
136 // parametres de filtrage
137 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
138 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
140 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
141 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
142 //+ mipmaps
143 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
144
145 // 6 faces profondeur
146 glGenTextures(1, &m_depth_cubemap);
147 glBindTexture(GL_TEXTURE_CUBE_MAP, m_depth_cubemap);
148 for(int i= 0; i < 6; i++)
149 {
150 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
151 GL_DEPTH_COMPONENT, w, h, 0,
152 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
153 }
154
155 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
156
157 // framebuffer, attache les 6 faces couleur + profondeur
158 glGenFramebuffers(1, &m_framebuffer);
159 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
160 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_cubemap, 0);
161 glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depth_cubemap, 0);
162
163 glBindFramebuffer(GL_FRAMEBUFFER, 0);
164 }
165
166 // creation des objets de l'application
167 int init( )
168 {
169 m_object= read_mesh("data/bigguy.obj");
170 m_cube= read_mesh("data/cube.obj");
171 m_ground= make_grid(20);
172
173 m_program_render= read_program("gkit2_tutos/render_cubemap.glsl");
174 program_print_errors(m_program_render);
175 m_program_draw= read_program("gkit2_tutos/draw_cubemap.glsl");
176 program_print_errors(m_program_draw);
177 m_program= read_program("gkit2_tutos/cubemap.glsl");
178 program_print_errors(m_program);
179
180 // init camera
181 Point pmin, pmax;
182 m_object.bounds(pmin, pmax);
183 camera().lookat(pmin*2, pmax*2);
184
185 // cubemap dynamique / framebuffer
186 init_dynamic_cubemap(1024, 1024);
187
188 // etat openGL par defaut
189 glGenVertexArrays(1, &m_vao); // un vao sans attributs, pour dessiner la cubemap
190
191 glClearColor(0.2f, 0.2f, 0.2f, 1.f); // couleur par defaut de la fenetre
192
193 glClearDepth(1.f); // profondeur par defaut
194 glDepthFunc(GL_LEQUAL); // !! ztest, conserver l'intersection la plus proche de la camera !!
195 glEnable(GL_DEPTH_TEST); // activer le ztest
196 glLineWidth(1.5);
197
198 return 0; // ras, pas d'erreur
199 }
200
201
202 struct Object
203 {
204 Transform model;
205 Color color;
206 };
207
208 void scene( std::vector<Object>& objects )
209 {
210 objects.resize(100);
211
212 // place quelques cubes dans la scene
213 float offset= global_time() / 200;
214 for(int i= 0; i < 100; i++)
215 {
216 float x= (i % 10 - 4.5) * 4;
217 float z= (i / 10 - 4.5) * 4;
218 float y= std::cos(x * z + offset);
219
220 objects[i].color= Color(White() * std::abs(y));
221 objects[i].model= Translation(x, y, z) * RotationY(y*180);
222 }
223 }
224
225 // dessiner une nouvelle image
226 int render( )
227 {
228 Transform view= camera().view();
229 Transform projection= camera().projection();
230 Transform viewport= camera().viewport();
231 Transform mvp= projection * view;
232
233 // "animer" les cubes du "decor"...
234 std::vector<Object> objects;
235 scene(objects);
236
237 // partie 1 : dessiner le decor dans la cubemap dynamique
238 {
239 // ... dans le framebuffer
240 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
241 glViewport(0, 0, 1024, 1024); // dimension des faces de la cubemap
242
243 // efface les 6 faces couleur + profondeur attachees au framebuffer
244 float black[4]= { 0.6, 0.6, 0.6, 1 };
245 glClearBufferfv(GL_COLOR, 0, black);
246
247 float one= 1;
248 glClearBufferfv(GL_DEPTH, 0, &one);
249
250 // prepare les 6 matrices view, une par face de la cubemap
251 // !! attention a la direction 'up' de lookat... rappel : orientation des textures des cubemaps !!
252 Transform faces[6];
253 faces[0]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(1, 0, 0), /* up */ Vector(0, -1, 0)); // +X
254 faces[1]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(-1, 0, 0), /* up */ Vector(0, -1, 0)); // -X
255
256 faces[2]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 1, 0), /* up */ Vector(0, 0, 1)); // +Y
257 faces[3]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, -1, 0), /* up */ Vector(0, 0, -1)); // -Y
258
259 faces[4]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, 1), /* up */ Vector(0, -1, 0)); // +Z
260 faces[5]= Lookat(/* from */ Point(0, 0, 0), /* to */ Point(0, 0, -1), /* up */ Vector(0, -1, 0)); // -Z
261
262 // dessine chaque objet du decor
263 GLuint vao= m_cube.create_buffers( USE_POSITION | USE_NORMAL );
264 glBindVertexArray(vao);
265
266 glUseProgram(m_program_render);
267 int location_mvp= glGetUniformLocation(m_program_render, "mvpMatrix");
268 int location_model= glGetUniformLocation(m_program_render, "modelMatrix");
269
270 for(int i= 0; i < int(objects.size()); i++)
271 {
272 Transform model= objects[i].model;
273 Transform projection= Perspective(45, 1, 0.01, 100);
274
275 // recalcule les 6 transformations, model est different pour chaque objet
276 Transform mvp[6];
277 for(int i= 0; i < 6; i++)
278 mvp[i]= projection * faces[i] * model;
279
280 // go !!
281 glUniformMatrix4fv(location_mvp, 6, GL_TRUE, mvp[0].data());
282 glUniformMatrix4fv(location_model, 1, GL_TRUE, model.data());
283 glDrawArraysInstanced(GL_TRIANGLES, 0, m_object.vertex_count(), 6);
284 }
285
286 // mise a jour des mipmaps des faces de la cubemap
287 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
288 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
289 }
290
291 // partie 2 : dessiner avec la cubemap dynamique...
292 {
293 // ... dans le framebuffer de la fenetre de l'application
294 glBindFramebuffer(GL_FRAMEBUFFER, 0);
295 glViewport(0, 0, window_width(), window_height());
296 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
297
298 Transform viewInv= Inverse(view);
299 Point camera_position= viewInv(Point(0, 0, 0)); // coordonnees de la camera, dans le repere camera... c'est l'origine
300
301 // affiche l'objet principal, utilise la cubemap pour calculer les reflets
302 Transform model= Identity();
303
304 glUseProgram(m_program);
305 program_uniform(m_program, "mvpMatrix", mvp * model);
306 program_uniform(m_program, "modelMatrix", model);
307 program_uniform(m_program, "camera_position", camera_position);
308
309 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
310 program_uniform(m_program, "texture0", int(0));
311
312 // dessine l'objet, les attributs position et normale sont necessaires à l'execution du shader.
313 m_object.draw(m_program);
314
315 // et le reste
316 draw(m_ground, Identity(), view, projection);
317 for(int i= 0; i < int(objects.size()); i++)
318 draw(m_cube, objects[i].model, view, projection);
319
320 // etape 2 : affiche la cube map
321 // inverse de la transformation repere monde vers repere image
322 Transform inv= Inverse(viewport * projection * view);
323
324 glUseProgram(m_program_draw);
325 glBindVertexArray(m_vao);
326 program_uniform(m_program_draw, "invMatrix", inv);
327 program_uniform(m_program_draw, "camera_position", camera_position);
328
329 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_cubemap);
330 program_uniform(m_program_draw, "texture0", int(0));
331
332 glDrawArrays(GL_TRIANGLES, 0, 3);
333 }
334
335 // nettoyage
336 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
337 glUseProgram(0);
338 glBindVertexArray(0);
339
340 if(key_state('r'))
341 {
342 clear_key_state('r');
343
344 reload_program(m_program_render, "gkit2_tutos/render_cubemap.glsl");
345 program_print_errors(m_program_render);
346 reload_program(m_program_draw, "gkit2_tutos/draw_cubemap.glsl");
347 program_print_errors(m_program_draw);
348 reload_program(m_program, "gkit2_tutos/cubemap.glsl");
349 program_print_errors(m_program);
350 }
351
352 if(key_state('s'))
353 {
354 clear_key_state('s');
355 static int calls= 0;
356 screenshot("cubemap_brdf", ++calls);
357 printf("screenshot %d\n", calls);
358 }
359
360 return 1;
361 }
362
363 // destruction des objets de l'application
364 int quit( )
365 {
366 m_object.release();
367 m_cube.release();
368 m_ground.release();
369
370 release_program(m_program_render);
371 release_program(m_program_draw);
372 release_program(m_program);
373
374 glDeleteVertexArrays(1, &m_vao);
375
376 glDeleteTextures(1, &m_texture_cubemap);
377 glDeleteTextures(1, &m_depth_cubemap);
378 glDeleteFramebuffers(1, &m_framebuffer);
379 return 0;
380 }
381
382protected:
383 Mesh m_object;
384 Mesh m_cube;
385 Mesh m_ground;
386
387 GLuint m_program_render;
388 GLuint m_program_draw;
389 GLuint m_program;
390 GLuint m_vao;
391 GLuint m_texture_cubemap;
392 GLuint m_depth_cubemap;
393 GLuint m_framebuffer;
394};
395
396
397int main( int argc, char **argv )
398{
399 TP tp;
400 tp.run();
401
402 return 0;
403}
classe application.
Definition app_camera.h:19
const Orbiter & camera() const
renvoie l'orbiter gere par l'application.
Definition app_camera.h:37
AppCamera(const int width, const int height, const int major=3, const int minor=3, const int samples=0)
constructeur, dimensions de la fenetre et version d'openGL.
Definition app_camera.cpp:5
int run()
execution de l'application.
Definition app.cpp:36
representation d'un objet / maillage.
Definition mesh.h:121
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:97
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
Definition mesh.cpp:66
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:84
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:48
Transform view() const
renvoie la transformation vue.
Definition orbiter.cpp:41
Definition alpha.cpp:58
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:27
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition window.cpp:46
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:40
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition window.cpp:23
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition window.cpp:126
Color Red()
utilitaire. renvoie une couleur rouge.
Definition color.cpp:28
Color Blue()
utilitaire. renvoie une couleur bleue.
Definition color.cpp:38
Image flipY(const Image &image)
retourne l'image
Definition image_io.cpp:112
Image flipX(const Image &image)
retourne l'image
Definition image_io.cpp:129
Color Green()
utilitaire. renvoie une couleur verte.
Definition color.cpp:33
Color White()
utilitaire. renvoie une couleur blanche.
Definition color.cpp:23
ImageData read_image_data(const void *buffer, const unsigned size, const bool flipY)
charge les donnees d'un fichier png stocke en memoire. renvoie une image initialisee par defaut en ca...
Definition image_io.cpp:315
Image copy(const Image &image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height)
renvoie un bloc de l'image
Definition image_io.cpp:145
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
@ USE_POSITION
inclut l'attribut position dans les buffers.
Definition mesh.h:112
@ USE_NORMAL
inclut l'attribut normale dans les buffers.
Definition mesh.h:114
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
Definition texture.cpp:178
GLuint read_program(const char *filename, const char *definitions)
Definition program.cpp:218
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition program.cpp:446
int release_program(const GLuint program)
detruit les shaders et le program.
Definition program.cpp:225
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
stockage temporaire des donnees d'une image.
Definition image_io.h:53
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:67
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.