Example #1
0
int main() {

  assert(sizeof(BHVNode)==32);  // in case we mess it up one day


  auto startTime = std::chrono::high_resolution_clock::now();

  int nthreads = 1;
  /* int nthreads = 2; */
  /* int nthreads = 4; */

  /* int width = 400; */
  /* int height = 200; */

  /* int width = 1600; */
  /* int height = 800; */

  /* int width = 1920/8; */
  /* int height = 1080/8; */

  /* int width = 1920/4; */
  /* int height = 1080/4; */
  /* int height = 50; */

  /* int width = 1920/2; */
  /* int height = 1080/2; */

  /* int width = 1920; */
  int height = 1080;

  /* int height = 1920; */
  /* int width = 1080; */

  /* int width = 1200; */
  /* int height = 600; */

  /* int width = 600; */
  /* int height = 300; */

  int width = height;

  /* int nsamples = 1; */
  /* int nsamples = 4; */
  int nsamples = 20;
  /* int nsamples = 50; */
  /* int nsamples = 100; */
  /* int nsamples = 200; */
  /* int nsamples = 500; */
  /* int nsamples = 1000; */
  /* int nsamples = 2000; */
  /* int nsamples = 5000; */
  /* int nsamples = 10000; */

  /* int max_bounces = 1; */
  /* int max_bounces = 2; */
  int max_bounces = 5;
  /* int max_bounces = 10; */
  /* int max_bounces = 100; */

  // above on the left
  /* Camera camera( */
  /*     width, */
  /*     height, */
  /*     Vector(-2, 2, 1), */
  /*     Vector(0, 0, -1), */
  /*     Vector(0, 1, 0), */
  /*     90 */
  /* ); */

  // in front
  /* Camera camera( */
  /*     width, */
  /*     height, */
  /*     Vector(-1.8, 1., -2), */
  /*     Vector(0, 0, -1), */
  /*     Vector(0, 1, 0), */
  /*     90 */
  /* ); */

  // inside the box, looking in front
  Camera camera(
      width,
      height,
      /* Vector(0, 0, -3.f),  // cow */
      /* Vector(-0.5f, 1.f, -6.f),  // bunny */
      Vector(0, 0, -3.8f),  // cornell box
      /* Vector(0, 0, -1.1f), */
      /* Vector(-0.5f, 1.f, 0),  // bunny pos */
      Vector(0.f, 0.f, 0.f),
      Vector(0, 1, 0),
      40
      );

#if 0

  // dragon
  Camera camera(
      width,
      height,
      Vector(0.f, 0.1f, 0.22f),  // profile
      /* Vector(-0.072f, 0.14f, -0.03f),  // quarter zoomed in */
      /* Vector(-0.2f, 0.2f, -0.2f),  // quarter */
      Vector(0.f, 0.12f, 0),
      Vector(0, 1, 0),
      40
      );

#elif 0

  /* // buddha */
  Camera camera(
      width,
      height,
      Vector(0.f, 0.2f, 0.35f),  // quarter
      Vector(0.f, 0.15f, 0),
      Vector(0, 1, 0),
      40
      );

#endif

  ObjectGroup *world = new ObjectGroup();

  // 2 metal + 1 lamb in the middle
  /* world->add( new Sphere(Vector(0, -100.5, -1), 100, new Lambertian(Vector(0.8, 0.8, 0))) ); */
  /* world->add( new Sphere(Vector(0, 0, -1), 0.5, new Lambertian(Vector(0.8, 0.3, 0.3))) ); */
  /* world->add( new Sphere(Vector(1, 0, -1), 0.5, new Metal(Vector(0.8, 0.6, 0.2), 0)) ); */
  /* world->add( new Sphere(Vector(-1, 0, -1), 0.5, new Metal(Vector(0.8, 0.8, 0.8), 0.1)) ); */

  // bubble-lamb-metal
  //
  /* world->add( new Plane(Vector(0, -0.5f, 0), Vector(0.f, 1.f, 0.f), new Lambertian(new ConstantTexture(0.8, 0.8, 0))) ); */
  /* world->add( new Sphere(Vector(0, -100.5, -1), 100, new Lambertian(new ConstantTexture(0.8, 0.8, 0))) ); */

  /* world->add( new Sphere(Vector(0, 0, -1), */
  /*                        0.5, */
  /*                        new Lambertian( */
  /*                          new CheckerTexture( */
  /*                            new ConstantTexture(0.f, 0.f, 0.f), */
  /*                            new ConstantTexture(1.f, 1.f, 1.f))))); */

  /* world->add( new Sphere(Vector(0, 0, -1), */
  /*       0.5, */
  /*       new Lambertian( */
  /*         new ImageTexture("earth.bmp")))); */

  /* world->add( new Triangle(Vector(0.2f, 0.5f, -1), Vector(0, 1.5f, -1), Vector(0, 0.5f, -2), new Metal(new ConstantTexture(0.8f, 0.8f, 0.8f), 0.0f)) ); */

  /* world->add( new Sphere(Vector(-0.5, 0, -2.2), 0.5, new Metal(new ConstantTexture(0.9, 0.9, 0.9), 0)) ); */
  /* world->add( new Sphere(Vector(-1, 0, -1), 0.5, new Dielectric(1.5f)) ); */
  /* world->add( new Sphere(Vector(-1, 0, -1), 0.45, new Dielectric(1.f, 1.5f)) ); */
  /* world->add( new Sphere(Vector(-2, 0, -1), 0.5, new Light(new ConstantTexture(20.f, 20.f, 20.f))) ); */
  /* world->add( new Sphere(Vector(0, 2, -1.5), 0.5, new Light(new ConstantTexture(20.f, 20.f, 20.f))) ); */


  // cornell box
  //
  //   /B---C
  //  A---D/|
  //  | F-|-G
  //  E/--H/

  Vector A = Vector(-1, 1, -1);
  Vector B = Vector(-1, 1, 1);
  Vector C = Vector(1, 1, 1);
  Vector D = Vector(1, 1, -1);
  Vector E = Vector(-1, -1, -1);
  Vector F = Vector(-1, -1, 1);
  Vector G = Vector(1, -1, 1);
  Vector H = Vector(1, -1, -1);

  // back
  Material* backMat = new Lambertian(new ConstantTexture(1.f, 1.f, 1.f));
  world->add( new Triangle(F, B, G, backMat));
  world->add( new Triangle(C, G, B, backMat));

  // front - letting ray in from the camera
  // /!\ not part of the original cornell box
  /* Material* frontMat = new Lambertian(new ConstantTexture(1.f, 1.f, 1.f)); */
  /* world->add( new Triangle(E, H, A, frontMat)); */
  /* world->add( new Triangle(D, A, H, frontMat)); */

  // floor
  Material* floorkMat = new Lambertian(new ConstantTexture(1.f, 1.f, 1.f));
  world->add( new Triangle(E, F, G, floorkMat));
  world->add( new Triangle(G, H, E, floorkMat));

  // ceiling
  Material* ceilingMat = new Lambertian(new ConstantTexture(1.f, 1.f, 1.f));
  /* Material* ceilingMat = new Metal(new ConstantTexture(1.f, 1.f, 1.f), 0); */
  world->add( new Triangle(A, C, B, ceilingMat));
  world->add( new Triangle(C, A, D, ceilingMat));

  // left
  Material* leftMat = new Lambertian(new ConstantTexture(1.f, 0.f, 0.f));
  world->add( new Triangle(A, B, E, leftMat));
  world->add( new Triangle(B, F, E, leftMat));

  // right
  Material* rightMat = new Lambertian(new ConstantTexture(0.f, 1.f, 0.f));
  world->add( new Triangle(D, H, C, rightMat));
  world->add( new Triangle(C, H, G, rightMat));

  // light
  float lightIntensity = 10.f;
  float lightSize = 0.3f;

  Material* lightMat = new Light(new ConstantTexture(lightIntensity, lightIntensity, lightIntensity));
  Vector lA = Vector(-lightSize, 0.99f, -lightSize);
  Vector lB = Vector(-lightSize, 0.99f, lightSize);
  Vector lC = Vector(lightSize, 0.99f, lightSize);
  Vector lD = Vector(lightSize, 0.99f, -lightSize);
  world->add( new Triangle(lA, lC, lB, lightMat));
  world->add( new Triangle(lC, lA, lD, lightMat));
  /* world->add( new Sphere(Vector(0, 0, 0), 0.2, new Light(new ConstantTexture(20.f, 20.f, 20.f))) ); */


  // stuff inside the box

  /* world->add( box(Vector(-0.7, -0.2, 0.2), 0.5, 0.5, 0.5, new Metal(new ConstantTexture(0.9, 0.9, 0.9), 0.01)) ); */
  /* for(int i=0 ; i<100 ; i++){ */
    world->extend( box(new Lambertian(new ConstantTexture(0.1, 0.2, 0.95)),
                    Vector(-0.6, -0.1, 0.1),
                    Vector(0.5, 0.8, 0.5),
                    Vector(0.f, -20.f, 0.f))->list );

    world->extend( box(new Lambertian(new ConstantTexture(1, 1, 1)),
          Vector(0., -0.5, -0.7),
          Vector(0.5, 0.5, 0.5),
          Vector(0.f, 15.f, 0.f))->list );
  /* } */


  // obj loading tests
  // http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/
  //
    auto checkpoint = std::chrono::high_resolution_clock::now();

    Material* objMat = new Lambertian(new ConstantTexture(0.1f, 0.2f, 0.8f));
  /* Material* objMat = new Metal(new ConstantTexture(0.6f, 0.6f, 0.2f), 0.1f); */
  /* Material* objMat = new Light(new ConstantTexture(0.1f, 0.1f, 0.8f)); */

  std::vector<Vector> vertices;
  std::vector<Vector> normals;
  /* std::vector<Vector> texturecoords; */
  std::vector<std::array<long double, 3>> faces;  // computed normals indexed by vertices
  std::vector<int> nfaces;  // number of faces by vertices - to average out the normal
  std::vector<std::array<int, 3>> faceLinks;  // for each face, link to vertice ids

  ObjectGroup *obj = new ObjectGroup();
  std::vector<SmoothedTriangle*> tosmooth;

  int ignoredObj = 0;

#if 1  // obj loading

  std::ifstream file("cow.obj");
  /* std::ifstream file("bunny.obj"); */
  std::string str;
  while (std::getline(file, str)) {

    bool gotnormals = false;

    // vertices
    if( str.find("v ") == 0){
      float a, b, c;
      sscanf(str.c_str(), "v %f %f %f", &a, &b, &c);
      vertices.push_back(Vector(a, b, c));

      faces.push_back( {{0.L, 0.L, 0.L}} );
      nfaces.push_back(0);

    // vertice normals
    } else if( str.find("vn ") == 0){
        float na, nb, nc;
        sscanf(str.c_str(), "vn %f %f %f", &na, &nb, &nc);
        normals.push_back(Vector(na, nb, nc));
        /* std::cout << Vector(na, nb, nc).length() << " na=" << na << " nb=" << nb << " nc=" << nc << std::endl; */


    // faces (ie triangles)
    } else if( str.find("f ") == 0){
      long a, b, c;
      long na, nb, nc;
      if(str.find("//") != std::string::npos){
        gotnormals = true;
        sscanf(str.c_str(), "f %ld//%ld %ld//%ld %ld//%ld", &a, &na, &b, &nb, &c, &nc);
      } else if(str.find("/") != std::string::npos) {
        gotnormals = true;
        sscanf(str.c_str(), "f %ld/%*s/%ld %ld/%*s/%ld %ld/%*s/%ld", &a, &na, &b, &nb, &c, &nc);
      } else {
        sscanf(str.c_str(), "f %ld %ld %ld", &a, &b, &c);
      }

      unsigned long A, B, C;
      A = a > 0 ? a-1 : vertices.size()+a;
      B = b > 0 ? b-1 : vertices.size()+b;
      C = c > 0 ? c-1 : vertices.size()+c;

      if(A > vertices.size()
          || B > vertices.size()
          || C > vertices.size()){
        std::cerr << "NOPE vertices " << A  << " " << B << " "  << C << " "  << vertices.size() << std::endl;
        std::cerr << str << std::endl;
        exit(1);
      }

      if(gotnormals) {
        unsigned long NA, NB, NC;
        NA = na > 0 ? na-1 : normals.size()+na;
        NB = nb > 0 ? nb-1 : normals.size()+nb;
        NC = nc > 0 ? nc-1 : normals.size()+nc;

        if(NA > normals.size()
            || NB > normals.size()
            || NC > normals.size()){
          std::cerr << "NOPE normals " << NA  << " " << NB << " "  << NC << " "  << normals.size() << std::endl;
          std::cerr << str << std::endl;
          exit(1);
        }

        obj->add( new SmoothedTriangle(  vertices[A],
                                         vertices[B],
                                         vertices[C],
                                         normals[NA],
                                         normals[NB],
                                         normals[NC],
                                         objMat) );
      } else {
        SmoothedTriangle* triangle = new SmoothedTriangle(
             vertices[A],
             vertices[B],
             vertices[C],
             objMat);
        tosmooth.push_back(triangle);

        long axis[] = {a, b, c};
        for(long axes : axis){
          for(int i=0 ; i<3 ; i++)
            faces[axes][i] += (long double) triangle->norm[i];

          nfaces[axes] += 1;
        }

        std::array<int, 3> link { {(int)a, (int)b, (int)c} };
        faceLinks.push_back(link);
      }

    }
  }

  long face_count = faces.size();

#else  // ply loading  -- pretty dumb one
  // assume the only elements are vertices & faces
  // + faces are composed of exactly 3 vertices
  // + ascii format

  std::ifstream file("ply/dragon_recon/dragon_vrip.ply");
  /* std::ifstream file("ply/dragon_recon/dragon_vrip_res2.ply"); */

  /* std::ifstream file("ply/happy_recon/happy_vrip.ply"); */
  /* std::ifstream file("ply/happy_recon/happy_vrip_res4.ply"); */

  std::string str;

  long face_count = -1;
  long vertex_count = -1;

  // read header
  while(std::getline(file, str)){
    if(str == "ply")
      continue;  // ignore

    else if(str.find("format") == 0){
      assert(str == "format ascii 1.0");  // only format supported atm

    } else if(str.find("element") == 0){
      if(str.find("element vertex") == 0) {
        assert(face_count == -1);
        sscanf(str.c_str(), "element vertex %ld", &vertex_count);

      } else if(str.find("element face") == 0) {
        assert(vertex_count != -1);
        sscanf(str.c_str(), "element face %ld", &face_count);

      } else {
        std::cout << "unknow element type in ply: " << str << std::endl;
        exit(1);
      }


    } else if(str.find("property") == 0){
      continue;  // ignore atm - assume vertices are x,y,z floats ; faces as 3 ints

    } else if(str.find("comment") == 0) {
      continue;  // ignore

    } else if(str == "end_header"){
      break;

    } else {
      std::cout << "UNKNOWN LINE IN PLY: " << str << std::endl;
    }
  }

  std::cout << "PLY header: vertices = " << vertex_count << " ; faces = " << face_count << std::endl;

  std::cout << "PLY header loaded in: " << (std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - checkpoint)).count() << " ms" << std::endl;
  checkpoint = std::chrono::high_resolution_clock::now();

  vertices.reserve(vertex_count);
  faces.reserve(vertex_count);
  nfaces.reserve(vertex_count);
  /* faceLinks.reserve(face_count); */
  /* tosmooth.reserve(face_count); */

  std::cout << "PLY struct reservation in: " << (std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - checkpoint)).count() << " ms" << std::endl;
  checkpoint = std::chrono::high_resolution_clock::now();

  for(int ivertex=0 ; ivertex < vertex_count ; ivertex++){
    std::getline(file, str);
    float a, b, c;
    sscanf(str.c_str(), "%f %f %f", &a, &b, &c);
    vertices.push_back(Vector(a,b,c));

    faces.push_back( {{0.L, 0.L, 0.L}} );
    nfaces.push_back(0);
  }

  std::cout << "PLY vertices loaded in: " << (std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - checkpoint)).count() << " ms" << std::endl;
  checkpoint = std::chrono::high_resolution_clock::now();

  for(int iface=0 ; iface < face_count ; iface++){
    std::getline(file, str);
    long a, b, c;
    sscanf(str.c_str(), "3 %ld %ld %ld", &a, &b, &c);

    /* std::cout << "str \"" << str << "\"  => a: " << a << " b: " << b << " c: " << c << std::endl; */

    assert(a >= 0 && b >= 0 && c >= 0
        && a < vertex_count
        && b < vertex_count
        && c < vertex_count);

    SmoothedTriangle* triangle = new SmoothedTriangle(
      vertices[a],
      vertices[b],
      vertices[c],
      objMat);

    // check for NaN in file
    bool toignore = false;
    for(int iaxis=0 ; iaxis<3 ; iaxis++)
      if(isnan(triangle->norm[iaxis]) || triangle->norm[iaxis] < -1.1f) {
        toignore = true;
        /* std::cout << "problem in ply file - incorrect normals: " << triangle->norm << " vertices: a=" << vertices[a] << " b=" << vertices[b] << " c= " << vertices[c] << "  indices: (" << a << ", " << b << ", " << c << ")" << std::endl; */
      }

    if(!toignore) {
      long axis[] = {a, b, c};
      for(long axes : axis){
        for(int i=0 ; i<3 ; i++)
          faces[axes][i] += (long double) triangle->norm[i];

        nfaces[axes] += 1;
      }

      tosmooth.push_back(triangle);

      std::array<int, 3> link { {(int)a, (int)b, (int)c} };
      faceLinks.push_back(link);

    } else {
      ignoredObj++;
    }
  }

  std::cout << "PLY faces loaded in: " << (std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - checkpoint)).count() << " ms" << std::endl;
  checkpoint = std::chrono::high_resolution_clock::now();

