gKit2 light
Loading...
Searching...
No Matches
tuto_cubemap.cpp File Reference

reflets miroirs cubemap / envmap. More...

#include <memory>
#include <random>
#include <chrono>
#include "wavefront.h"
#include "texture.h"
#include "orbiter.h"
#include "program.h"
#include "uniforms.h"
#include "draw.h"
#include "app_camera.h"

Go to the source code of this file.

Classes

struct  World
struct  splitsum
class  TP

Functions

Mesh make_grid (const int n=10)
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.
GLuint make_cubemap (const unsigned unit, const std::vector< Image > &faces, GLenum texel_type=GL_RGBA)
std::vector< Imageread_envmap (const char *filename)
vec3 envmap_texel (const Vector &d)
vec3 envmap_direction (const int face, const float s, const float t)
float frsplit (const Vector &v, const float ns)
splitsum splitsum_cubemap (const int unit, const char *filename, const GLenum texel_type=GL_RGBA)
int main (int argc, char **argv)

Detailed Description

reflets miroirs cubemap / envmap.

Definition in file tuto_cubemap.cpp.


Class Documentation

◆ splitsum

struct splitsum

Definition at line 368 of file tuto_cubemap.cpp.

Class Members
GLuint diffuse_texture
GLuint glossy_texture

Function Documentation

◆ make_grid()

Mesh make_grid ( const int n = 10)

Definition at line 20 of file tuto_cubemap.cpp.

21{
22 Mesh grid= Mesh(GL_LINES);
23
24 // grille
25 grid.color(White());
26 float w= float(n-1) / 2;
27 for(int x= 0; x < n; x++)
28 {
29 grid.vertex(x -w, 0, -w);
30 grid.vertex(x -w, 0, w);
31 }
32 for(int z= 0; z < n; z++)
33 {
34 grid.vertex(-w, 0, z -w);
35 grid.vertex( w, 0, z -w);
36 }
37
38 // axes XYZ
39 grid.color(Red());
40 grid.vertex(Point(0, .1, 0));
41 grid.vertex(Point(1, .1, 0));
42
43 grid.color(Green());
44 grid.vertex(Point(0, .1, 0));
45 grid.vertex(Point(0, 1, 0));
46
47 grid.color(Blue());
48 grid.vertex(Point(0, .1, 0));
49 grid.vertex(Point(0, .1, 1));
50
51 glLineWidth(2);
52
53 return grid;
54}
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
Color Red()
utilitaire. renvoie une couleur rouge.
Definition color.cpp:28
Color Blue()
utilitaire. renvoie une couleur bleue.
Definition color.cpp:38
Color Green()
utilitaire. renvoie une couleur verte.
Definition color.cpp:33
Color White()
utilitaire. renvoie une couleur blanche.
Definition color.cpp:23
representation d'un point 3d.
Definition vec.h:21

◆ read_cubemap()

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.

Definition at line 57 of file tuto_cubemap.cpp.

58{
59 ImageData image= read_image_data(filename);
60 if(image.pixels.empty())
61 return 0;
62
63 // les 6 faces sur une colonne
64 //~ int w= image.width;
65 //~ int h= image.height / 6;
66 // les 6 faces sur une croix
67 int w= image.width / 4;
68 int h= image.height / 3;
69 assert(w == h);
70
71 GLenum data_format;
72 GLenum data_type= GL_UNSIGNED_BYTE;
73 if(image.channels == 3)
74 data_format= GL_RGB;
75 else // par defaut
76 data_format= GL_RGBA;
77
78 // creer la texture
79 GLuint texture= 0;
80 glGenTextures(1, &texture);
81 glActiveTexture(GL_TEXTURE0 + unit);
82 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
83
84 // creer les 6 faces
85 // chaque face de la cubemap est un rectangle [image.width/4 x image.height/3] dans l'image originale
86 struct { int x, y; } faces[]= {
87 {0, 1}, // X+
88 {2, 1}, // X-
89 {1, 2}, // Y+
90 {1, 0}, // Y-
91 {1, 1}, // Z+
92 {3, 1}, // Z-
93 };
94 //~ struct { int x, y; } faces[]= {
95 //~ {0, 4}, // Z+
96 //~ {0, 5}, // Z-
97 //~ {0, 3}, // Y-
98 //~ {0, 2}, // Y+
99 //~ {0, 0}, // X+
100 //~ {0, 1}, // X-
101 //~ };
102
103 // face de test / rouge
104 ImageData red(w, h, image.channels);
105 for(unsigned y= 0; y < red.height; y++)
106 for(unsigned x= 0; x < red.width; x++)
107 {
108 unsigned char *pixel= red.pixels.data() + red.offset(x, y);
109 pixel[0]= 255;
110 pixel[1]= 0;
111 pixel[2]= 0;
112 if(red.channels > 3)
113 pixel[3]= 255;
114 }
115
116 for(int i= 0; i < 6; i++)
117 {
118 ImageData face= flipX(flipY(copy(image, faces[i].x*w, faces[i].y*h, w, h)));
119
120 //~ if(i == 5) // remplace par la face test...
121 //~ face= red;
122
123 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
124 texel_type, w, h, 0,
125 data_format, data_type, face.data());
126 }
127
128 // parametres de filtrage
129 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
130 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
131 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
132 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
133 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
134
135 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
136
137 // filtrage "correct" sur les bords du cube...
138 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
139 //~ glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
140
141 printf(" cubemap faces %dx%d\n", w, h);
142
143 return texture;
144}
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
Image flipY(const Image &image)
retourne l'image
Definition image_io.cpp:113
Image flipX(const Image &image)
retourne l'image
Definition image_io.cpp:130
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:335
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:146
stockage temporaire des donnees d'une image.
Definition image_io.h:55

