Guest User

asdfasdfasdfasdf

a guest
Mar 14th, 2018
310
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.79 KB | None | 0 0
  1. #include "pathtracer.h"
  2. #include "bsdf.h"
  3. #include "ray.h"
  4.  
  5. // #include "lenscamera.h"
  6.  
  7. #include <stack>
  8. #include <random>
  9. #include <algorithm>
  10. #include <sstream>
  11.  
  12. #include "CGL/CGL.h"
  13. #include "CGL/vector3D.h"
  14. #include "CGL/matrix3x3.h"
  15. #include "CGL/lodepng.h"
  16.  
  17. #include "GL/glew.h"
  18.  
  19. #include "static_scene/sphere.h"
  20. #include "static_scene/triangle.h"
  21. #include "static_scene/light.h"
  22.  
  23. using namespace CGL::StaticScene;
  24.  
  25. using std::min;
  26. using std::max;
  27.  
  28. namespace CGL {
  29.  
  30. PathTracer::PathTracer(size_t ns_aa,
  31.                        size_t max_ray_depth,
  32.                        size_t ns_area_light,
  33.                        size_t ns_diff,
  34.                        size_t ns_glsy,
  35.                        size_t ns_refr,
  36.                        size_t num_threads,
  37.                        size_t samples_per_batch,
  38.                        float max_tolerance,
  39.                        HDRImageBuffer* envmap,
  40.                        bool direct_hemisphere_sample,
  41.                        string filename,
  42.                        double lensRadius,
  43.                        double focalDistance){
  44.   state = INIT,
  45.   this->ns_aa = ns_aa;
  46.   this->max_ray_depth = max_ray_depth;
  47.   this->ns_area_light = ns_area_light;
  48.   this->ns_diff = ns_diff;
  49.   this->ns_glsy = ns_diff;
  50.   this->ns_refr = ns_refr;
  51.   this->samplesPerBatch = samples_per_batch;
  52.   this->maxTolerance = max_tolerance;
  53.   this->lensRadius = lensRadius;
  54.   this->focalDistance = focalDistance;
  55.   this->direct_hemisphere_sample = direct_hemisphere_sample;
  56.   this->filename = filename;
  57.  
  58.   if (envmap) {
  59.     this->envLight = new EnvironmentLight(envmap);
  60.   } else {
  61.     this->envLight = NULL;
  62.   }
  63.  
  64.   bvh = NULL;
  65.   scene = NULL;
  66.   camera = NULL;
  67.  
  68.   gridSampler = new UniformGridSampler2D();
  69.   hemisphereSampler = new UniformHemisphereSampler3D();
  70.  
  71.   show_rays = true;
  72.  
  73.   imageTileSize = 32;
  74.   numWorkerThreads = num_threads;
  75.   workerThreads.resize(numWorkerThreads);
  76.  
  77.   tm_gamma = 2.2f;
  78.   tm_level = 1.0f;
  79.   tm_key = 0.18;
  80.   tm_wht = 5.0f;
  81.  
  82. }
  83.  
  84. PathTracer::~PathTracer() {
  85.  
  86.   delete bvh;
  87.   delete gridSampler;
  88.   delete hemisphereSampler;
  89.  
  90. }
  91.  
  92. void PathTracer::set_scene(Scene *scene) {
  93.  
  94.   if (state != INIT) {
  95.     return;
  96.   }
  97.  
  98.   if (this->scene != nullptr) {
  99.     delete scene;
  100.     delete bvh;
  101.     selectionHistory.pop();
  102.   }
  103.  
  104.   if (this->envLight != nullptr) {
  105.     scene->lights.push_back(this->envLight);
  106.   }
  107.  
  108.   this->scene = scene;
  109.   build_accel();
  110.  
  111.   if (has_valid_configuration()) {
  112.     state = READY;
  113.   }
  114. }
  115.  
  116. void PathTracer::set_camera(Camera *camera) {
  117.   if (state != INIT) {
  118.     return;
  119.   }
  120.   this->camera = camera;
  121.   if (!this->camera->lensRadius)
  122.     this->camera->lensRadius = lensRadius;
  123.   if (!this->camera->focalDistance)
  124.     this->camera->focalDistance = focalDistance;
  125.   if (has_valid_configuration()) {
  126.     state = READY;
  127.   }
  128. }
  129.  
  130. void PathTracer::set_frame_size(size_t width, size_t height) {
  131.   if (state != INIT && state != READY) {
  132.     stop();
  133.   }
  134.   sampleBuffer.resize(width, height);
  135.   frameBuffer.resize(width, height);
  136.   cell_tl = Vector2D(0,0);
  137.   cell_br = Vector2D(width, height);
  138.   render_cell = false;
  139.   sampleCountBuffer.resize(width * height);
  140.   if (has_valid_configuration()) {
  141.     state = READY;
  142.   }
  143. }
  144.  
  145. bool PathTracer::has_valid_configuration() {
  146.   return scene && camera && gridSampler && hemisphereSampler &&
  147.          (!sampleBuffer.is_empty());
  148. }
  149.  
  150. void PathTracer::update_screen() {
  151.   switch (state) {
  152.     case INIT:
  153.     case READY:
  154.       break;
  155.     case VISUALIZE:
  156.       visualize_accel();
  157.       break;
  158.     case RENDERING:
  159.       glDrawPixels(frameBuffer.w, frameBuffer.h, GL_RGBA,
  160.                    GL_UNSIGNED_BYTE, &frameBuffer.data[0]);
  161.       if (render_cell)
  162.         visualize_cell();
  163.       break;
  164.     case DONE:
  165.         //sampleBuffer.tonemap(frameBuffer, tm_gamma, tm_level, tm_key, tm_wht);
  166.       glDrawPixels(frameBuffer.w, frameBuffer.h, GL_RGBA,
  167.                    GL_UNSIGNED_BYTE, &frameBuffer.data[0]);
  168.       if (render_cell)
  169.         visualize_cell();
  170.       break;
  171.   }
  172. }
  173.  
  174. void PathTracer::stop() {
  175.   switch (state) {
  176.     case INIT:
  177.     case READY:
  178.       break;
  179.     case VISUALIZE:
  180.       while (selectionHistory.size() > 1) {
  181.         selectionHistory.pop();
  182.       }
  183.       state = READY;
  184.       break;
  185.     case RENDERING:
  186.       continueRaytracing = false;
  187.     case DONE:
  188.       for (int i=0; i<numWorkerThreads; i++) {
  189.             workerThreads[i]->join();
  190.             delete workerThreads[i];
  191.         }
  192.       state = READY;
  193.       break;
  194.   }
  195.   render_silent = false;
  196. }
  197.  
  198. void PathTracer::clear() {
  199.   if (state != READY) return;
  200.   delete bvh;
  201.   bvh = NULL;
  202.   scene = NULL;
  203.   camera = NULL;
  204.   selectionHistory.pop();
  205.   sampleBuffer.resize(0, 0);
  206.   frameBuffer.resize(0, 0);
  207.   state = INIT;
  208.   render_cell = false;
  209. }
  210.  
  211. void PathTracer::start_visualizing() {
  212.   if (state != READY) {
  213.     return;
  214.   }
  215.   state = VISUALIZE;
  216. }
  217.  
  218. void PathTracer::start_raytracing() {
  219.   if (state != READY) return;
  220.  
  221.   // Intersection isect;
  222.   // Ray r = camera->center_ray();
  223.   // if (camera->lens_ind >= 0&& bvh->intersect(r, &isect)) {
  224.   //   camera->focus_at(isect.t);
  225.   // }
  226.  
  227.   rayLog.clear();
  228.   workQueue.clear();
  229.  
  230.   state = RENDERING;
  231.   continueRaytracing = true;
  232.   workerDoneCount = 0;
  233.  
  234.   sampleBuffer.clear();
  235.   if (!render_cell) {
  236.     frameBuffer.clear();
  237.     num_tiles_w = sampleBuffer.w / imageTileSize + 1;
  238.     num_tiles_h = sampleBuffer.h / imageTileSize + 1;
  239.     tilesTotal = num_tiles_w * num_tiles_h;
  240.     tilesDone = 0;
  241.     tile_samples.resize(num_tiles_w * num_tiles_h);
  242.     memset(&tile_samples[0], 0, num_tiles_w * num_tiles_h * sizeof(int));
  243.  
  244.     // populate the tile work queue
  245.     for (size_t y = 0; y < sampleBuffer.h; y += imageTileSize) {
  246.         for (size_t x = 0; x < sampleBuffer.w; x += imageTileSize) {
  247.             workQueue.put_work(WorkItem(x, y, imageTileSize, imageTileSize));
  248.         }
  249.     }
  250.   } else {
  251.     int w = (cell_br-cell_tl).x;
  252.     int h = (cell_br-cell_tl).y;
  253.     int imTS = imageTileSize / 4;
  254.     num_tiles_w = w / imTS + 1;
  255.     num_tiles_h = h / imTS + 1;
  256.     tilesTotal = num_tiles_w * num_tiles_h;
  257.     tilesDone = 0;
  258.     tile_samples.resize(num_tiles_w * num_tiles_h);
  259.     memset(&tile_samples[0], 0, num_tiles_w * num_tiles_h * sizeof(int));
  260.  
  261.     // populate the tile work queue
  262.     for (size_t y = cell_tl.y; y < cell_br.y; y += imTS) {
  263.       for (size_t x = cell_tl.x; x < cell_br.x; x += imTS) {
  264.         workQueue.put_work(WorkItem(x, y,
  265.           min(imTS, (int)(cell_br.x-x)), min(imTS, (int)(cell_br.y-y)) ));
  266.       }
  267.     }
  268.   }
  269.  
  270.   bvh->total_isects = 0; bvh->total_rays = 0;
  271.   // launch threads
  272.   fprintf(stdout, "[PathTracer] Rendering... "); fflush(stdout);
  273.   for (int i=0; i<numWorkerThreads; i++) {
  274.       workerThreads[i] = new std::thread(&PathTracer::worker_thread, this);
  275.   }
  276. }
  277.  
  278. void PathTracer::render_to_file(string filename, size_t x, size_t y, size_t dx, size_t dy) {
  279.   if (x == -1) {
  280.     unique_lock<std::mutex> lk(m_done);
  281.     start_raytracing();
  282.     cv_done.wait(lk, [this]{ return state == DONE; });
  283.     lk.unlock();
  284.     save_image(filename);
  285.     fprintf(stdout, "[PathTracer] Job completed.\n");
  286.   } else {
  287.     render_cell = true;
  288.     cell_tl = Vector2D(x,y);
  289.     cell_br = Vector2D(x+dx,y+dy);
  290.     ImageBuffer buffer;
  291.     raytrace_cell(buffer);
  292.     save_image(filename, &buffer);
  293.     fprintf(stdout, "[PathTracer] Cell job completed.\n");
  294.   }
  295. }
  296.  
  297.  
  298. void PathTracer::build_accel() {
  299.  
  300.   // collect primitives //
  301.   fprintf(stdout, "[PathTracer] Collecting primitives... "); fflush(stdout);
  302.   timer.start();
  303.   vector<Primitive *> primitives;
  304.   for (SceneObject *obj : scene->objects) {
  305.     const vector<Primitive *> &obj_prims = obj->get_primitives();
  306.     primitives.reserve(primitives.size() + obj_prims.size());
  307.     primitives.insert(primitives.end(), obj_prims.begin(), obj_prims.end());
  308.   }
  309.   timer.stop();
  310.   fprintf(stdout, "Done! (%.4f sec)\n", timer.duration());
  311.  
  312.   // build BVH //
  313.   fprintf(stdout, "[PathTracer] Building BVH from %lu primitives... ", primitives.size());
  314.   fflush(stdout);
  315.   timer.start();
  316.   bvh = new BVHAccel(primitives);
  317.   timer.stop();
  318.   fprintf(stdout, "Done! (%.4f sec)\n", timer.duration());
  319.  
  320.   // initial visualization //
  321.   selectionHistory.push(bvh->get_root());
  322. }
  323.  
  324. void PathTracer::visualize_accel() const {
  325.  
  326.   glPushAttrib(GL_ENABLE_BIT);
  327.   glDisable(GL_LIGHTING);
  328.   glLineWidth(1);
  329.   glEnable(GL_DEPTH_TEST);
  330.  
  331.   // hardcoded color settings
  332.   Color cnode = Color(.5, .5, .5, .25);
  333.   Color cnode_hl = Color(1., .25, .0, .6);
  334.   Color cnode_hl_child = Color(1., 1., 1., .6);
  335.  
  336.   Color cprim_hl_left = Color(.6, .6, 1., 1);
  337.   Color cprim_hl_right = Color(.8, .8, 1., 1);
  338.   Color cprim_hl_edges = Color(0., 0., 0., 0.5);
  339.  
  340.   BVHNode *selected = selectionHistory.top();
  341.  
  342.   // render solid geometry (with depth offset)
  343.   glPolygonOffset(1.0, 1.0);
  344.   glEnable(GL_POLYGON_OFFSET_FILL);
  345.  
  346.   if (selected->isLeaf()) {
  347.     bvh->draw(selected, cprim_hl_left);
  348.   } else {
  349.     bvh->draw(selected->l, cprim_hl_left);
  350.     bvh->draw(selected->r, cprim_hl_right);
  351.   }
  352.  
  353.   glDisable(GL_POLYGON_OFFSET_FILL);
  354.  
  355.   // draw geometry outline
  356.   bvh->drawOutline(selected, cprim_hl_edges);
  357.  
  358.   // keep depth buffer check enabled so that mesh occluded bboxes, but
  359.   // disable depth write so that bboxes don't occlude each other.
  360.   glDepthMask(GL_FALSE);
  361.  
  362.   // create traversal stack
  363.   stack<BVHNode *> tstack;
  364.  
  365.   // push initial traversal data
  366.   tstack.push(bvh->get_root());
  367.  
  368.   // draw all BVH bboxes with non-highlighted color
  369.   while (!tstack.empty()) {
  370.  
  371.     BVHNode *current = tstack.top();
  372.     tstack.pop();
  373.  
  374.     current->bb.draw(cnode);
  375.     if (current->l) tstack.push(current->l);
  376.     if (current->r) tstack.push(current->r);
  377.   }
  378.  
  379.   // draw selected node bbox and primitives
  380.   if (selected->l) selected->l->bb.draw(cnode_hl_child);
  381.   if (selected->r) selected->r->bb.draw(cnode_hl_child);
  382.  
  383.   glLineWidth(3.f);
  384.   selected->bb.draw(cnode_hl);
  385.  
  386.   // now perform visualization of the rays
  387.   if (show_rays) {
  388.       glLineWidth(1.f);
  389.       glBegin(GL_LINES);
  390.  
  391.       for (size_t i=0; i<rayLog.size(); i+=500) {
  392.  
  393.           const static double VERY_LONG = 10e4;
  394.           double ray_t = VERY_LONG;
  395.  
  396.           // color rays that are hits yellow
  397.           // and rays this miss all geometry red
  398.           if (rayLog[i].hit_t >= 0.0) {
  399.               ray_t = rayLog[i].hit_t;
  400.               glColor4f(1.f, 1.f, 0.f, 0.1f);
  401.           } else {
  402.               glColor4f(1.f, 0.f, 0.f, 0.1f);
  403.           }
  404.  
  405.           Vector3D end = rayLog[i].o + ray_t * rayLog[i].d;
  406.  
  407.           glVertex3f(rayLog[i].o[0], rayLog[i].o[1], rayLog[i].o[2]);
  408.           glVertex3f(end[0], end[1], end[2]);
  409.       }
  410.       glEnd();
  411.   }
  412.  
  413.   glDepthMask(GL_TRUE);
  414.   glPopAttrib();
  415. }
  416.  
  417. void PathTracer::visualize_cell() const {
  418.   glPushAttrib(GL_VIEWPORT_BIT);
  419.   glViewport(0, 0, sampleBuffer.w, sampleBuffer.h);
  420.  
  421.   glMatrixMode(GL_PROJECTION);
  422.   glPushMatrix();
  423.   glLoadIdentity();
  424.   glOrtho(0, sampleBuffer.w, sampleBuffer.h, 0, 0, 1);
  425.  
  426.   glMatrixMode(GL_MODELVIEW);
  427.   glPushMatrix();
  428.   glLoadIdentity();
  429.   glTranslatef(0, 0, -1);
  430.  
  431.   glColor4f(1.0, 0.0, 0.0, 0.8);
  432.   glDisable(GL_DEPTH_TEST);
  433.   glDisable(GL_LIGHTING);
  434.  
  435.   // Draw the Red Rectangle.
  436.   glBegin(GL_LINE_LOOP);
  437.   glVertex2f(cell_tl.x, sampleBuffer.h-cell_br.y);
  438.   glVertex2f(cell_br.x, sampleBuffer.h-cell_br.y);
  439.   glVertex2f(cell_br.x, sampleBuffer.h-cell_tl.y);
  440.   glVertex2f(cell_tl.x, sampleBuffer.h-cell_tl.y);
  441.   glEnd();
  442.  
  443.   glMatrixMode(GL_PROJECTION);
  444.   glPopMatrix();
  445.  
  446.   glMatrixMode(GL_MODELVIEW);
  447.   glPopMatrix();
  448.  
  449.   glPopAttrib();
  450.  
  451.   glEnable(GL_LIGHTING);
  452.   glEnable(GL_DEPTH_TEST);
  453. }
  454.  
  455. void PathTracer::key_press(int key) {
  456.  
  457.   BVHNode *current = selectionHistory.top();
  458.   switch (key) {
  459.   case ']':
  460.       ns_aa *=2;
  461.       fprintf(stdout, "[PathTracer] Samples per pixel changed to %lu\n", ns_aa);
  462.       //tm_key = clamp(tm_key + 0.02f, 0.0f, 1.0f);
  463.       break;
  464.   case '[':
  465.       //tm_key = clamp(tm_key - 0.02f, 0.0f, 1.0f);
  466.       ns_aa /=2;
  467.       if (ns_aa < 1) ns_aa = 1;
  468.       fprintf(stdout, "[PathTracer] Samples per pixel changed to %lu\n", ns_aa);
  469.       break;
  470.   case '=': case '+':
  471.       ns_area_light *= 2;
  472.       fprintf(stdout, "[PathTracer] Area light sample count increased to %zu.\n", ns_area_light);
  473.       break;
  474.   case '-': case '_':
  475.       if (ns_area_light > 1) ns_area_light /= 2;
  476.       fprintf(stdout, "[PathTracer] Area light sample count decreased to %zu.\n", ns_area_light);
  477.       break;
  478.   case '.': case '>':
  479.       max_ray_depth++;
  480.       fprintf(stdout, "[PathTracer] Max ray depth increased to %zu.\n", max_ray_depth);
  481.       break;
  482.   case ',': case '<':
  483.       if (max_ray_depth) max_ray_depth--;
  484.       fprintf(stdout, "[PathTracer] Max ray depth decreased to %zu.\n", max_ray_depth);
  485.       break;
  486.   case ';': case ':':
  487.       focalDistance += .1;
  488.       camera->focalDistance = focalDistance;
  489.       fprintf(stdout, "[PathTracer] Focal distance increased to %f.\n", camera->focalDistance);
  490.       break;
  491.   case '\'': case '\"':
  492.       focalDistance -= .1;
  493.       camera->focalDistance = focalDistance;
  494.       fprintf(stdout, "[PathTracer] Focal distance decreased to %f.\n", camera->focalDistance);
  495.       break;
  496.   case 'k': case 'K':
  497.       if (lensRadius == 0)
  498.         lensRadius = .03125f;
  499.       else
  500.         lensRadius *= sqrt(2.);
  501.       camera->lensRadius = lensRadius;
  502.       fprintf(stdout, "[PathTracer] Aperture increased to %f.\n", camera->lensRadius);
  503.       break;
  504.   case 'l': case 'L':
  505.       if (lensRadius <= .03125f)
  506.         lensRadius = 0.;
  507.       else
  508.         lensRadius /= sqrt(2.);
  509.       camera->lensRadius = lensRadius;
  510.       fprintf(stdout, "[PathTracer] Aperture decreased to %f.\n", camera->lensRadius);
  511.       break;
  512.   case KEYBOARD_UP:
  513.       if (current != bvh->get_root()) {
  514.           selectionHistory.pop();
  515.       }
  516.       break;
  517.   case KEYBOARD_LEFT:
  518.       if (current->l) {
  519.           selectionHistory.push(current->l);
  520.       }
  521.       break;
  522.   case KEYBOARD_RIGHT:
  523.       if (current->l) {
  524.           selectionHistory.push(current->r);
  525.       }
  526.       break;
  527.  
  528.   case 'C':
  529.     render_cell = !render_cell;
  530.     if (render_cell)
  531.       fprintf(stdout, "[PathTracer] Now in cell render mode.\n");
  532.     else
  533.       fprintf(stdout, "[PathTracer] No longer in cell render mode.\n");
  534.   break;
  535.  
  536.   default:
  537.       return;
  538.   }
  539. }
  540.  
  541.  
  542. Spectrum PathTracer::estimate_direct_lighting_hemisphere(const Ray& r, const Intersection& isect) {
  543.   // Estimate the lighting from this intersection coming directly from a light.
  544.   // For this function, sample uniformly in a hemisphere.
  545.  
  546.   // make a coordinate system for a hit point
  547.   // with N aligned with the Z direction.
  548.   Matrix3x3 o2w;
  549.   make_coord_space(o2w, isect.n);
  550.   Matrix3x3 w2o = o2w.T();
  551.  
  552.   // w_out points towards the source of the ray (e.g.,
  553.   // toward the camera if this is a primary ray)
  554.   const Vector3D& hit_p = r.o + r.d * isect.t;
  555.   const Vector3D& w_out = w2o * (-r.d);
  556.  
  557.   // This is the same number of total samples as estimate_direct_lighting_importance (outside of delta lights).
  558.   // We keep the same number of samples for clarity of comparison.
  559.   int num_samples = scene->lights.size() * ns_area_light;
  560.   Spectrum L_out;
  561.  
  562.   // TODO (Part 3): Write your sampling loop here
  563.   // COMMENT OUT `normal_shading` IN `est_radiance_global_illumination` BEFORE YOU BEGIN
  564.   double pdf = 1.0 / (2 * PI);
  565.   Intersection inters;
  566.   for (int i = 0; i < num_samples; i ++) {
  567.     Vector3D wi = hemisphereSampler->get_sample();
  568.     Vector3D wi_world = o2w * wi;
  569.     if (bvh->intersect(Ray(EPS_D * wi_world + hit_p, wi_world, INF_D), &inters)) {
  570.       L_out += inters.bsdf->get_emission() * isect.bsdf->f(wi, w_out) * wi.z / pdf;
  571.     }
  572.   }
  573.  
  574.   return L_out / num_samples;
  575. }
  576.  
  577. Spectrum PathTracer::estimate_direct_lighting_importance(const Ray& r, const Intersection& isect) {
  578.   // Estimate the lighting from this intersection coming directly from a light.
  579.   // To implement importance sampling, sample only from lights, not uniformly in a hemisphere.
  580.  
  581.   // make a coordinate system for a hit point
  582.   // with N aligned with the Z direction.
  583.   Matrix3x3 o2w;
  584.   make_coord_space(o2w, isect.n);
  585.   Matrix3x3 w2o = o2w.T();
  586.  
  587.   // w_out points towards the source of the ray (e.g.,
  588.   // toward the camera if this is a primary ray)
  589.   const Vector3D& hit_p = r.o + r.d * isect.t;
  590.   const Vector3D& w_out = w2o * (-r.d);
  591.   Spectrum L_out;
  592.  
  593.   // TODO (Part 3): Here is where your code for looping over scene lights goes
  594.   // COMMENT OUT `normal_shading` IN `est_radiance_global_illumination` BEFORE YOU BEGIN
  595.   Intersection inters;
  596.   for (SceneLight *sl : scene->lights) {
  597.     Spectrum L_out_temp;
  598.  
  599.     if (sl->is_delta_light()) {
  600.       Vector3D wi;
  601.       float distToLight, pdf;
  602.       Spectrum e = sl->sample_L(hit_p, &wi, &distToLight, &pdf);
  603.       Vector3D w_in = w2o * wi;
  604.  
  605.       if (w_in.z < 0) {
  606.         continue;
  607.       }
  608.  
  609.       if (!bvh->intersect(Ray(EPS_D * wi + hit_p, wi, distToLight), &inters)) {
  610.         L_out_temp += e * isect.bsdf->f(w_in, w_out) * w_in.z / pdf;
  611.       }
  612.     } else {
  613.       for (int i = 0; i < ns_area_light; i ++) {
  614.         Vector3D wi;
  615.         float distToLight, pdf;
  616.         Spectrum e = sl->sample_L(hit_p, &wi, &distToLight, &pdf);
  617.         Vector3D w_in = w2o * wi;
  618.  
  619.         if (w_in.z < 0) {
  620.           continue;
  621.         }
  622.  
  623.         if (!bvh->intersect(Ray(EPS_D * wi + hit_p, wi, distToLight), &inters)) {
  624.           L_out_temp += e * isect.bsdf->f(w_in, w_out) * w_in.z / pdf;
  625.         }
  626.       }
  627.       L_out_temp /= ns_area_light;
  628.     }
  629.     L_out += L_out_temp;
  630.   }
  631.   return L_out;
  632. }
  633.  
  634.  
  635.  
  636.  
  637. Spectrum PathTracer::zero_bounce_radiance(const Ray&r, const Intersection& isect) {
  638.   // TODO: Part 4, Task 2
  639.   // Returns the light that results from no bounces of light
  640.   return isect.bsdf->get_emission();
  641. }
  642.  
  643. Spectrum PathTracer::one_bounce_radiance(const Ray&r, const Intersection& isect) {
  644.   // TODO: Part 4, Task 2
  645.   // Returns either the direct illumination by hemisphere or importance sampling
  646.   // depending on `direct_hemisphere_sample`
  647.   // (you implemented these functions in Part 3)
  648.  
  649.   if (direct_hemisphere_sample)
  650.     return estimate_direct_lighting_hemisphere(r, isect);
  651.   return estimate_direct_lighting_importance(r, isect);
  652. }
  653.  
  654. Spectrum PathTracer::at_least_one_bounce_radiance(const Ray&r, const Intersection& isect) {
  655.   Matrix3x3 o2w;
  656.   make_coord_space(o2w, isect.n);
  657.   Matrix3x3 w2o = o2w.T();
  658.  
  659.   Vector3D hit_p = r.o + r.d * isect.t;
  660.   Vector3D w_out = w2o * (-r.d);
  661.  
  662.   Spectrum L_out = Spectrum(0, 0, 0);
  663.   if (!isect.bsdf->is_delta())
  664.     L_out = one_bounce_radiance(r, isect);
  665.  
  666.   // TODO (Part 4.2): Here is where your code for sampling the BSDF,
  667.   // performing Russian roulette step, and returning a recursively
  668.   // traced ray (when applicable) goes
  669.   Vector3D w_in;
  670.   float pdf;
  671.   Spectrum s = isect.bsdf->sample_f(w_out, &w_in, &pdf);
  672.  
  673.   if (coin_flip(0.5) && r.depth > 1) {
  674.     Intersection inters;
  675.     Ray r_new = Ray(hit_p + EPS_D * o2w * w_in, o2w * w_in, INF_D, r.depth - 1);
  676.     if (bvh->intersect(r_new, &inters)) {
  677.       if (isect.bsdf->is_delta())
  678.         L_out += (at_least_one_bounce_radiance(r_new, inters) + zero_bounce_radiance(r_new, inters))
  679.                  * s * fabs(w_in.z) / ((1 - 0.5) * pdf);
  680.       else
  681.         L_out += at_least_one_bounce_radiance(r_new, inters) * s * fabs(w_in.z) / ((1 - 0.5) * pdf);
  682.     }
  683.   }
  684.   return L_out;
  685. }
  686.  
  687. Spectrum PathTracer::est_radiance_global_illumination(const Ray &r) {
  688.   Intersection isect;
  689.   Spectrum L_out;
  690.  
  691.   // You will extend this in assignment 3-2.
  692.   // If no intersection occurs, we simply return black.
  693.   // This changes if you implement hemispherical lighting for extra credit.
  694.  
  695.   if (!bvh->intersect(r, &isect))
  696.     return L_out;
  697.  
  698.   // This line returns a color depending only on the normal vector
  699.   // to the surface at the intersection point.
  700.   // REMOVE IT when you are ready to begin Part 3.
  701.  
  702.   // return normal_shading(isect.n);
  703.  
  704.   // TODO (Part 3): Return the direct illumination.
  705.   // L_out = estimate_direct_lighting_hemisphere(r, isect) + zero_bounce_radiance(r, isect);
  706.   // L_out = estimate_direct_lighting_importance(r, isect) + zero_bounce_radiance(r, isect);
  707.   // TODO (Part 4): Accumulate the "direct" and "indirect"
  708.   L_out = zero_bounce_radiance(r, isect) + at_least_one_bounce_radiance(r, isect);
  709.   // parts of global illumination into L_out rather than just direct
  710.   // indirect only
  711.   // Spectrum one_bounce = one_bounce_radiance(r, isect);
  712.   // L_out.r -= one_bounce.r;
  713.   // L_out.g -= one_bounce.g;
  714.   // L_out.b -= one_bounce.b;
  715.   return L_out;
  716. }
  717.  
  718. Spectrum PathTracer::raytrace_pixel(size_t x, size_t y) {
  719.  
  720.   // TODO (Part 1.1):
  721.   // Make a loop that generates num_samples camera rays and traces them
  722.   // through the scene. Return the average Spectrum.
  723.   // You should call est_radiance_global_illumination in this function.
  724.  
  725.   // TODO (Part 5):
  726.   // Modify your implementation to include adaptive sampling.
  727.   // Use the command line parameters "samplesPerBatch" and "maxTolerance"
  728.  
  729.   int num_samples = ns_aa;            // total samples to evaluate
  730.   Vector2D origin = Vector2D(x,y);    // bottom left corner of the pixel
  731.  
  732.   Spectrum total = Spectrum(0, 0, 0);
  733.  
  734.   if (num_samples == 1) {
  735.     Ray r = camera->generate_ray((x + 0.5) / sampleBuffer.w, (y + 0.5) / sampleBuffer.h);
  736.     r.depth = max_ray_depth;
  737.     return est_radiance_global_illumination(r);
  738.   }
  739.  
  740.   double s1 = 0;
  741.   double s2 = 0;
  742.   float mean, std_dev;
  743.  
  744.   for (int i = 0; i < num_samples; i ++) {
  745.     Vector2D random = gridSampler->get_sample();
  746.     Ray r = camera->generate_ray((x + random.x) / sampleBuffer.w, (y + random.y) / sampleBuffer.h);
  747.     r.depth = max_ray_depth;
  748.     Spectrum spec = est_radiance_global_illumination(r);
  749.     total += spec;
  750.  
  751.     float illum = spec.illum();
  752.     s1 += illum;
  753.     s2 += illum * illum;
  754.     if ((i + 1) % samplesPerBatch == 0) {
  755.       mean = s1 / (i + 1);
  756.       std_dev = sqrt(1.0 / i * (s2 - (s1 * s1) / (i + 1)));
  757.       if (1.96 * std_dev / sqrt(i + 1) <= maxTolerance * mean) {
  758.         num_samples = i + 1;
  759.         break;
  760.       }
  761.     }
  762.   }
  763.   sampleCountBuffer[y * sampleBuffer.w + x] = num_samples;
  764.   return total / num_samples;
  765. }
  766.  
  767. void PathTracer::raytrace_tile(int tile_x, int tile_y,
  768.                                int tile_w, int tile_h) {
  769.  
  770.   size_t w = sampleBuffer.w;
  771.   size_t h = sampleBuffer.h;
  772.  
  773.   size_t tile_start_x = tile_x;
  774.   size_t tile_start_y = tile_y;
  775.  
  776.   size_t tile_end_x = std::min(tile_start_x + tile_w, w);
  777.   size_t tile_end_y = std::min(tile_start_y + tile_h, h);
  778.  
  779.   size_t tile_idx_x = tile_x / imageTileSize;
  780.   size_t tile_idx_y = tile_y / imageTileSize;
  781.   size_t num_samples_tile = tile_samples[tile_idx_x + tile_idx_y * num_tiles_w];
  782.  
  783.   for (size_t y = tile_start_y; y < tile_end_y; y++) {
  784.     if (!continueRaytracing) return;
  785.     for (size_t x = tile_start_x; x < tile_end_x; x++) {
  786.         Spectrum s = raytrace_pixel(x, y);
  787.         sampleBuffer.update_pixel(s, x, y);
  788.     }
  789.   }
  790.  
  791.   tile_samples[tile_idx_x + tile_idx_y * num_tiles_w] += 1;
  792.   sampleBuffer.toColor(frameBuffer, tile_start_x, tile_start_y, tile_end_x, tile_end_y);
  793. }
  794.  
  795. void PathTracer::raytrace_cell(ImageBuffer& buffer) {
  796.   size_t tile_start_x = cell_tl.x;
  797.   size_t tile_start_y = cell_tl.y;
  798.  
  799.   size_t tile_end_x = cell_br.x;
  800.   size_t tile_end_y = cell_br.y;
  801.  
  802.   size_t w = tile_end_x - tile_start_x;
  803.   size_t h = tile_end_y - tile_start_y;
  804.   HDRImageBuffer sb(w, h);
  805.   buffer.resize(w,h);
  806.  
  807.   stop();
  808.   render_cell = true;
  809.   {
  810.     unique_lock<std::mutex> lk(m_done);
  811.     start_raytracing();
  812.     cv_done.wait(lk, [this]{ return state == DONE; });
  813.     lk.unlock();
  814.   }
  815.  
  816.   for (size_t y = tile_start_y; y < tile_end_y; y++) {
  817.     for (size_t x = tile_start_x; x < tile_end_x; x++) {
  818.         buffer.data[w*(y-tile_start_y)+(x-tile_start_x)] = frameBuffer.data[x+y*sampleBuffer.w];
  819.     }
  820.   }
  821. }
  822.  
  823. void PathTracer::worker_thread() {
  824.  
  825.   Timer timer;
  826.   timer.start();
  827.  
  828.   WorkItem work;
  829.   while (continueRaytracing && workQueue.try_get_work(&work)) {
  830.     raytrace_tile(work.tile_x, work.tile_y, work.tile_w, work.tile_h);
  831.     {
  832.       lock_guard<std::mutex> lk(m_done);
  833.       ++tilesDone;
  834.       if (!render_silent)  cout << "\r[PathTracer] Rendering... " << int((double)tilesDone/tilesTotal * 100) << '%';
  835.       cout.flush();
  836.     }
  837.   }
  838.  
  839.   workerDoneCount++;
  840.   if (!continueRaytracing && workerDoneCount == numWorkerThreads) {
  841.     timer.stop();
  842.     if (!render_silent)  fprintf(stdout, "\n[PathTracer] Rendering canceled!\n");
  843.     state = READY;
  844.   }
  845.  
  846.   if (continueRaytracing && workerDoneCount == numWorkerThreads) {
  847.     timer.stop();
  848.     if (!render_silent)  fprintf(stdout, "\r[PathTracer] Rendering... 100%%! (%.4fs)\n", timer.duration());
  849.     if (!render_silent)  fprintf(stdout, "[PathTracer] BVH traced %llu rays.\n", bvh->total_rays);
  850.     if (!render_silent)  fprintf(stdout, "[PathTracer] Averaged %f intersection tests per ray.\n", (((double)bvh->total_isects)/bvh->total_rays));
  851.  
  852.     lock_guard<std::mutex> lk(m_done);
  853.     state = DONE;
  854.     cv_done.notify_one();
  855.   }
  856. }
  857.  
  858. void PathTracer::save_image(string filename, ImageBuffer* buffer) {
  859.  
  860.   if (state != DONE) return;
  861.  
  862.   if (!buffer)
  863.     buffer = &frameBuffer;
  864.  
  865.   if (filename == "") {
  866.     time_t rawtime;
  867.     time (&rawtime);
  868.  
  869.     time_t t = time(nullptr);
  870.     tm *lt = localtime(&t);
  871.     stringstream ss;
  872.     ss << this->filename << "_screenshot_" << lt->tm_mon+1 << "-" << lt->tm_mday << "_"
  873.       << lt->tm_hour << "-" << lt->tm_min << "-" << lt->tm_sec << ".png";
  874.     filename = ss.str();  
  875.   }
  876.  
  877.   uint32_t* frame = &buffer->data[0];
  878.   size_t w = buffer->w;
  879.   size_t h = buffer->h;
  880.   uint32_t* frame_out = new uint32_t[w * h];
  881.   for(size_t i = 0; i < h; ++i) {
  882.     memcpy(frame_out + i * w, frame + (h - i - 1) * w, 4 * w);
  883.   }
  884.  
  885.   fprintf(stderr, "[PathTracer] Saving to file: %s... ", filename.c_str());
  886.   lodepng::encode(filename, (unsigned char*) frame_out, w, h);
  887.   fprintf(stderr, "Done!\n");
  888.  
  889.   save_sampling_rate_image(filename);
  890. }
  891.  
  892. void PathTracer::save_sampling_rate_image(string filename) {
  893.   size_t w = frameBuffer.w;
  894.   size_t h = frameBuffer.h;
  895.   ImageBuffer outputBuffer(w, h);
  896.  
  897.   for (int x = 0; x < w; x++) {
  898.       for (int y = 0; y < h; y++) {
  899.           float samplingRate = sampleCountBuffer[y * w + x] * 1.0f / ns_aa;
  900.  
  901.           Color c;
  902.           if (samplingRate <= 0.5) {
  903.               float r = (0.5 - samplingRate) / 0.5;
  904.               c = Color(0.0f, 0.0f, 1.0f) * r + Color(0.0f, 1.0f, 0.0f) * (1.0 - r);
  905.           } else {
  906.               float r = (1.0 - samplingRate) / 0.5;
  907.               c = Color(0.0f, 1.0f, 0.0f) * r + Color(1.0f, 0.0f, 0.0f) * (1.0 - r);
  908.           }
  909.           outputBuffer.update_pixel(c, x, h - 1 - y);
  910.       }
  911.   }
  912.  
  913.   lodepng::encode(filename.substr(0,filename.size()-4) + "_rate.png", (unsigned char*) (outputBuffer.data.data()), w, h);
  914. }
  915.  
  916. }  // namespace CGL
Advertisement
Add Comment
Please, Sign In to add comment