#endif

  if(ignoredObj > 0)
    std::cout << "\n=============\n!!!! " << ignoredObj << " FACES HAVE BEEN IGNORED ON THE 1st PASS!!!\n==========\n" << std::endl;

  int secondPassIgnoredObj = 0;

  file.close();

  for(unsigned int iface=0 ; iface<face_count-ignoredObj ; iface++){
    SmoothedTriangle* triangle = tosmooth[iface];
    std::array<int, 3> link = faceLinks[iface];

    for(int iaxes = 0 ; iaxes<3 ; iaxes++){
      triangle->na[iaxes] = float( faces[link[0]][iaxes] / nfaces[link[0]] );
      triangle->nb[iaxes] = float( faces[link[1]][iaxes] / nfaces[link[1]] );
      triangle->nc[iaxes] = float( faces[link[2]][iaxes] / nfaces[link[2]] );
    }

    /* std::cout << "link: " << link[0] << " " << link[1] << " " << link[2] << std::endl; */

    bool ignoreobj = false;  // if some problem occurs
    for(int iaxis=0 ; iaxis<3 ; iaxis++){
      /* bool toignorethis = true; */
      /* if(nfaces[link[iaxis]] == 0) */
      /*   std::cout << "problem in ply file: " << link[iaxis] << std::endl; */

      /* else if(isnan(triangle->na[iaxis]) || triangle->na[iaxis] < -1.1f) */
      /*   std::cout << "problem in ply file: " << faces[link[0]] << std::endl; */

      /* else if(isnan(triangle->nb[iaxis]) || triangle->nb[iaxis] < -1.1f) */
      /*   std::cout << "problem in ply file: " << faces[link[1]] << std::endl; */

      /* else if(isnan(triangle->nc[iaxis]) || triangle->nc[iaxis] < -1.1f) */
      /*   std::cout << "problem in ply file: " << faces[link[2]] << std::endl; */

      /* else */
      /*   toignorethis = false; */

      /* if(toignorethis) */
      /*   ignoreobj = true; */

      if( !(nfaces[link[iaxis]] != 0
          && !isnan(triangle->na[iaxis]) && triangle->na[iaxis] > -1.f
          && !isnan(triangle->nb[iaxis]) && triangle->nb[iaxis] > -1.f
          && !isnan(triangle->nc[iaxis]) && triangle->nc[iaxis] > -1.f))

        ignoreobj = true;
    }

    if(!ignoreobj)
      obj->add(triangle);
    else
      secondPassIgnoredObj++;
  }

  std::cout << "Triangle smoothing in: " << (std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - checkpoint)).count() << " ms" << std::endl;

  auto fileReadingTime = std::chrono::high_resolution_clock::now();
  std::chrono::duration<double, std::milli> totalFileReadingTime = fileReadingTime - startTime;
  std::cout << "File loaded in: " << totalFileReadingTime.count() << " ms\n" << std::endl;

  if(secondPassIgnoredObj > 0)
    std::cout << "\n=============\n!!!! " << secondPassIgnoredObj  << " FACES HAVE BEEN IGNORED ON 2nd PASS!!!\n==========\n" << std::endl;

  /* world = new ObjectGroup(); */
  world->extend(obj->list);


  // debug cube
  /* world = new ObjectGroup(); */
  /* world->extend( box(new Metal(new ConstantTexture(0.8, 0.8, 0.8), 0.f))->list ); */


  // convert world to a BHV
  auto bhvStartTime = std::chrono::high_resolution_clock::now();

  /* BHV* bhv_world = new BHV(&world->list[0], world->list.size()); */
  const BHV bhv_world(world->list);

  std::cout << "Triangle count: " << world->list.size() << std::endl;
  /* std::cout << "BHV depth: " << bhv_world.depth() << std::endl; */

  std::cout << "\nWorld center at: " << bhv_world.bounding_box()->getCenter().str() << std::endl;
  std::cout << "World bounding box: " << bhv_world.bounding_box()->str() << std::endl;

  /* std::cout << bhv_world->str() << std::endl; */
  /* std::cout << bhv_world->bounding_box()->str() << std::endl; */
  /* std::cout << bhv_world->left->bounding_box()->str() << std::endl; */
  /* std::cout << bhv_world->right->bounding_box()->str() << std::endl; */


  auto bhvTime = std::chrono::high_resolution_clock::now();
  std::chrono::duration<double, std::milli> totalBHVtime = bhvTime - bhvStartTime;
  std::cout << "\nBHV in: " << totalBHVtime.count() << " ms" << std::endl;
  startTime = std::chrono::high_resolution_clock::now();


  // start job threads
  std::thread *threads = new std::thread[nthreads];
  Vector*** out = new Vector**[nthreads];
  for(int ithread=0 ; ithread<nthreads ; ithread++) {
    out[ithread] = new Vector*[width];
    for(int i=0 ; i<width ; i++)
      out[ithread][i] = new Vector[height];

    threads[ithread] = std::thread(rt_pass, camera, bhv_world, width, height, (ithread*width)/nthreads, max_bounces, nsamples/nthreads, out[ithread]);
    /* threads[ithread] = std::thread(rt_pass, camera, bhv_world, width, height, 0, max_bounces, nsamples/nthreads, out[ithread]); */
  }


  long totalDirectRay = width*height*(nsamples-nsamples%nthreads);
  int perc = 0;
  long lastTotalRay = 0;
  int pauseCount = 0;  // keep track of the pause number: allow to display average rays for the last second - TODO rolling second
  const int pauseTime = 1; // in ms

  while(perc != 100) {

    perc = (nDirectRay*100)/totalDirectRay;

    std::this_thread::sleep_for(std::chrono::milliseconds(pauseTime));

    pauseCount++;
    if(pauseCount*pauseTime>=1000){
      pauseCount = 0;
      std::cout << "\r" << perc << " %" << "  -- " << (nTotalRay-lastTotalRay)/1000.f << "K ray per sec" << std::flush;
      lastTotalRay = nTotalRay;
    }

  }


  // join threads - just in case
  for(int ithread=0 ; ithread<nthreads ; ithread++)
    threads[ithread].join();

  auto endTime = std::chrono::high_resolution_clock::now();

  // average res & write the image
  std::ofstream image;
  image.open("image.ppm");
  /* image.open("image_"+std::to_string(nsamples)+".ppm"); */

  image << "P3\n" << width << " " << height << "\n255\n";

  // debug: bhv traversal count
  // compute maximum to display the right color panel
