diff --git a/.gitignore b/.gitignore index 52efb26..7a3155a 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,6 @@ ray # Others +textures/ *.d *~ diff --git a/Makefile b/Makefile index 250efd9..636239c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CXX = g++ TARGET = ray -OBJECTS = main.o sampling.o camera.o disk.o plane.o sphere.o phong_brdf.o hsa_brdf.o directional_light.o point_light.o spot_light.o tracer.o path_tracer.o whitted_tracer.o +OBJECTS = main.o sampling.o camera.o environment.o disk.o plane.o sphere.o phong_brdf.o hsa_brdf.o directional_light.o point_light.o spot_light.o tracer.o path_tracer.o whitted_tracer.o DEPENDS = $(OBJECTS:.o=.d) CXXFLAGS = -ansi -pedantic -Wall -DGLM_FORCE_RADIANS -fopenmp LDLIBS = -lfreeimage diff --git a/TODO.org b/TODO.org index b87f29e..1034b39 100644 --- a/TODO.org +++ b/TODO.org @@ -1,4 +1,4 @@ -* Features [9/20] +* Features [12/20] - [X] Perspective projection - [X] Ray-sphere intersection @@ -15,15 +15,15 @@ - [ ] Area lights - [ ] Sphere lights - [ ] Box/planar lights - - [ ] Mesh lights - [X] Phong shading - [X] Specular reflections - [X] Transmission - [ ] Scene description input files (JSON) - [X] Indirect illumination - - [ ] Russian roulette - - [ ] Image based lightning - - [ ] HDR light probes for IBL - - [ ] Tone mapping + - [ ] Glossy reflections + - [X] Image based lighting + - [X] HDR light probes for IBL + - [X] Tone mapping - [ ] Texture mapping - [ ] Photon mapping + diff --git a/environment.cpp b/environment.cpp new file mode 100644 index 0000000..1c4cfd0 --- /dev/null +++ b/environment.cpp @@ -0,0 +1,38 @@ +#include + +#include +#include + +#include "environment.hpp" + +using glm::vec2; +using glm::acos; +using glm::pi; + +vec3 Environment::get_color(Ray & r) { + float _r; + vec2 tex_coord; + BYTE * bits; + FIRGBF * pixel; + unsigned int pitch; + + if (m_texture == NULL) + return m_bckg_color; + else { + if (!m_probe) { + tex_coord = vec2((1.0f + atan2(r.m_direction.x, -r.m_direction.z) / pi()) / 2.0f, acos(r.m_direction.y) / pi()); + tex_coord = vec2(tex_coord.x, 1.0f - tex_coord.y); + } else { + _r = (1.0f / pi()) * acos(r.m_direction.z) / glm::sqrt((r.m_direction.x * r.m_direction.x) + (r.m_direction.y * r.m_direction.y)); + tex_coord = vec2(r.m_direction.x * _r, r.m_direction.y * _r); + tex_coord += vec2(1.0f, 1.0f); + tex_coord /= 2.0f; + } + + tex_coord *= vec2(FreeImage_GetWidth(m_texture) - 1, FreeImage_GetHeight(m_texture) - 1); + pitch = FreeImage_GetPitch(m_texture); + bits = ((BYTE *)FreeImage_GetBits(m_texture)) + (static_cast(tex_coord.y) * pitch); + pixel = (FIRGBF *)bits; + return vec3(pixel[static_cast(tex_coord.x)].red, pixel[static_cast(tex_coord.x)].green, pixel[static_cast(tex_coord.x)].blue); + } +} diff --git a/environment.hpp b/environment.hpp new file mode 100644 index 0000000..549e412 --- /dev/null +++ b/environment.hpp @@ -0,0 +1,37 @@ +#pragma once +#ifndef ENVIRONMENT_HPP +#define ENVIRONMENT_HPP + +#include +#include + +#include "ray.hpp" + +using glm::vec3; + +class Environment { +public: + Environment(const char * tex_file = NULL, bool light_probe = false, vec3 bckg = vec3(1.0f)): m_bckg_color(bckg), m_probe(light_probe) { + FREE_IMAGE_FORMAT fif; + + if (tex_file != NULL) { + fif = FreeImage_GetFIFFromFilename(tex_file); + m_texture = FreeImage_Load(fif, tex_file, 0); + } else + m_texture = NULL; + } + + ~Environment() { + if (m_texture != NULL) + FreeImage_Unload(m_texture); + } + + vec3 get_color(Ray & r); + +private: + vec3 m_bckg_color; + FIBITMAP * m_texture; + bool m_probe; +}; + +#endif diff --git a/main.cpp b/main.cpp index d37bbec..1e88ab6 100644 --- a/main.cpp +++ b/main.cpp @@ -27,6 +27,7 @@ #include "brdf.hpp" #include "phong_brdf.hpp" #include "hsa_brdf.hpp" +#include "environment.hpp" using namespace std; using namespace glm; @@ -40,10 +41,10 @@ using namespace glm; //////////////////////////////////////////// // Function prototypes. //////////////////////////////////////////// -static void scene_1(vector
& vf, vector & vl, Camera * c); -static void scene_2(vector
& vf, vector & vl, Camera * c); -static void scene_3(vector
& vf, vector & vl, Camera * c); -static void scene_4(vector
& vf, vector & vl, Camera * c); +static void scene_1(vector
& vf, vector & vl, Environment * & e, Camera * c); +static void scene_2(vector
& vf, vector & vl, Environment * & e, Camera * c); +static void scene_3(vector
& vf, vector & vl, Environment * & e, Camera * c); +static void scene_4(vector
& vf, vector & vl, Environment * & e, Camera * c); static void print_usage(char ** const argv); static void parse_args(int argc, char ** const argv); @@ -87,6 +88,7 @@ int main(int argc, char ** argv) { FIRGBF *pixel; int pitch; Camera * cam; + Environment * env = NULL; parse_args(argc, argv); @@ -100,7 +102,7 @@ int main(int argc, char ** argv) { image[i] = new vec3[g_w]; } - scene_2(figures, lights, cam); + scene_3(figures, lights, env, cam); // Create the tracer object. cout << "Rendering the input file: " << ANSI_BOLD_YELLOW << g_input_file << ANSI_RESET_STYLE << endl; @@ -136,7 +138,7 @@ int main(int argc, char ** argv) { sample = cam->sample_pixel(i, j); r = Ray(normalize(vec3(sample, -0.5f) - vec3(0.0f)), vec3(0.0f)); cam->view_to_world(r); - image[i][j] += tracer->trace_ray(r, figures, lights, 0); + image[i][j] += tracer->trace_ray(r, figures, lights, env, 0); #pragma omp atomic current++; } @@ -176,6 +178,8 @@ int main(int argc, char ** argv) { delete cam; delete tracer; + if (env != NULL) + delete env; for (size_t i = 0; i < figures.size(); i++) { delete figures[i]; @@ -344,12 +348,14 @@ void parse_args(int argc, char ** const argv) { } } -void scene_1(vector
& vf, vector & vl, Camera * c) { +void scene_1(vector
& vf, vector & vl, Environment * & e, Camera * c) { Sphere * s; Plane * p; Disk * d; DirectionalLight * l; + e = new Environment(NULL, false, vec3(0.7f, 0.4f, 0.05f)); + s = new Sphere(1.0f, 1.0f, -2.0f, 0.5f); s->m_mat->m_diffuse = vec3(1.0f, 0.0f, 0.0f); vf.push_back(static_cast
(s)); @@ -419,7 +425,7 @@ void scene_1(vector
& vf, vector & vl, Camera * c) { vl.push_back(static_cast(l)); } -void scene_2(vector
& vf, vector & vl, Camera * c) { +void scene_2(vector
& vf, vector & vl, Environment * & e, Camera * c) { Sphere * s; Plane * p; Disk * d; @@ -493,15 +499,17 @@ void scene_2(vector
& vf, vector & vl, Camera * c) { vl.push_back(static_cast(l)); } -void scene_3(vector
& vf, vector & vl, Camera * c) { +void scene_3(vector
& vf, vector & vl, Environment * & e, Camera * c) { Sphere * s; - Plane * p; - SpotLight * l; - DirectionalLight * l2; - vec3 eye = vec3(0.0f, 1.5f, 0.0f); + Disk * d; + // SpotLight * l; + // DirectionalLight * l2; + vec3 eye = vec3(0.0f, 1.5f, 1.0f); vec3 center = vec3(0.0f, 0.0f, -2.0f); vec3 left = vec3(-1.0f, 0.0f, 0.0f); + e = new Environment("textures/pisa.hdr"); + c->m_eye = eye; c->m_look = center; c->m_up = cross(normalize(center - eye), left); @@ -525,39 +533,44 @@ void scene_3(vector
& vf, vector & vl, Camera * c) { // s->m_mat->m_ref_index = 2.6f; // vf.push_back(static_cast
(s)); - s = new Sphere(2.0f, 0.0f, -2.0f, 1.0f, new HeidrichSeidelAnisotropicBRDF(vec3(0.0f, 1.0f, 0.0f))); + s = new Sphere(2.0f, 0.0f, -2.0f, 1.5f, new HeidrichSeidelAnisotropicBRDF(vec3(0.0f, 1.0f, 0.0f))); s->m_mat->m_diffuse = vec3(1.0f, 1.0f, 0.0f); s->m_mat->m_shininess = 128.0f; vf.push_back(static_cast
(s)); - s = new Sphere(-1.0f, 0.0f, -3.25f, 1.0f); + s = new Sphere(-1.0f, 0.0f, -3.25f, 1.5f); s->m_mat->m_diffuse = vec3(1.0f, 0.0f, 1.0f); s->m_mat->m_rho = 0.4f; vf.push_back(static_cast
(s)); - p = new Plane(vec3(0.0f, -1.5f, 0.0f), vec3(0.0f, 1.0f, 0.0f)); - p->m_mat->m_diffuse = vec3(1.0f); - p->m_mat->m_specular = vec3(0.0f); - vf.push_back(static_cast
(p)); + s = new Sphere(1.0f, 0.0f, -3.25f, 1.5f); + s->m_mat->m_diffuse = vec3(1.0f); + s->m_mat->m_rho = 0.4f; + vf.push_back(static_cast
(s)); + + d = new Disk(vec3(1.0f, -1.5f, -3.25f), vec3(0.0f, 1.0f, 0.0f), 3.0f); + d->m_mat->m_diffuse = vec3(0.0f, 0.5f, 0.5f); + d->m_mat->m_specular = vec3(0.0f); + vf.push_back(static_cast
(d)); + + // l = new SpotLight(); + // l->m_position = normalize(vec3(-2.0f, 1.5f, -1.0f)); + // l->m_diffuse = vec3(1.0f, 1.0f, 0.0f); + // l->m_spot_dir = normalize(vec3(0.5f, 0.0f, -2.5f) - vec3(-2.0f, 1.5f, -1.0f)); + // l->m_spot_cutoff = 89.0f; + // l->m_spot_exponent = 10.0f; + // vl.push_back(static_cast(l)); - l = new SpotLight(); - l->m_position = normalize(vec3(-2.0f, 1.5f, -1.0f)); - l->m_diffuse = vec3(1.0f, 1.0f, 0.0f); - l->m_spot_dir = normalize(vec3(0.5f, 0.0f, -2.5f) - vec3(-2.0f, 1.5f, -1.0f)); - l->m_spot_cutoff = 89.0f; - l->m_spot_exponent = 10.0f; - vl.push_back(static_cast(l)); + // l2 = new DirectionalLight(); + // l2->m_position = normalize(vec3(-1.0f, 0.7f, 1.0f)); + // l2->m_diffuse = vec3(1.0f, 1.0f, 1.0f); + // vl.push_back(static_cast(l2)); - l2 = new DirectionalLight(); - l2->m_position = normalize(vec3(-1.0f, 0.7f, 1.0f)); - l2->m_diffuse = vec3(1.0f, 1.0f, 1.0f); - vl.push_back(static_cast(l2)); - - l2 = new DirectionalLight(); - l2->m_position = normalize(vec3(-0.5f, 0.7f, 1.0f)); - l2->m_diffuse = vec3(0.0f, 0.0f, 1.0f); - l2->m_specular = vec3(0.0f, 0.0f, 1.0f); - vl.push_back(static_cast(l2)); + // l2 = new DirectionalLight(); + // l2->m_position = normalize(vec3(-0.5f, 0.7f, 1.0f)); + // l2->m_diffuse = vec3(0.0f, 0.0f, 1.0f); + // l2->m_specular = vec3(0.0f, 0.0f, 1.0f); + // vl.push_back(static_cast(l2)); // l = new DirectionalLight(); // l->m_position = normalize(vec3(1.0f, 0.0f, 1.0f)); @@ -565,12 +578,15 @@ void scene_3(vector
& vf, vector & vl, Camera * c) { // vl.push_back(static_cast(l)); } -void scene_4(vector
& vf, vector & vl, Camera * c) { +void scene_4(vector
& vf, vector & vl, Environment * & e, Camera * c) { Sphere * s; Plane * p; + e = new Environment("textures/pisa.hdr"); + s = new Sphere(0.0f, 0.0f, -2.0f, 1.0f); - s->m_mat->m_diffuse = vec3(1.0f, 1.0f, 0.0f); + s->m_mat->m_diffuse = vec3(1.0f); + s->m_mat->m_rho = 0.3f; vf.push_back(static_cast
(s)); p = new Plane(vec3(0.0f, -1.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f)); diff --git a/output.png b/output.png index c6a041d..6992842 100644 Binary files a/output.png and b/output.png differ diff --git a/path_tracer.cpp b/path_tracer.cpp index 49c35b2..59afaad 100644 --- a/path_tracer.cpp +++ b/path_tracer.cpp @@ -10,7 +10,7 @@ using namespace glm; PathTracer::~PathTracer() { } -vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const { +vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, Environment * e, 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, amb_color; @@ -63,36 +63,35 @@ vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vector 0.0f || BCKG_COLOR.g > 0.0f || BCKG_COLOR.b > 0.0f) { - vis = true; + vis = true; - r1 = random01(); - r2 = random01(); - sample = sample_hemisphere(r1, r2); - rotate_sample(sample, n); - rr = Ray(normalize(sample), i_pos + (sample * BIAS)); + r1 = random01(); + r2 = random01(); + sample = sample_hemisphere(r1, r2); + rotate_sample(sample, n); + rr = Ray(normalize(sample), i_pos + (sample * BIAS)); - // Cast a shadow ray to determine visibility. - for (size_t f = 0; f < v_figures.size(); f++) { - if (v_figures[f]->intersect(rr, _t)) { - vis = false; - break; - } + // Cast a shadow ray to determine visibility. + for (size_t f = 0; f < v_figures.size(); f++) { + if (v_figures[f]->intersect(rr, _t)) { + vis = false; + break; } - - amb_color = vis ? BCKG_COLOR * max(dot(n, rr.m_direction), 0.0f) / PDF : vec3(0.0f); } - + + amb_color = vis ? e->get_color(rr) * max(dot(n, rr.m_direction), 0.0f) / PDF : vec3(0.0f); + + // 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, v_figures, v_lights, rec_level + 1); + color += _f->m_mat->m_rho * trace_ray(rr, v_figures, v_lights, e, rec_level + 1); } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth) return vec3(0.0f); @@ -103,14 +102,14 @@ vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vector 0.0f && rec_level < m_max_depth) { rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); - color += kr * trace_ray(rr, v_figures, v_lights, rec_level + 1); + color += kr * trace_ray(rr, v_figures, v_lights, e, 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, v_figures, v_lights, rec_level + 1); + color += (1.0f - kr) * trace_ray(rr, v_figures, v_lights, e, rec_level + 1); } else if (rec_level >= m_max_depth) return vec3(0.0f); @@ -119,6 +118,10 @@ vec3 PathTracer::trace_ray(Ray & r, vector
& v_figures, vectorget_color(r); + else + return vec3(0.0f); + } } diff --git a/path_tracer.hpp b/path_tracer.hpp index 4f4f589..f4853f6 100644 --- a/path_tracer.hpp +++ b/path_tracer.hpp @@ -12,7 +12,7 @@ public: virtual ~PathTracer(); - virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const; + virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, Environment * e, unsigned int rec_level) const; }; #endif diff --git a/tracer.hpp b/tracer.hpp index 871a5df..bf6107b 100644 --- a/tracer.hpp +++ b/tracer.hpp @@ -8,6 +8,7 @@ #include "figure.hpp" #include "light.hpp" +#include "environment.hpp" #include "ray.hpp" using std::vector; @@ -28,7 +29,7 @@ public: virtual ~Tracer() { } - virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const = 0; + virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, Environment * e, unsigned int rec_level) const = 0; protected: float fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) const; diff --git a/whitted_tracer.cpp b/whitted_tracer.cpp index da402da..957f29e 100644 --- a/whitted_tracer.cpp +++ b/whitted_tracer.cpp @@ -9,7 +9,7 @@ using namespace glm; WhittedTracer::~WhittedTracer() { } -vec3 WhittedTracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const { +vec3 WhittedTracer::trace_ray(Ray & r, vector
& v_figures, vector & v_lights, Environment * e, unsigned int rec_level) const { float t, _t; Figure * _f; vec3 n, color, i_pos, ref, dir_diff_color, dir_spec_color; @@ -60,7 +60,7 @@ vec3 WhittedTracer::trace_ray(Ray & r, vector
& v_figures, vectorm_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, v_figures, v_lights, rec_level + 1); + color += _f->m_mat->m_rho * trace_ray(rr, v_figures, v_lights, e, rec_level + 1); } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth) return vec3(0.0f); @@ -71,14 +71,14 @@ vec3 WhittedTracer::trace_ray(Ray & r, vector
& v_figures, vector 0.0f && rec_level < m_max_depth) { rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS); - color += kr * trace_ray(rr, v_figures, v_lights, rec_level + 1); + color += kr * trace_ray(rr, v_figures, v_lights, e, 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, v_figures, v_lights, rec_level + 1); + color += (1.0f - kr) * trace_ray(rr, v_figures, v_lights, e, rec_level + 1); } else if (rec_level >= m_max_depth) return vec3(0.0f); @@ -87,6 +87,10 @@ vec3 WhittedTracer::trace_ray(Ray & r, vector
& v_figures, vectorget_color(r); + else + return vec3(0.0f); + } } diff --git a/whitted_tracer.hpp b/whitted_tracer.hpp index e781266..00692c1 100644 --- a/whitted_tracer.hpp +++ b/whitted_tracer.hpp @@ -12,7 +12,7 @@ public: virtual ~WhittedTracer(); - virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, unsigned int rec_level) const; + virtual vec3 trace_ray(Ray & r, vector
& v_figures, vector & v_lights, Environment * e, unsigned int rec_level) const; }; #endif