20Mesh make_grid(
const int n= 10 )
26 float w= float(n-1) / 2;
27 for(
int x= 0; x < n; x++)
32 for(
int z= 0; z < n; z++)
57GLuint
read_cubemap(
const int unit,
const char *filename,
const GLenum texel_type = GL_RGBA )
60 if(image.pixels.empty())
67 int w= image.width / 4;
68 int h= image.height / 3;
72 GLenum data_type= GL_UNSIGNED_BYTE;
73 if(image.channels == 3)
80 glGenTextures(1, &texture);
81 glActiveTexture(GL_TEXTURE0 + unit);
82 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
86 struct {
int x, y; } faces[]= {
105 for(
unsigned y= 0; y < red.height; y++)
106 for(
unsigned x= 0; x < red.width; x++)
108 unsigned char *pixel= red.pixels.data() + red.offset(x, y);
116 for(
int i= 0; i < 6; i++)
123 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i, 0,
125 data_format, data_type, face.data());
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);
135 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
138 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
141 printf(
" cubemap faces %dx%d\n", w, h);
147GLuint make_cubemap(
const unsigned unit,
const std::vector<Image>& faces, GLenum texel_type= GL_RGBA )
152 for(
unsigned i= 1; i < faces.size(); i++)
153 if( faces[i].width() != faces[0].width()
154 || faces[i].height() != faces[0].height() )
159 glGenTextures(1, &texture);
160 glActiveTexture(GL_TEXTURE0 + unit);
161 glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
163 Image red( faces[0].width(), faces[0].height(),
Red() );
166 for(
unsigned i= 0; i < 6; i++)
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());
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);
183 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
186 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
189 printf(
" cubemap faces %dx%d\n", faces[0].width(), faces[0].height());
193std::vector<Image> read_envmap(
const char *filename )
196 if(image.size() == 0)
199 int w= image.width() / 4;
200 int h= image.height() / 3;
205 struct {
int x, y; } cells[]= {
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))) );
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)
279 float s= (sm +1) / 2;
280 float t= (tm +1) / 2;
281 return { face, s, t };
284vec3 envmap_direction(
const int face,
const float s,
const float t )
294 return { 1, -tm, -sm };
301 return { -1, -tm, sm };
308 return { sm, 1, tm };
315 return { sm, -1, -tm };
322 return { sm, -tm, 1 };
329 return { -sm, -tm, -1 };
335 World( ) : t(), b(), n() {}
337 World(
const Vector& _n ) : n(_n)
339 float s= std::copysign(
float(1), n.z);
340 float a= -1 / (s + n.z);
341 float d= n.x * n.y * a;
342 t=
Vector(1 + s * n.x * n.x * a, s * d, -s * n.x);
343 b=
Vector(d, s + n.y * n.y * a, -n.y);
347 Vector operator( ) (
const Vector& local )
const {
return local.x * t + local.y * b + local.z * n; }
357float frsplit(
const Vector& v,
const float ns )
364 return (8 + ns) / float(8*M_PI) * std::pow( std::max(
float(0), h.z), ns );
370 GLuint diffuse_texture;
371 GLuint glossy_texture;
374splitsum splitsum_cubemap(
const int unit,
const char *filename,
const GLenum texel_type = GL_RGBA )
376 std::vector<Image> faces= read_envmap(filename);
377 if(faces.size() == 0)
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() );
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++)
391 for(
unsigned k= 0; k < levels; k++)
393 unsigned ksize= std::max(
unsigned(1), size0 >> k);
394 glossy[i].emplace_back( ksize, ksize,
Black() );
399 std::chrono::high_resolution_clock::time_point start= std::chrono::high_resolution_clock::now();
401 for(
unsigned face= 0; face < diffuse.size(); face++)
403 #pragma omp parallel for schedule(dynamic, 1)
404 for(
unsigned y= 0; y < size; y++)
406 std::random_device hwseed;
407 std::default_random_engine rng( hwseed() );
408 std::uniform_real_distribution<float> uniform;
410 for(
unsigned x= 0; x < size; x++)
412 Vector n= envmap_direction( face,
float(x) /
float(size),
float(y) /
float(size) );
417 for(
unsigned i= 0; i < samples; i++)
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);
424 Vector v= world( { std::cos(phi) * sin_theta, std::sin(phi) * sin_theta, cos_theta} );
426 vec3 fuv= envmap_texel(v);
427 color= color + faces[fuv.x].texture(fuv.y, fuv.z) / float(M_PI) * cos_theta / pdf;
430 diffuse[face](x, y)=
Color(color /
float(samples), 1);
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() ));
439 for(
unsigned face= 0; face < glossy.size(); face++)
441 unsigned ksamples= 256;
444 glossy[face][0]=
Image(ksize, ksize);
446 #pragma omp parallel for schedule(dynamic, 1)
447 for(
unsigned y= 0; y < ksize; y++)
449 std::random_device hwseed;
450 std::default_random_engine rng( hwseed() );
451 std::uniform_real_distribution<float> uniform;
453 for(
unsigned x= 0; x < ksize; x++)
455 Vector n= envmap_direction( face,
float(x) /
float(ksize),
float(y) /
float(ksize) );
461 for(
unsigned i= 0; i < ksamples; i++)
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);
468 Vector h= { std::cos(phi_h) * sin_theta_h, std::sin(phi_h) * sin_theta_h, cos_theta_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;
473 float cos_theta= v.z;
476 vec3 fuv= envmap_texel( world(v) );
477 color= color + faces[fuv.x].texture(fuv.y, fuv.z) * frsplit(v, ns) * cos_theta / pdf;
481 glossy[face][0](x, y)=
Color(color /
float(samples), 1);
483 if(face == 0 && y == 0)
484 printf(
"%u %f\n", x, color.max() /
float(samples));
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() ));
492 std::vector<Image> tmp_glossy;
493 for(
unsigned i= 0; i < glossy.size(); i++)
494 tmp_glossy.emplace_back( glossy[i][0] );
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]);
505 return { make_cubemap(0, diffuse), make_cubemap(0, tmp_glossy) };
522 if(m_objet.vertex_count() == 0)
526 splitsum textures= splitsum_cubemap(0,
"canyon2.jpg");
528 m_texture= textures.glossy_texture;
538 m_program_draw=
read_program(
"gkit2_tutos/draw_cubemap.glsl");
545 m_objet.bounds(pmin, pmax);
549 glGenVertexArrays(1, &m_vao);
551 glEnable(GL_FRAMEBUFFER_SRGB);
552 glClearColor(0.1, 0.1, 0.1, 1);
555 glDepthFunc(GL_LEQUAL);
556 glEnable(GL_DEPTH_TEST);
567 glDeleteVertexArrays(1, &m_vao);
568 glDeleteTextures(1, &m_texture);
575 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
586 Transform mvp= projection * view * model;
589 Point camera_position= viewInv(
Point(0, 0, 0));
592 glUseProgram(m_program);
593 program_uniform(m_program,
"mvpMatrix", mvp);
594 program_uniform(m_program,
"modelMatrix", model);
595 program_uniform(m_program,
"camera_position", camera_position);
597 glActiveTexture(GL_TEXTURE0);
598 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
601 program_uniform(m_program,
"texture0", 0);
604 m_objet.draw(m_program);
610 glUseProgram(m_program_draw);
611 glBindVertexArray(m_vao);
612 program_uniform(m_program_draw,
"invMatrix", inv);
613 program_uniform(m_program_draw,
"camera_position", camera_position);
615 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
617 program_uniform(m_program_draw,
"texture0",
int(0));
619 glDrawArrays(GL_TRIANGLES, 0, 3);
622 glBindTexture(GL_TEXTURE_2D, 0);
623 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
625 glBindVertexArray(0);
631 reload_program(m_program_draw,
"gkit2_tutos/draw_cubemap.glsl");
633 reload_program(m_program,
"gkit2_tutos/cubemap.glsl");
642 printf(
"screenshot %d\n", calls);
651 GLuint m_program_draw;
657int main(
int argc,
char **argv )
const Orbiter & camera() const
renvoie l'orbiter gere par l'application.
AppCamera(const int width, const int height, const int major=3, const int minor=3)
constructeur, dimensions de la fenetre et version d'openGL.
int run()
execution de l'application.
representation d'une image.
representation d'un objet / maillage.
unsigned int vertex(const vec3 &p)
insere un sommet de position p, et ses attributs (s'ils sont definis par color(), texcoord(),...
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
void lookat(const Point ¢er, const float size)
observe le point center a une distance size.
Transform viewport() const
renvoie la transformation viewport actuelle. doit etre initialise par projection(width,...
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...
Transform view() const
renvoie la transformation vue.
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.
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
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().
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
Color Red()
utilitaire. renvoie une couleur rouge.
Color Blue()
utilitaire. renvoie une couleur bleue.
Color Black()
utilitaire. renvoie une couleur noire.
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....
Image flipY(const Image &image)
retourne l'image
Image flipX(const Image &image)
retourne l'image
Image read_image(const char *filename, const bool flipY)
Color Green()
utilitaire. renvoie une couleur verte.
Color White()
utilitaire. renvoie une couleur blanche.
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...
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
Image copy(const Image &image, const unsigned xmin, const unsigned ymin, const unsigned width, const unsigned height)
renvoie un bloc de l'image
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Transform Identity()
construit la transformation identite.
Transform RotationY(const float a)
renvoie la matrice representation une rotation de a degree autour de l'axe Y.
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
GLuint read_program(const char *filename, const char *definitions)
int program_print_errors(const GLuint program, const char *filename)
affiche les erreurs de compilation.
int release_program(const GLuint program)
detruit les shaders et le program.
representation d'une couleur (rgba) transparente ou opaque.
stockage temporaire des donnees d'une image.
representation d'un point 3d.
representation d'un vecteur 3d.
vecteur generique, utilitaire.
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.