#if BHV_TRAVERSAL_COUNT
  int max_traversal = 0;
  long double average_traversal = 0.f;
  for(int j=height-1 ; j>=0; j--)
    for(int i=width-1 ; i>=0 ; i--)
      for(int ithread=0 ; ithread<nthreads ; ithread++){
        if(out[ithread][i][j].x > max_traversal)
           max_traversal = out[ithread][i][j].x;
        average_traversal += out[ithread][i][j].x;
      }

  std::cout << "\nmax traversal: " << max_traversal << std::endl;
  std::cout << "average direct traversal: " << (average_traversal/totalDirectRay) << std::endl;
#endif

  for(int j=height-1 ; j>=0; j--)
    for(int i=width-1 ; i>=0 ; i--) {
      Vector average = VECTOR_ZERO;
      for(int ithread=0 ; ithread<nthreads ; ithread++)
        average += out[ithread][i][j];
      average = average/nthreads;

#if BHV_TRAVERSAL_COUNT
      int *rgb = (average/max_traversal).toRGB(2);
#else
      int *rgb = average.tone_map().toRGB(2);
#endif
      // check for incoherent values
      for(int iaxis=0 ; iaxis<3 ; iaxis++)
        if(rgb[iaxis] < 0 || rgb[iaxis] > 255 || isnan(rgb[iaxis])){
          std::cout << "something's wrong: " << average << std::endl;
          for(int ithread=0 ; ithread<nthreads ; ithread++)
            std::cout << "on thread " << ithread << " => " << out[ithread][i][j] << std::endl;
          rgb[iaxis] = 0;  // =[
        }

      image << rgb[0] << " " << rgb[1] << " " << rgb[2] << "\n";
    }

  image.close();

  std::chrono::duration<double, std::milli> totalTime = endTime - startTime;
  std::cout << "\n\nTotal: " << totalTime.count() << " ms" << std::endl;
  std::cout << "\nTriangle intersections: " << nTriangleIntersection/1000000.f << "M" << std::endl;
  std::cout << "BHV intersection: " << nBoxIntersection/1000000.f << "M" << std::endl;

  std::cout << "\nTriangle intersection per ray: " << nTriangleIntersection/float(nTotalRay) << std::endl;
  std::cout << "BHV intersection per ray: " << nBoxIntersection/float(nTotalRay) << std::endl;

  std::cout << "\nAverage bounce: " << nTotalRay/float(nDirectRay) << std::endl;

  std::cout << "\nDirect rays: " << nDirectRay << std::endl;
  std::cout << "Total rays: " << nTotalRay << std::endl;
  std::cout << "\nRay per seconds: " << nTotalRay/totalTime.count() << " k" << std::endl;

  return 0;
}
Example #2
0
/**
 * Init the scene and OpenGL state
 *
 */
