diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a58964..3636658 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,8 @@ cmake_minimum_required(VERSION 3.10) project(snoopy) -file(GLOB snoopy_src - "src/*.h" - "src/*.cpp" -) +include_directories("include") +file(GLOB SOURCES "src/*.cpp") -add_executable(snoopy ${snoopy_src}) +add_executable(snoopy ${SOURCES}) diff --git a/include/camera.h b/include/camera.h new file mode 100644 index 0000000..0f68329 --- /dev/null +++ b/include/camera.h @@ -0,0 +1,52 @@ +#pragma once + +#include "rtweekend.h" +#include "image.h" + +class camera +{ + public: + camera( + point3 lookfrom, + point3 lookat, + vec3 vup, + double vfov, // vertical field of view in degrees + double aspect_ratio, + double aperture, + double focus_dist) + { + auto theta = degrees_to_radians(vfov); + auto h = tan(theta/2); + auto viewport_height = 2.0 * h; + auto viewport_width = aspect_ratio * viewport_height; + + w_ = unit_vector(lookfrom - lookat); + u_ = unit_vector(cross(vup, w_)); + v_ = cross(w_, u_); + + origin_ = lookfrom; + horizontal_ = focus_dist * viewport_width * u_; + vertical_ = focus_dist * viewport_height * v_; + lower_left_corner_ = origin_ - horizontal_/2 - vertical_/2 - focus_dist * w_; + + lens_radius_ = aperture / 2; + } + + ray get_ray(double s, double t) const + { + vec3 rd = lens_radius_ * random_in_unit_disk(); + vec3 offset = (u_ * rd.x()) + (v_ * rd.y()); + + return ray( + origin_ + offset, + lower_left_corner_ + s*horizontal_ + t*vertical_ - origin_ - offset); + } + + private: + point3 origin_; + point3 lower_left_corner_; + vec3 horizontal_; + vec3 vertical_; + vec3 u_, v_, w_; + double lens_radius_; +}; diff --git a/src/colour.h b/include/colour.h similarity index 85% rename from src/colour.h rename to include/colour.h index 4d46604..e54e5a2 100755 --- a/src/colour.h +++ b/include/colour.h @@ -26,6 +26,11 @@ void correct_gamma(colour& pixel_colour, int samples) pixel_colour = colour(r, g, b); } +int format_component(double component) +{ + return int(256 * math::clamp(component, 0.0, 0.999)); +} + void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel) { correct_gamma(pixel_colour, samples_per_pixel); @@ -35,14 +40,9 @@ void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_ auto b = pixel_colour.z(); // write the translated [0,255] value of each colour component. - out << static_cast(256 * clamp(r, 0.0, 0.999)) << ' ' - << static_cast(256 * clamp(g, 0.0, 0.999)) << ' ' - << static_cast(256 * clamp(b, 0.0, 0.999)) << '\n'; -} - -int format_component(double component) -{ - return int(256 * clamp(component, 0.0, 0.999)); + out << format_component(r) << ' ' + << format_component(g) << ' ' + << format_component(b) << '\n'; } void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel) diff --git a/src/error.h b/include/error.h similarity index 100% rename from src/error.h rename to include/error.h diff --git a/include/foo.h b/include/foo.h new file mode 100644 index 0000000..604782e --- /dev/null +++ b/include/foo.h @@ -0,0 +1 @@ +#include diff --git a/src/hittable.h b/include/hittable.h similarity index 100% rename from src/hittable.h rename to include/hittable.h diff --git a/src/hittable_list.h b/include/hittable_list.h similarity index 100% rename from src/hittable_list.h rename to include/hittable_list.h diff --git a/src/image.h b/include/image.h similarity index 100% rename from src/image.h rename to include/image.h diff --git a/src/material.h b/include/material.h similarity index 81% rename from src/material.h rename to include/material.h index 895b06b..fb8f666 100644 --- a/src/material.h +++ b/include/material.h @@ -31,7 +31,7 @@ class lambertian : public material colour& attenuation, ray& scattered) const { - vec3 scatter_direction = rec.normal + random_unit_vector(); + vec3 scatter_direction = rec.normal + vec3::random_unit_vector(); scattered = ray(rec.p, scatter_direction); attenuation = albedo_; return true; @@ -54,8 +54,8 @@ class metal : public material colour& attenuation, ray& scattered) const { - vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); - scattered = ray(rec.p, reflected + fuzz_*random_in_unit_sphere()); + vec3 reflected = vec3::reflect(unit_vector(r_in.direction()), rec.normal); + scattered = ray(rec.p, reflected + fuzz_ * vec3::random_in_unit_sphere()); attenuation = albedo_; return dot(scattered.direction(), rec.normal) > 0; } @@ -85,20 +85,20 @@ class dielectric : public material double sin_theta = sqrt(1.0 - cos_theta*cos_theta); if (etai_over_etat * sin_theta > 1.0) { - vec3 reflected = reflect(unit_direction, rec.normal); + vec3 reflected = vec3::reflect(unit_direction, rec.normal); scattered = ray(rec.p, reflected); return true; } double reflect_prob = schlick(cos_theta, etai_over_etat); - if (random_double() < reflect_prob) + if (math::random_double() < reflect_prob) { - vec3 reflected = reflect(unit_direction, rec.normal); + vec3 reflected = vec3::reflect(unit_direction, rec.normal); scattered = ray(rec.p, reflected); return true; } - vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat); + vec3 refracted = vec3::refract(unit_direction, rec.normal, etai_over_etat); scattered = ray(rec.p, refracted); return true; diff --git a/include/math.h b/include/math.h new file mode 100644 index 0000000..e8fbc79 --- /dev/null +++ b/include/math.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class math +{ +public: + static constexpr double infinity = std::numeric_limits::infinity(); + static constexpr double pi = 3.1415926535897932385; + + static double degrees_to_radians(double degrees); + static double random_double(); + static double random_double(double min, double max); + static double clamp(double x, double min, double max); +}; diff --git a/src/ray.h b/include/ray.h similarity index 100% rename from src/ray.h rename to include/ray.h diff --git a/include/rtweekend.h b/include/rtweekend.h new file mode 100644 index 0000000..e5ae6a2 --- /dev/null +++ b/include/rtweekend.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include +#include + +// usings + +using std::shared_ptr; +using std::make_shared; +using std::sqrt; + +// common headers + +#include "error.h" +#include "ray.h" +#include "vec3.h" diff --git a/src/scene.h b/include/scene.h similarity index 97% rename from src/scene.h rename to include/scene.h index 33acf32..dba330b 100644 --- a/src/scene.h +++ b/include/scene.h @@ -1,5 +1,6 @@ #pragma once +#include "math.h" #include "sphere.h" #include "colour.h" #include "material.h" @@ -14,7 +15,7 @@ colour ray_colour(const ray& r, const hittable& world, int depth) return grey; } - if (world.hit(r, 0.001, infinity, rec)) + if (world.hit(r, 0.001, math::infinity, rec)) { ray scattered; colour attenuation; diff --git a/src/sphere.h b/include/sphere.h similarity index 100% rename from src/sphere.h rename to include/sphere.h diff --git a/src/vec3.h b/include/vec3.h similarity index 65% rename from src/vec3.h rename to include/vec3.h index d76dcff..061c222 100755 --- a/src/vec3.h +++ b/include/vec3.h @@ -1,23 +1,28 @@ #pragma once -#include #include -#include "rtweekend.h" +#include "math.h" class vec3 { public: inline static vec3 random() { - return vec3(random_double(),random_double(),random_double()); + return vec3(math::random_double(),math::random_double(),math::random_double()); } inline static vec3 random(double min, double max) { - return vec3(random_double(min,max),random_double(min,max),random_double(min,max)); + return vec3(math::random_double(min,max),math::random_double(min,max),math::random_double(min,max)); } + static vec3 random_in_unit_disk(); + static vec3 random_unit_vector(); + static vec3 random_in_unit_sphere(); + static vec3 reflect(const vec3& v, const vec3& n); + static vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat); + vec3() : e{0,0,0} {} vec3(double e0, double e1, double e2) : e{e0, e1, e2} {} @@ -129,57 +134,3 @@ inline vec3 unit_vector(vec3 v) return v / v.length(); } -vec3 random_in_unit_sphere() -{ - while (true) - { - auto p = vec3::random(-1,1); - if (p.length_squared() >= 1) continue; - return p; - } -} - -vec3 random_unit_vector() -{ - auto a = random_double(0, 2*pi); - auto z = random_double(-1,1); - auto r = sqrt(1 - z*z); - return vec3(r*cos(a), r*sin(a), z); -} - -vec3 random_in_hemisphere(const vec3& normal) -{ - vec3 in_unit_sphere = random_in_unit_sphere(); - if (dot(in_unit_sphere, normal) > 0.0) - { - return in_unit_sphere; - } - else - { - return -in_unit_sphere; - } -} - -vec3 random_in_unit_disk() -{ - while(true) - { - auto p = vec3(random_double(-1,1), random_double(-1,1), 0); - if (p.length_squared() >= 1) continue; - return p; - } -} - -vec3 reflect(const vec3& v, const vec3& n) -{ - return v - 2*dot(v,n)*n; -} - -vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat) -{ - auto cos_theta = dot(-uv, n); - vec3 r_out_parallel = etai_over_etat * (uv + cos_theta*n); - vec3 r_out_perp = -sqrt(1.0 - r_out_parallel.length_squared()) * n; - - return r_out_parallel + r_out_perp; -} diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..08151c7 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,38 @@ +#include "math.h" +#include "camera.h" + +camera::camera( + point3 lookfrom, + point3 lookat, + vec3 vup, + double vfov, // vertical field of view in degrees + double aspect_ratio, + double aperture, + double focus_dist) +{ + auto theta = math::degrees_to_radians(vfov); + auto h = tan(theta/2); + auto viewport_height = 2.0 * h; + auto viewport_width = aspect_ratio * viewport_height; + + w_ = unit_vector(lookfrom - lookat); + u_ = unit_vector(cross(vup, w_)); + v_ = cross(w_, u_); + + origin_ = lookfrom; + horizontal_ = focus_dist * viewport_width * u_; + vertical_ = focus_dist * viewport_height * v_; + lower_left_corner_ = origin_ - horizontal_/2 - vertical_/2 - focus_dist * w_; + + lens_radius_ = aperture / 2; +} + +ray camera::get_ray(double s, double t) const +{ + vec3 rd = lens_radius_ * vec3::random_in_unit_disk(); + vec3 offset = (u_ * rd.x()) + (v_ * rd.y()); + + return ray( + origin_ + offset, + lower_left_corner_ + s*horizontal_ + t*vertical_ - origin_ - offset); +} diff --git a/src/camera.h b/src/camera.h index 0f68329..f8b423f 100644 --- a/src/camera.h +++ b/src/camera.h @@ -1,52 +1,29 @@ #pragma once -#include "rtweekend.h" +#include "math.h" +#include "vec3.h" +#include "ray.h" #include "image.h" class camera { - public: - camera( - point3 lookfrom, - point3 lookat, - vec3 vup, - double vfov, // vertical field of view in degrees - double aspect_ratio, - double aperture, - double focus_dist) - { - auto theta = degrees_to_radians(vfov); - auto h = tan(theta/2); - auto viewport_height = 2.0 * h; - auto viewport_width = aspect_ratio * viewport_height; +public: + camera( + point3 lookfrom, + point3 lookat, + vec3 vup, + double vfov, // vertical field of view in degrees + double aspect_ratio, + double aperture, + double focus_dist); - w_ = unit_vector(lookfrom - lookat); - u_ = unit_vector(cross(vup, w_)); - v_ = cross(w_, u_); + ray get_ray(double s, double t) const; - origin_ = lookfrom; - horizontal_ = focus_dist * viewport_width * u_; - vertical_ = focus_dist * viewport_height * v_; - lower_left_corner_ = origin_ - horizontal_/2 - vertical_/2 - focus_dist * w_; - - lens_radius_ = aperture / 2; - } - - ray get_ray(double s, double t) const - { - vec3 rd = lens_radius_ * random_in_unit_disk(); - vec3 offset = (u_ * rd.x()) + (v_ * rd.y()); - - return ray( - origin_ + offset, - lower_left_corner_ + s*horizontal_ + t*vertical_ - origin_ - offset); - } - - private: - point3 origin_; - point3 lower_left_corner_; - vec3 horizontal_; - vec3 vertical_; - vec3 u_, v_, w_; - double lens_radius_; +private: + point3 origin_; + point3 lower_left_corner_; + vec3 horizontal_; + vec3 vertical_; + vec3 u_, v_, w_; + double lens_radius_; }; diff --git a/src/foo.cpp b/src/foo.cpp new file mode 100644 index 0000000..f4de601 --- /dev/null +++ b/src/foo.cpp @@ -0,0 +1 @@ +#include "foo.h" diff --git a/src/main.cpp b/src/main.cpp index 527ca97..9da9c1a 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -117,8 +117,8 @@ void render(camera& cam, hittable_list& world, int client_sock) for (int s = 0; s < SAMPLES_PER_PIXEL; ++s) { - auto u = (i + random_double()) / (WIDTH-1); - auto v = (j + random_double()) / (HEIGHT-1); + auto u = (i + math::random_double()) / (WIDTH-1); + auto v = (j + math::random_double()) / (HEIGHT-1); ray r = cam.get_ray(u, v); pixel_colour += ray_colour(r, world, MAX_DEPTH); } diff --git a/src/math.cpp b/src/math.cpp new file mode 100644 index 0000000..b16754a --- /dev/null +++ b/src/math.cpp @@ -0,0 +1,25 @@ +#include "math.h" + +double math::random_double() +{ + // returns a random real in [0,1) + return rand() / (RAND_MAX + 1.0); +} + +double math::random_double(double min, double max) +{ + // returns a random real in [min,max) + return min + (max-min)*math::random_double(); +} + +double math::degrees_to_radians(double degrees) +{ + return degrees * math::pi / 180; +} + +double math::clamp(double x, double min, double max) +{ + if (x < min) return min; + if (x > max) return max; + return x; +} diff --git a/src/rtweekend.h b/src/rtweekend.h deleted file mode 100644 index e79e95a..0000000 --- a/src/rtweekend.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// usings - -using std::shared_ptr; -using std::make_shared; -using std::sqrt; - -// constants - -const double infinity = std::numeric_limits::infinity(); -const double pi = 3.1415926535897932385; - -// utility functions -inline double degrees_to_radians(double degrees) -{ - return degrees * pi / 180; -} - -inline double random_double() -{ - // returns a random real in [0,1) - return rand() / (RAND_MAX + 1.0); -} - -inline double random_double(double min, double max) -{ - // returns a random real in [min,max) - return min + (max-min)*random_double(); -} - -inline double clamp(double x, double min, double max) -{ - if (x < min) return min; - if (x > max) return max; - return x; -} - -// common headers - -#include "error.h" -#include "ray.h" -#include "vec3.h" diff --git a/src/vec3.cpp b/src/vec3.cpp new file mode 100644 index 0000000..08fd529 --- /dev/null +++ b/src/vec3.cpp @@ -0,0 +1,57 @@ +#include "vec3.h" + +vec3 vec3::random_unit_vector() +{ + auto a = math::random_double(0, 2 * math::pi); + auto z = math::random_double(-1,1); + auto r = sqrt(1 - z*z); + return vec3(r*cos(a), r*sin(a), z); +} + +vec3 vec3::reflect(const vec3& v, const vec3& n) +{ + return v - 2*dot(v,n)*n; +} + +vec3 vec3::refract(const vec3& uv, const vec3& n, double etai_over_etat) +{ + auto cos_theta = dot(-uv, n); + vec3 r_out_parallel = etai_over_etat * (uv + cos_theta*n); + vec3 r_out_perp = -sqrt(1.0 - r_out_parallel.length_squared()) * n; + + return r_out_parallel + r_out_perp; +} + +vec3 vec3::random_in_unit_disk() +{ + while(true) + { + auto p = vec3(math::random_double(-1,1), math::random_double(-1,1), 0); + if (p.length_squared() >= 1) continue; + return p; + } +} + +vec3 vec3::random_in_unit_sphere() +{ + while (true) + { + auto p = vec3::random(-1,1); + if (p.length_squared() >= 1) continue; + return p; + } +} + +vec3 random_in_hemisphere(const vec3& normal) +{ + vec3 in_unit_sphere = vec3::random_in_unit_sphere(); + if (dot(in_unit_sphere, normal) > 0.0) + { + return in_unit_sphere; + } + else + { + return -in_unit_sphere; + } +} +