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 }
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) );
414
415
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
439 for(unsigned face= 0; face < glossy.size(); face++)
440 {
441 unsigned ksamples= 256;
442 unsigned ksize= 256;
443
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) );
457
458 float ns= 100;
459
461 for(unsigned i= 0; i < ksamples; i++)
462 {
463
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 };
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
500
501
502
504
505 return { make_cubemap(0, diffuse), make_cubemap(0, tmp_glossy) };
506}
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....
bool write_image(const Image &image, const char *filename, const bool flipY)
enregistre une image au format .png
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
representation d'une couleur (rgba) transparente ou opaque.