void MyScene::init()
{
    _objects[CUBE].load("./data/cube.off");
    _objects[PYRAMID].load("./data/pyramid.off");
    _objects[DISK].load("./data/disk.off");
    _objects[DISKHOLE].load("./data/diskhole.off");
    _objects[CYLINDER].load("./data/cylinder.off");
    _objects[CONE].load("./data/cone.off");
    _objects[SPHERE].load("./data/sphere.off");
    _objects[AIRCRAFT].load("./data/aircraft.off");
    _objects[VENUS].load("./data/venus.off");
    _objects[NEFERTITI].load("./data/nefertiti.off");

    Mesh* cone = new Mesh();
    cone->load("./data/cone.off");
    cone->addTransformation(glTranslatef,0.0,0.0,_radius);
    cone->addTransformation(glScalef,0.1, 0.1, 0.5);

    Mesh* cylinder = new Mesh();
    cylinder->load("./data/cylinder.off");
    cylinder->addTransformation(glScalef,0.01, 0.01, 1.0);

    ObjectGroup* zArrow = new ObjectGroup();
    zArrow->add(cone);
    zArrow->add(cylinder);
    //zArrow->addTransformation(glScalef, _radius/2, _radius/2, _radius/2);
    zArrow->addTransformation(glColor3f, 0, 0, 0.5);

    ObjectGroup* xArrow = zArrow->clone();
    xArrow->addTransformation(glRotatef, 90, 0, 1, 0);
    xArrow->addTransformation(glColor3f, 0.5, 0, 0);

    ObjectGroup* yArrow = zArrow->clone();
    yArrow->addTransformation(glRotatef, -90, 1, 0, 0);
    yArrow->addTransformation(glColor3f, 0, 0.5, 0);

    Mesh* centerSphere = new Mesh();
    centerSphere->load("./data/sphere.off");
    centerSphere->addTransformation(glScalef,0.05, 0.05, 0.05);
    centerSphere->addTransformation(glColor3f, 0.5, 0.5, 0.5);

    _allObjects = new ObjectGroup();
    _allObjects->add(centerSphere);
    _allObjects->add(xArrow);
    _allObjects->add(yArrow);
    _allObjects->add(zArrow);

    Mesh* sun = new Mesh();
    sun->load("./data/sphere.off");
    sun->addTransformation(glScalef, 0.3, 0.3, 0.3);
    sun->addTransformation(glColor3f, 0.9, 0.2, 0.0);
    _allObjects->add(sun);

    ObjectGroup* earthAndMoon = new ObjectGroup();
    _earthAndMoonRotator = new ParametrizedRotator(0,0,1);
    earthAndMoon->addTransformation(_earthAndMoonRotator);
    earthAndMoon->addTransformation(glTranslatef, 2, 0.0, 0.0);

    Mesh* earth = new Mesh();
    earth->load("./data/sphere.off");
    earth->addTransformation(glScalef, 0.1, 0.1, 0.1);
    earth->addTransformation(glColor3f, 0.0, 0.2, 0.9);
    earthAndMoon->add(earth);

    Mesh* moon = new Mesh();
    moon->load("./data/sphere.off");
    _moonRotator = new ParametrizedRotator(0,0,1);
    moon->addTransformation(_moonRotator);
    moon->addTransformation(glTranslatef, 0.5, 0.0, 0.0);
    moon->addTransformation(glScalef, 0.04, 0.04, 0.04);
    moon->addTransformation(glColor3f, 0.3, 0.3, 0.3);
    earthAndMoon->add(moon);

    _allObjects->add(earthAndMoon);

    setDayOfYear(0);

    // set antialiased lines
    //glEnable(GL_LINE_SMOOTH);	// FIXME current MESA driver messes up with antialiasing ...
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    glLineWidth(1.5);
}