◆ make_cubemap()

GLuint make_cubemap ( const unsigned unit,
const std::vector< Image > & faces,
GLenum texel_type = GL_RGBA )

Definition at line 147 of file tuto_cubemap.cpp.

148{
149 if(faces.empty())
150 return 0;
151
152 for(unsigned i= 1; i < faces.size(); i++)
153 if( faces[i].width() != faces[0].width()
154 || faces[i].height() != faces[0].height() )
155 return 0;
156
157 // creer la texture
158 GLuint texture= 0;
159 glGenTextures(1, &texture);
160 glActiveTexture(GL_TEXTURE0 + unit);
161 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
162
163 Image red( faces[0].width(), faces[0].height(), Red() );
164
165 // cree les 6 faces
166 for(unsigned i= 0; i < 6; i++)
167 {
168 //~ if(i == 5) // remplace par la face test...
169 //~ face= red;
170
171 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
172 texel_type, faces[i].width(), faces[i].height(), 0,
173 GL_RGBA, GL_FLOAT, faces[i].data());
174 }
175
176 // parametres de filtrage
177 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
178 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
181 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
182
183 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
184
185 // filtrage "correct" sur les bords du cube...
186 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
187 //~ glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
188
189 printf(" cubemap faces %dx%d\n", faces[0].width(), faces[0].height());
190 return texture;
191}
representation d'une image.
Definition image.h:21

◆ read_envmap()

std::vector< Image > read_envmap ( const char * filename)

Definition at line 193 of file tuto_cubemap.cpp.

194{
195 Image image= linear( read_image( filename ) );
196 if(image.size() == 0)
197 return {};
198
199 int w= image.width() / 4;
200 int h= image.height() / 3;
201 assert(w == h);
202
203 // creer les 6 faces
204 // chaque face de la cubemap est un rectangle [image.width/4 x image.height/3] dans l'image originale
205 struct { int x, y; } cells[]= {
206 {0, 1}, // X+
207 {2, 1}, // X-
208 {1, 2}, // Y+
209 {1, 0}, // Y-
210 {1, 1}, // Z+
211 {3, 1}, // Z-
212 };
213
214 std::vector<Image> faces;
215 for(int i= 0; i < 6; i++)
216 faces.emplace_back( flipX(flipY(copy(image, cells[i].x*w, cells[i].y*h, w, h))) );
217
218 return faces;
219}
Image read_image(const char *filename, const bool flipY)
Definition image_io.cpp:191

◆ envmap_texel()

vec3 envmap_texel ( const Vector & d)

Definition at line 223 of file tuto_cubemap.cpp.

224{
225 int face= -1;
226 float sm, tm;
227
228 const vec3 m= { std::abs(d.x), std::abs(d.y), std::abs(d.z) };
229 if(m.x > m.y && m.x > m.z)
230 {
231 // X
232 if(d.x > 0)
233 {
234 face= 0;
235 sm= -d.z / m.x;
236 tm= -d.y / m.x;
237 }
238 else
239 {
240 face= 1;
241 sm= d.z / m.x;
242 tm= -d.y / m.x;
243 }
244 }
245 else if(m.y > m.z)
246 {
247 // Y
248 if(d.y > 0)
249 {
250 face= 2;
251 sm= d.x / m.y;
252 tm= d.z / m.y;
253 }
254 else
255 {
256 face= 3;
257 sm= d.x / m.y;
258 tm= -d.z / m.y;
259 }
260 }
261 else
262 {
263 // Z
264 if(d.z > 0)
265 {
266 face= 4;
267 sm= d.x / m.z;
268 tm= -d.y / m.z;
269 }
270 else
271 {
272 face= 5;
273 sm= -d.x / m.z;
274 tm= -d.y / m.z;
275 }
276 }
277
278 assert(face != -1);
279 float s= (sm +1) / 2;
280 float t= (tm +1) / 2;
281 return { face, s, t };
282}
vecteur generique, utilitaire.
Definition vec.h:169

