diff --git a/area_light.hpp b/area_light.hpp index ad0603b..0aa4a66 100644 --- a/area_light.hpp +++ b/area_light.hpp @@ -76,7 +76,11 @@ public: return vec3(0.0f); } - virtual void sample_at_surface(vec3 point) = 0; + virtual vec3 normal_at_last_sample() { + return m_n_at_last_sample; + } + + virtual vec3 sample_at_surface() = 0; protected: vec3 m_last_sample; diff --git a/disk_area_light.cpp b/disk_area_light.cpp index 8a6ee37..a809f34 100644 --- a/disk_area_light.cpp +++ b/disk_area_light.cpp @@ -1,7 +1,8 @@ #include "disk_area_light.hpp" -void DiskAreaLight::sample_at_surface(vec3 point) { +vec3 DiskAreaLight::sample_at_surface() { Disk * d = static_cast(m_figure); m_last_sample = m_figure->sample_at_surface(); m_n_at_last_sample = d->m_normal; + return m_last_sample; } diff --git a/disk_area_light.hpp b/disk_area_light.hpp index d205242..e14d603 100644 --- a/disk_area_light.hpp +++ b/disk_area_light.hpp @@ -9,7 +9,7 @@ class DiskAreaLight: public AreaLight { public: DiskAreaLight(Disk * _s, float _c = 1.0, float _l = 0.0, float _q = 0.0): AreaLight(static_cast
(_s), _c, _l, _q) { } - virtual void sample_at_surface(vec3 point); + virtual vec3 sample_at_surface(); }; #endif diff --git a/path_tracer.cpp b/path_tracer.cpp index c06d67f..534ab3b 100644 --- a/path_tracer.cpp +++ b/path_tracer.cpp @@ -73,7 +73,7 @@ vec3 PathTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { } else if (s->m_lights[l]->light_type() == Light::AREA) { // Cast a shadow ray towards a sample point on the surface of the light source. al = static_cast(s->m_lights[l]); - al->sample_at_surface(i_pos); + al->sample_at_surface(); sr = Ray(al->direction(i_pos), i_pos + (n * BIAS)); for (size_t f = 0; f < s->m_figures.size(); f++) { diff --git a/photon_tracer.cpp b/photon_tracer.cpp index cb2b66e..0b9acbd 100644 --- a/photon_tracer.cpp +++ b/photon_tracer.cpp @@ -12,9 +12,160 @@ using namespace glm; PhotonTracer::~PhotonTracer() { } vec3 PhotonTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { + float t, _t; + Figure * _f; + vec3 n, color, i_pos, ref, dir_diff_color, dir_spec_color; + Ray mv_r, sr, rr; + bool vis, is_area_light; + float kr; + AreaLight * al; + + t = numeric_limits::max(); + _f = NULL; + + // Find the closest intersecting surface. + for (size_t f = 0; f < s->m_figures.size(); f++) { + if (s->m_figures[f]->intersect(r, _t) && _t < t) { + t = _t; + _f = s->m_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); + + is_area_light = false; + // Check if the object is an area light; + for (size_t l = 0; l < s->m_lights.size(); l++) { + if (s->m_lights[l]->light_type() == Light::AREA && static_cast(s->m_lights[l])->m_figure == _f) + is_area_light = true; + } + + // If the object is an area light, return it's emission value. + if (is_area_light) { + return _f->m_mat->m_emission; + + // Check if the material is not reflective/refractive. + } else if (!_f->m_mat->m_refract) { + + // Calculate the direct lighting. + for (size_t l = 0; l < s->m_lights.size(); l++) { + // For every light source + vis = true; + + if (s->m_lights[l]->light_type() == Light::INFINITESIMAL) { + // Cast a shadow ray to determine visibility. + sr = Ray(s->m_lights[l]->direction(i_pos), i_pos + n * BIAS); + for (size_t f = 0; f < s->m_figures.size(); f++) { + if (s->m_figures[f]->intersect(sr, _t) && _t < s->m_lights[l]->distance(i_pos)) { + vis = false; + break; + } + } + + } else if (s->m_lights[l]->light_type() == Light::AREA) { + // Cast a shadow ray towards a sample point on the surface of the light source. + al = static_cast(s->m_lights[l]); + al->sample_at_surface(); + sr = Ray(al->direction(i_pos), i_pos + (n * BIAS)); + + for (size_t f = 0; f < s->m_figures.size(); f++) { + // Avoid self-intersection with the light source. + if (al->m_figure != s->m_figures[f]) { + if (s->m_figures[f]->intersect(sr, _t) && _t < al->distance(i_pos)) { + vis = false; + break; + } + } + } + } + + // Evaluate the shading model accounting for visibility. + dir_diff_color += vis ? s->m_lights[l]->diffuse(n, r, i_pos, *_f->m_mat) : vec3(0.0f); + dir_spec_color += vis ? s->m_lights[l]->specular(n, r, i_pos, *_f->m_mat) : vec3(0.0f); + } + + color += (dir_diff_color * (_f->m_mat->m_diffuse / pi())) + (_f->m_mat->m_specular * dir_spec_color); + + // Determine the specular reflection color. + if (_f->m_mat->m_rho > 0.0f && rec_level < m_max_depth) { + rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); + color += _f->m_mat->m_rho * trace_ray(rr, s, rec_level + 1); + } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth) + return vec3(0.0f); + + } else { + // If the material has transmission enabled, calculate the Fresnel term. + kr = fresnel(r.m_direction, n, r.m_ref_index, _f->m_mat->m_ref_index); + + // Determine the specular reflection color. + if (kr > 0.0f && rec_level < m_max_depth) { + rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); + color += kr * trace_ray(rr, s, rec_level + 1); + } else if (rec_level >= m_max_depth) + return vec3(0.0f); + + // Determine the transmission color. + if (_f->m_mat->m_refract && kr < 1.0f && rec_level < m_max_depth) { + 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 - kr) * trace_ray(rr, s, rec_level + 1); + } else if (rec_level >= m_max_depth) + return vec3(0.0f); + + } + + // Return final color. + return _f->m_mat->m_emission + color; + + } else + return s->m_env->get_color(r); +} + +void PhotonTracer::build_photon_map(Scene * s, const size_t n_photons_per_ligth, const bool specular) { + Light * l; + AreaLight * al; + vec3 l_sample, s_normal, h_sample; + float r1, r2; + Ray rr; + + for (vector::iterator it = s->m_lights.begin(); it != s->m_lights.end(); it++) { + for (size_t p = 0; p < n_photons_per_ligth; p++) { + l = *it; + + /* Only area lights supported right now. */ + if (l->light_type() != Light::AREA) + continue; + + al = static_cast(l); + + if (!specular) { + l_sample = al->sample_at_surface(); + s_normal = al->normal_at_last_sample(); + + r1 = random01(); + r2 = random01(); + h_sample = sample_hemisphere(r1, r2); + rotate_sample(h_sample, s_normal); + rr = Ray(normalize(h_sample), l_sample + (h_sample * BIAS)); + + } else { + // TODO: Generate photon from light source in direction of specular reflective objects. + } + + trace_photon(rr, s, 0, specular); + } + } +} + +vec3 PhotonTracer::trace_photon(Ray &r, Scene * s, const unsigned int rec_level, const bool specular) { + Photon photon; float t, _t; Figure * _f; vec3 n, color, i_pos, ref, sample, dir_diff_color, dir_spec_color, ind_color, amb_color; + Vec3 p_pos; Ray mv_r, sr, rr; bool vis, is_area_light = false; float kr, r1, r2; @@ -46,6 +197,10 @@ vec3 PhotonTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { // If the object is an area light, return it's emission value. if (is_area_light) { + p_pos = Vec3(i_pos.x, i_pos.y, i_pos.z); + photon = Photon(p_pos, _f->m_mat->m_emission.r, _f->m_mat->m_emission.g, _f->m_mat->m_emission.b); + m_photon_map.addPhoton(photon); + return _f->m_mat->m_emission; // Check if the material is not reflective/refractive. @@ -73,7 +228,7 @@ vec3 PhotonTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { } else if (s->m_lights[l]->light_type() == Light::AREA) { // Cast a shadow ray towards a sample point on the surface of the light source. al = static_cast(s->m_lights[l]); - al->sample_at_surface(i_pos); + al->sample_at_surface(); sr = Ray(al->direction(i_pos), i_pos + (n * BIAS)); for (size_t f = 0; f < s->m_figures.size(); f++) { @@ -124,12 +279,14 @@ vec3 PhotonTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { // Add lighting. color += ((dir_diff_color + ind_color + amb_color) * (_f->m_mat->m_diffuse / pi())) + (_f->m_mat->m_specular * dir_spec_color); - // Determine the specular reflection color. - if (_f->m_mat->m_rho > 0.0f && rec_level < m_max_depth) { - rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); - color += _f->m_mat->m_rho * trace_ray(rr, s, rec_level + 1); - } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth) + if (specular) { + // Determine the specular reflection color. + if (_f->m_mat->m_rho > 0.0f && rec_level < m_max_depth) { + rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); + color += _f->m_mat->m_rho * trace_ray(rr, s, rec_level + 1); + } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth) return vec3(0.0f); + } } else { // If the material has transmission enabled, calculate the Fresnel term. @@ -151,30 +308,15 @@ vec3 PhotonTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { } + color += _f->m_mat->m_emission; + + p_pos = Vec3(i_pos.x, i_pos.y, i_pos.z); + photon = Photon(p_pos, color.r, color.g, color.b); + m_photon_map.addPhoton(photon); + // Return final color. - return _f->m_mat->m_emission + color; + return color; } else return s->m_env->get_color(r); } - -void PhotonTracer::build_photon_map(kdTree & photon_map, Scene * s, const unsigned int rec_level, const size_t n_photons_per_ligth, const bool specular) const { - Light * l; - Photon photon; - - - for (vector::iterator it = s->m_lights.begin(); it != s->m_lights.end(); it++) { - for (size_t p = 0; p < n_photons_per_ligth; p++) { - l = *it; - - if (!specular) { - // TODO: Generate photon from light source. - } else { - // TODO: Generate photon from light source in direction of specular reflective objects. - } - // TODO: Trace indirect illumination for the generated sample. - - photon_map.addPhoton(photon); - } - } -} diff --git a/photon_tracer.hpp b/photon_tracer.hpp index c5154ee..f582ece 100644 --- a/photon_tracer.hpp +++ b/photon_tracer.hpp @@ -8,14 +8,16 @@ class PhotonTracer: public Tracer { public: PhotonTracer(): Tracer() { } - PhotonTracer(unsigned int max_depth): Tracer(max_depth) { }; virtual ~PhotonTracer(); - virtual vec3 trace_ray(Ray & r, Scene * s, unsigned int rec_level) const; - void build_photon_map(kdTree & photon_map, Scene * s, const unsigned int rec_level, const size_t n_photons_per_ligth = 10000, const bool specular = false) const; + void build_photon_map(Scene * s, const size_t n_photons_per_ligth = 10000, const bool specular = false); + +private: + kdTree m_photon_map; + vec3 trace_photon(Ray &r, Scene * s, const unsigned int rec_level, const bool specular = false); }; #endif diff --git a/sphere_area_light.cpp b/sphere_area_light.cpp index d8891d3..8cc22c0 100644 --- a/sphere_area_light.cpp +++ b/sphere_area_light.cpp @@ -1,7 +1,8 @@ #include "sphere_area_light.hpp" -void SphereAreaLight::sample_at_surface(vec3 point) { +vec3 SphereAreaLight::sample_at_surface() { Sphere * s = static_cast(m_figure); m_last_sample = m_figure->sample_at_surface(); m_n_at_last_sample = normalize(vec3((m_last_sample - s->m_center) / s->m_radius)); + return m_last_sample; } diff --git a/sphere_area_light.hpp b/sphere_area_light.hpp index 0d0ed9d..23e2951 100644 --- a/sphere_area_light.hpp +++ b/sphere_area_light.hpp @@ -9,7 +9,7 @@ class SphereAreaLight: public AreaLight { public: SphereAreaLight(Sphere * _s, float _c = 1.0, float _l = 0.0, float _q = 0.0): AreaLight(static_cast
(_s), _c, _l, _q) { } - virtual void sample_at_surface(vec3 point); + virtual vec3 sample_at_surface(); }; #endif diff --git a/whitted_tracer.cpp b/whitted_tracer.cpp index 3c56be6..b7b7a06 100644 --- a/whitted_tracer.cpp +++ b/whitted_tracer.cpp @@ -69,7 +69,7 @@ vec3 WhittedTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const } else if (s->m_lights[l]->light_type() == Light::AREA) { // Cast a shadow ray towards a sample point on the surface of the light source. al = static_cast(s->m_lights[l]); - al->sample_at_surface(i_pos); + al->sample_at_surface(); sr = Ray(al->direction(i_pos), i_pos + (n * BIAS)); for (size_t f = 0; f < s->m_figures.size(); f++) {