From d46f4abdab1f75b9d27848e26bdfeb1575572d40 Mon Sep 17 00:00:00 2001 From: Miguel Angel Date: Thu, 5 Jan 2017 17:59:04 -0400 Subject: [PATCH] Made Tracer an abstract class. --- Makefile | 2 +- main.cpp | 17 ++++---- path_tracer.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++ path_tracer.hpp | 20 ++++++++++ tracer.cpp | 103 ++---------------------------------------------- tracer.hpp | 21 ++++++---- 6 files changed, 147 insertions(+), 115 deletions(-) create mode 100644 path_tracer.cpp create mode 100644 path_tracer.hpp diff --git a/Makefile b/Makefile index 37ba643..2e51ea8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CXX = g++ TARGET = ray -OBJECTS = main.o disk.o plane.o sphere.o directional_light.o point_light.o tracer.o +OBJECTS = main.o disk.o plane.o sphere.o directional_light.o point_light.o tracer.o path_tracer.o DEPENDS = $(OBJECTS:.o=.d) CXXFLAGS = -ansi -pedantic -Wall -DGLM_FORCE_RADIANS -fopenmp LDLIBS = diff --git a/main.cpp b/main.cpp index c65b971..02d3895 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,7 @@ #include "directional_light.hpp" #include "point_light.hpp" #include "tracer.hpp" +#include "path_tracer.hpp" using namespace std; using namespace glm; @@ -41,9 +42,9 @@ int main(int argc, char ** argv) { vec2 sample; vector
figures; vector lights; - Tracer tracer; - int total; - int current = 0; + Tracer * tracer; + size_t total; + size_t current = 0; mat4x4 i_model_view; vec4 dir, orig; @@ -97,7 +98,7 @@ int main(int argc, char ** argv) { scene_2(figures, lights, i_model_view); - tracer = Tracer(g_h, g_w, g_fov, true); + tracer = static_cast(new PathTracer(g_h, g_w, g_fov, true)); total = g_h * g_w * g_samples; @@ -105,11 +106,11 @@ int main(int argc, char ** argv) { for (int i = 0; i < g_h; i++) { for (int j = 0; j < g_w; j++) { for (int k = 0; k < g_samples; k++) { - sample = tracer.sample_pixel(i, j); + sample = tracer->sample_pixel(i, j); dir = i_model_view * normalize(vec4(sample, -1.0f, 1.0f) - vec4(0.0f, 0.0f, 0.0f, 1.0f)); orig = i_model_view * vec4(0.0f, 0.0f, 0.0f, 1.0f); r = Ray(dir.x, dir.y, dir.z, orig.x, orig.y, orig.z); - image[i][j] += tracer.trace_ray(r, figures, lights, 0); + image[i][j] += tracer->trace_ray(r, figures, lights, 0); #pragma omp critical { current++; @@ -119,11 +120,13 @@ int main(int argc, char ** argv) { } #pragma omp critical { - cout << "\r" << setw(3) << static_cast((static_cast(current) / static_cast(total)) * 100.0f) << "% done"; + cout << "\r" << setw(3) << static_cast((static_cast(current) / static_cast(total)) * 100.0) << "% done"; } } cout << endl; + delete tracer; + for (size_t i = 0; i < figures.size(); i++) { delete figures[i]; } diff --git a/path_tracer.cpp b/path_tracer.cpp new file mode 100644 index 0000000..c3b325d --- /dev/null +++ b/path_tracer.cpp @@ -0,0 +1,99 @@ +#include + +#include + +#include "path_tracer.hpp" + +using std::numeric_limits; +using namespace glm; + +PathTracer::~PathTracer() { } + +vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const { + float t, _t; + Figure * _f; + vec3 n, color, i_pos, ref, sample, dir_diff_color, dir_spec_color, ind_color; + Ray mv_r, sr, rr; + bool vis; + float kr, r1, r2; + + t = numeric_limits::max(); + _f = NULL; + + // Find the closest intersecting surface. + for (size_t f = 0; f < v_figures.size(); f++) { + if (v_figures[f]->intersect(r, _t) && _t < t) { + t = _t; + _f = v_figures[f]; + } + } + + // If this ray intersects something: + if (_f != NULL) { + // Take the intersection point and the normal of the surface at that point. + i_pos = r.m_origin + (t * r.m_direction); + n = _f->normal_at_int(r, t); + + // Check if the material is not reflective/refractive. + if( !_f->m_mat.m_refract && _f->m_mat.m_rho == 0.0f) { + // Calculate the direct lighting. + for (size_t l = 0; l < v_lights.size(); l++) { + // For every light source + vis = true; + + // Cast a shadow ray to determine visibility. + sr = Ray(v_lights[l]->direction(i_pos), i_pos + n * BIAS); + for (size_t f = 0; f < v_figures.size(); f++) { + if (v_figures[f]->intersect(sr, _t) && _t < v_lights[l]->distance(i_pos)) { + vis = false; + break; + } + } + + // Evaluate the shading model accounting for visibility. + dir_diff_color += (vis ? 1.0f : 0.0f) * v_lights[l]->diffuse(n, r, t, _f->m_mat); + dir_spec_color += (vis ? 1.0f : 0.0f) * v_lights[l]->specular(n, r, t, _f->m_mat); + } + + // If enabled, calculate indirect lighting contribution. + if (indirect_l && rec_level < MAX_RECURSION) { + r1 = random01(); + r2 = random01(); + sample = sample_hemisphere(r1, r2); + rotate_sample(sample, n); + rr = Ray(normalize(sample), i_pos + (sample * BIAS)); + ind_color += r1 * trace_ray(rr, v_figures, v_lights, rec_level + 1) / (1.0f / (2.0f * pi())); + } + + color += ((dir_diff_color + ind_color) * (_f->m_mat.m_diffuse / pi())) + dir_spec_color; + + } else { + // If the material has reflection/transmission enabled. + // Calculate the Fresnel term if the surface is refracting. + if (_f->m_mat.m_refract) + kr = fresnel(r.m_direction, n, r.m_ref_index, _f->m_mat.m_ref_index); + else + kr = _f->m_mat.m_rho; + + // Determinte the specular reflection color. + if (kr > 0.0f && rec_level < MAX_RECURSION) { + rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); + color += _f->m_mat.m_rho * kr * trace_ray(rr, v_figures, v_lights, rec_level + 1); + } else if (rec_level >= MAX_RECURSION) + return vec3(0.0f); + + // Determine the transmission color. + if (_f->m_mat.m_refract && kr < 1.0f && rec_level < MAX_RECURSION) { + rr = Ray(normalize(refract(r.m_direction, n, r.m_ref_index / _f->m_mat.m_ref_index)), i_pos - n * BIAS, _f->m_mat.m_ref_index); + color += (1.0f - _f->m_mat.m_rho) * (1.0f - kr) * trace_ray(rr, v_figures, v_lights, rec_level + 1); + } else if (rec_level >= MAX_RECURSION) + return vec3(0.0f); + + } + + // Return final color. + return clamp(color, 0.0f, 1.0f); + + } else + return vec3(BCKG_COLOR); +} diff --git a/path_tracer.hpp b/path_tracer.hpp new file mode 100644 index 0000000..5e4f321 --- /dev/null +++ b/path_tracer.hpp @@ -0,0 +1,20 @@ +#pragma once +#ifndef PATH_TRACER_HPP +#define PATH_TRACER_HPP + +#include "tracer.hpp" + +class PathTracer: public Tracer { +public: + bool indirect_l; + + PathTracer(): Tracer(), indirect_l(false) { } + + PathTracer(int h, int w, float fov, bool il): Tracer(h, w, fov), indirect_l(il) { }; + + virtual ~PathTracer(); + + virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const; +}; + +#endif diff --git a/tracer.cpp b/tracer.cpp index 75d0f5b..7692c93 100644 --- a/tracer.cpp +++ b/tracer.cpp @@ -1,26 +1,18 @@ -#include -#include #include #include #include "tracer.hpp" -#define MAX_RECURSION 3 -#define BIAS 0.000001f - -using namespace std; - -using std::numeric_limits; using namespace glm; -static const vec3 BCKG_COLOR = vec3(0.0f); +const vec3 BCKG_COLOR = vec3(0.0f, 0.2f, 0.6f); -static inline float random01() { +float Tracer::random01() const { return static_cast(rand()) / static_cast(RAND_MAX); } -static float fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) { +float Tracer::fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) const { float cos_t1 = dot(i, n); float cos_t2 = dot(normalize(refract(i, n, ir1 / ir2)), n); float sin_t2 = (ir1 / ir2) * sqrt(1.0f - (cos_t2 * cos_t2)); @@ -48,95 +40,6 @@ vec2 Tracer::sample_pixel(int i, int j) const { return vec2(pxS, pyS); } -vec3 Tracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const { - float t, _t; - Figure * _f; - vec3 n, color, i_pos, ref, sample, dir_diff_color, dir_spec_color, ind_color; - Ray mv_r, sr, rr; - bool vis; - float kr, r1, r2; - - t = numeric_limits::max(); - _f = NULL; - - // Find the closest intersecting surface. - for (size_t f = 0; f < v_figures.size(); f++) { - if (v_figures[f]->intersect(r, _t) && _t < t) { - t = _t; - _f = v_figures[f]; - } - } - - // If this ray intersects something: - if (_f != NULL) { - // Take the intersection point and the normal of the surface at that point. - i_pos = r.m_origin + (t * r.m_direction); - n = _f->normal_at_int(r, t); - - // Check if the material is not reflective/refractive. - if( !_f->m_mat.m_refract && _f->m_mat.m_rho == 0.0f) { - // Calculate the direct lighting. - for (size_t l = 0; l < v_lights.size(); l++) { - // For every light source - vis = true; - - // Cast a shadow ray to determine visibility. - sr = Ray(v_lights[l]->direction(i_pos), i_pos + n * BIAS); - for (size_t f = 0; f < v_figures.size(); f++) { - if (v_figures[f]->intersect(sr, _t) && _t < v_lights[l]->distance(i_pos)) { - vis = false; - break; - } - } - - // Evaluate the shading model accounting for visibility. - dir_diff_color += (vis ? 1.0f : 0.0f) * v_lights[l]->diffuse(n, r, t, _f->m_mat); - dir_spec_color += (vis ? 1.0f : 0.0f) * v_lights[l]->specular(n, r, t, _f->m_mat); - } - - // If enabled, calculate indirect lighting contribution. - if (indirect_l && rec_level < MAX_RECURSION) { - r1 = random01(); - r2 = random01(); - sample = sample_hemisphere(r1, r2); - rotate_sample(sample, n); - rr = Ray(normalize(sample), i_pos + (sample * BIAS)); - ind_color += r1 * trace_ray(rr, v_figures, v_lights, rec_level + 1) / (1.0f / (2.0f * pi())); - } - - color += ((dir_diff_color + ind_color) * (_f->m_mat.m_diffuse / pi())) + dir_spec_color; - - } else { - // If the material has reflection/transmission enabled. - // Calculate the Fresnel term if the surface is refracting. - if (_f->m_mat.m_refract) - kr = fresnel(r.m_direction, n, r.m_ref_index, _f->m_mat.m_ref_index); - else - kr = _f->m_mat.m_rho; - - // Determinte the specular reflection color. - if (kr > 0.0f && rec_level < MAX_RECURSION) { - rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); - color += _f->m_mat.m_rho * kr * trace_ray(rr, v_figures, v_lights, rec_level + 1); - } else if (rec_level >= MAX_RECURSION) - return vec3(0.0f); - - // Determine the transmission color. - if (_f->m_mat.m_refract && kr < 1.0f && rec_level < MAX_RECURSION) { - rr = Ray(normalize(refract(r.m_direction, n, r.m_ref_index / _f->m_mat.m_ref_index)), i_pos - n * BIAS, _f->m_mat.m_ref_index); - color += (1.0f - _f->m_mat.m_rho) * (1.0f - kr) * trace_ray(rr, v_figures, v_lights, rec_level + 1); - } else if (rec_level >= MAX_RECURSION) - return vec3(0.0f); - - } - - // Return final color. - return clamp(color, 0.0f, 1.0f); - - } else - return vec3(BCKG_COLOR); -} - /* Helper functions pretty much taken from scratchapixel.com */ void Tracer::create_coords_system(const vec3 &n, vec3 &nt, vec3 &nb) const { if (abs(n.x) > abs(n.y)) diff --git a/tracer.hpp b/tracer.hpp index ee5faa8..0ef6957 100644 --- a/tracer.hpp +++ b/tracer.hpp @@ -13,7 +13,11 @@ using std::vector; using glm::vec2; using glm::vec3; -using glm::mat4x4; + +#define MAX_RECURSION 3 +#define BIAS 0.000001f + +extern const vec3 BCKG_COLOR; class Tracer { public: @@ -21,18 +25,21 @@ public: int m_w; float m_fov; float m_a_ratio; - bool indirect_l; - Tracer(): m_h(480), m_w(640), m_fov(90.0f), m_a_ratio(640.0f / 480.0f), indirect_l(false) { } + Tracer(): m_h(480), m_w(640), m_fov(90.0f), m_a_ratio(640.0f / 480.0f) { } - Tracer(int h, int w, float fov, bool il): m_h(h), m_w(w), m_fov(fov), indirect_l(il) { + Tracer(int h, int w, float fov): m_h(h), m_w(w), m_fov(fov) { m_a_ratio = static_cast(w) / static_cast(h); }; - vec2 sample_pixel(int i, int j) const; - vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const; + virtual ~Tracer() { } -private: + vec2 sample_pixel(int i, int j) const; + virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const = 0; + +protected: + float random01() const; + float fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) const; void create_coords_system(const vec3 &n, vec3 &nt, vec3 &nb) const; vec3 sample_hemisphere(const float r1, const float r2) const; void rotate_sample(vec3 & sample, const vec3 & n) const;