◆ envmap_direction()

vec3 envmap_direction ( const int face,
const float s,
const float t )

Definition at line 284 of file tuto_cubemap.cpp.

285{
286 // retrouve le point sur le cube [-1 .. 1]
287 float sm= 2 * s -1;
288 float tm= 2 * t -1;
289 if(face == 0)
290 {
291 // X+
292 // sm= -d.z / m.x;
293 // tm= -d.y / m.x;
294 return { 1, -tm, -sm };
295 }
296 else if(face == 1)
297 {
298 // X-
299 // sm= d.z / m.x;
300 // tm= -d.y / m.x;
301 return { -1, -tm, sm };
302 }
303 else if(face == 2)
304 {
305 // Y+
306 // sm= d.x / m.y;
307 // tm= d.z / m.y;
308 return { sm, 1, tm };
309 }
310 else if(face == 3)
311 {
312 // Y-
313 // sm= d.x / m.y;
314 // tm= -d.z / m.y;
315 return { sm, -1, -tm };
316 }
317 else if(face == 4)
318 {
319 // Z+
320 // sm= d.x / m.z;
321 // tm= -d.y / m.z;
322 return { sm, -tm, 1 };
323 }
324 else // if(face == 5)
325 {
326 // Z-
327 // sm= -d.x / m.z;
328 // tm= -d.y / m.z;
329 return { -sm, -tm, -1 };
330 }
331}

◆ frsplit()

float frsplit ( const Vector & v,
const float ns )

Definition at line 357 of file tuto_cubemap.cpp.

358{
359 // n= Z
360 // o= Z
361 assert(v.z >= 0);
362
363 Vector h= normalize( Vector(0, 0, 1) + v );
364 return (8 + ns) / float(8*M_PI) * std::pow( std::max(float(0), h.z), ns );
365}
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition vec.cpp:167
representation d'un vecteur 3d.
Definition vec.h:67

◆ splitsum_cubemap()

splitsum splitsum_cubemap ( const int unit,
const char * filename,
const GLenum texel_type = GL_RGBA )

Definition at line 374 of file tuto_cubemap.cpp.

375{
376 std::vector<Image> faces= read_envmap(filename);
377 if(faces.size() == 0)
378 return {};
379
380 const unsigned size= 16;
381 const unsigned samples= 4096;
382 std::vector<Image> diffuse;
383 for(unsigned i= 0; i < 6; i++)
384 diffuse.emplace_back( size, size, Black() );
385
386 unsigned size0= std::max( faces[0].width(), faces[0].height() );
387 unsigned levels= miplevels( faces[0].width(), faces[0].height() );
388 std::vector< std::vector<Image> > glossy(6);
389 for(unsigned i= 0; i < 6; i++)
390 {
391 for(unsigned k= 0; k < levels; k++)
392 {
393 unsigned ksize= std::max(unsigned(1), size0 >> k);
394 glossy[i].emplace_back( ksize, ksize, Black() );
395 }
396 }
397 printf("\n");
398
399 std::chrono::high_resolution_clock::time_point start= std::chrono::high_resolution_clock::now();
400
401 for(unsigned face= 0; face < diffuse.size(); face++)
402 {
403 #pragma omp parallel for schedule(dynamic, 1)
404 for(unsigned y= 0; y < size; y++)
405 {
406 std::random_device hwseed;
407 std::default_random_engine rng( hwseed() );
408 std::uniform_real_distribution<float> uniform;
409
410 for(unsigned x= 0; x < size; x++)
411 {
412 Vector n= envmap_direction( face, float(x) / float(size), float(y) / float(size) );
413 World world( n );
414
415 // diffuse
416 Color color;
417 for(unsigned i= 0; i < samples; i++)
418 {
419 float cos_theta= std::sqrt( uniform( rng ) );
420 float sin_theta= std::sqrt(1 - cos_theta * cos_theta);
421 float phi= uniform( rng ) * float(2 * M_PI);
422 float pdf= cos_theta / float(M_PI);
423
424 Vector v= world( { std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta} );
425
426 vec3 fuv= envmap_texel(v);
427 color= color + faces[fuv.x].texture(fuv.y, fuv.z) / float(M_PI) * cos_theta / pdf;
428 }
429
430 diffuse[face](x, y)= Color(color / float(samples), 1);
431 }
432 }
433 }
434
435 std::chrono::high_resolution_clock::time_point stop= std::chrono::high_resolution_clock::now();
436 printf("splitsum %dms\n", int( std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() ));
437
438 // glossy
439 for(unsigned face= 0; face < glossy.size(); face++)
440 {
441 unsigned ksamples= 256;
442 unsigned ksize= 256;
443 //~ unsigned ksize= std::max( glossy[face][0].width(), glossy[face][0].height() );
444 glossy[face][0]= Image(ksize, ksize);
445
446 #pragma omp parallel for schedule(dynamic, 1)
447 for(unsigned y= 0; y < ksize; y++)
448 {
449 std::random_device hwseed;
450 std::default_random_engine rng( hwseed() );
451 std::uniform_real_distribution<float> uniform;
452
453 for(unsigned x= 0; x < ksize; x++)
454 {
455 Vector n= envmap_direction( face, float(x) / float(ksize), float(y) / float(ksize) );
456 World world( n );
457
458 float ns= 100;
459
460 Color color;
461 for(unsigned i= 0; i < ksamples; i++)
462 {
463 // repere local, n= 0 0 1 et o= 0 0 1
464 float cos_theta_h= std::min( float(1), std::pow( uniform( rng ), float(1) / float(ns+1) ) );
465 float sin_theta_h= std::sqrt( 1 - cos_theta_h * cos_theta_h );
466 float phi_h= uniform( rng ) * float(2 * M_PI);
467
468 Vector h= { std::cos(phi_h) * sin_theta_h, std::sin(phi_h) * sin_theta_h, cos_theta_h };
469 Vector v= 2*h.z * h - Vector(0, 0, 1); // reflect(o, h)
470 float pdf_h= float(ns +1) / float(2 * M_PI) * std::pow(cos_theta_h, ns);
471 float pdf= float(1) / float(4 * h.z) * pdf_h;
472
473 float cos_theta= v.z;
474 if(cos_theta > 0)
475 {
476 vec3 fuv= envmap_texel( world(v) );
477 color= color + faces[fuv.x].texture(fuv.y, fuv.z) * frsplit(v, ns) * cos_theta / pdf;
478 }
479 }
480
481 glossy[face][0](x, y)= Color(color / float(samples), 1);
482
483 if(face == 0 && y == 0)
484 printf("%u %f\n", x, color.max() / float(samples));
485 }
486 }
487 }
488
489 std::chrono::high_resolution_clock::time_point stop2= std::chrono::high_resolution_clock::now();
490 printf("splitsum %dms\n", int( std::chrono::duration_cast<std::chrono::milliseconds>(stop2 - stop).count() ));
491
492 std::vector<Image> tmp_glossy;
493 for(unsigned i= 0; i < glossy.size(); i++)
494 tmp_glossy.emplace_back( glossy[i][0] );
495
496 Image band(tmp_glossy[0].width(), tmp_glossy[0].width()*6);
497 for(unsigned i= 0; i < 6; i++)
498 blit(band, 0, i * tmp_glossy[0].width(), tmp_glossy[i]);
499 //~ Image band(diffuse[0].width(), diffuse[0].width()*6);
500 //~ for(unsigned i= 0; i < 6; i++)
501 //~ blit(band, 0, i * diffuse[0].width(), diffuse[i]);
502
503 write_image(band, "env.png");
504
505 return { make_cubemap(0, diffuse), make_cubemap(0, tmp_glossy) };
506}
Color Black()
utilitaire. renvoie une couleur noire.
Definition color.cpp:18
Image & blit(Image &image, const unsigned xmin, const unsigned ymin, const Image &pixels)
remplace un bout d'image par une autre. copie l'image pixels dans image [xmin, xmin+pixels....
Definition image_io.cpp:162
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
Definition image_io.cpp:245
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
Definition image_io.cpp:537
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14

◆ main()

int main ( int argc,
char ** argv )

Definition at line 657 of file tuto_cubemap.cpp.

658{
659 // il ne reste plus qu'a creer un objet application et la lancer
660 TP tp;
661 tp.run();
662
663 return 0;
664}
int run()
execution de l'application.
Definition app.cpp:36
Definition alpha.cpp:58