From 75e9bac55652f594e3bf156d464a2fb81e749334 Mon Sep 17 00:00:00 2001 From: ktyl Date: Mon, 20 Feb 2023 01:19:28 +0000 Subject: [PATCH] refactoring, remove rtweekend header --- include/colour.h | 71 +++++++--------------------- include/error.h | 8 ++-- include/hit_record.h | 23 +++++++++ include/hittable.h | 23 ++------- include/hittable_list.h | 18 -------- include/material.h | 16 +++---- include/rtweekend.h | 18 -------- include/scene.h | 100 ---------------------------------------- include/sphere.h | 49 ++------------------ include/vec3.h | 1 - include/world.h | 17 +++++++ src/colour.cpp | 67 +++++++++++++++++++++++++++ src/error.cpp | 7 +++ src/foo.cpp | 1 - src/hittable_list.cpp | 20 ++++++++ src/main.cpp | 16 +++---- src/sphere.cpp | 43 +++++++++++++++++ src/world.cpp | 54 ++++++++++++++++++++++ 18 files changed, 272 insertions(+), 280 deletions(-) create mode 100644 include/hit_record.h delete mode 100644 include/rtweekend.h delete mode 100644 include/scene.h create mode 100644 include/world.h create mode 100644 src/colour.cpp create mode 100644 src/error.cpp delete mode 100644 src/foo.cpp create mode 100644 src/hittable_list.cpp create mode 100644 src/sphere.cpp create mode 100644 src/world.cpp diff --git a/include/colour.h b/include/colour.h index e54e5a2..b4f62dc 100755 --- a/include/colour.h +++ b/include/colour.h @@ -1,6 +1,7 @@ #pragma once -#include "rtweekend.h" +#include "error.h" +#include "vec3.h" // for writing to stdout #include @@ -8,59 +9,21 @@ // for writing to socket #include +class colour : public vec3 +{ + using vec3::vec3; + +public: + friend colour operator*(const colour& u, const colour& v); + friend colour lerp(const colour& a, const colour& b, double t); + + colour correct_gamma(int samples); + + friend void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel); + friend void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel); + friend int format_component(double component); +}; + const colour pink(254.0/255.0, 226.0/255.0, 170.0/255.0); const colour grey(0.133, 0.133, 0.133); -void correct_gamma(colour& pixel_colour, int samples) -{ - double r = pixel_colour.x(); - double g = pixel_colour.y(); - double b = pixel_colour.z(); - - // divide the colour total by the number of samples and gamma-correct for gamma=2.0 - auto scale = 1.0 / samples; - r = sqrt(scale * r); - g = sqrt(scale * g); - b = sqrt(scale * b); - - 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); - - auto r = pixel_colour.x(); - auto g = pixel_colour.y(); - auto b = pixel_colour.z(); - - // write the translated [0,255] value of each colour component. - 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) -{ - correct_gamma(pixel_colour, samples_per_pixel); - - int r = format_component(pixel_colour.x()); - int g = format_component(pixel_colour.y()); - int b = format_component(pixel_colour.z()); - - // pack values - int len = 3; - char s[len]; - sprintf(s, "%c%c%c", r, g, b); - - int written = write(sockfd, s, len); - if (written < 0) - { - error("ERROR writing colour to socket"); - } -} diff --git a/include/error.h b/include/error.h index 6280115..1561ea0 100644 --- a/include/error.h +++ b/include/error.h @@ -1,7 +1,5 @@ +#pragma once + #include -void error(const char* message) -{ - perror(message); - exit(1); -} +void error(const char* message); diff --git a/include/hit_record.h b/include/hit_record.h new file mode 100644 index 0000000..9038716 --- /dev/null +++ b/include/hit_record.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +class material; + +struct hit_record +{ + point3 p; + vec3 normal; + std::shared_ptr mat_ptr; + double t; + bool front_face; + + inline void set_face_normal(const ray& r, const vec3& outward_normal) + { + front_face = dot(r.direction(), outward_normal) < 0; + normal = front_face ? outward_normal : -outward_normal; + } +}; diff --git a/include/hittable.h b/include/hittable.h index c350b32..7928877 100644 --- a/include/hittable.h +++ b/include/hittable.h @@ -1,27 +1,10 @@ #pragma once -#include "rtweekend.h" #include "ray.h" - -class material; - -struct hit_record -{ - point3 p; - vec3 normal; - shared_ptr mat_ptr; - double t; - bool front_face; - - inline void set_face_normal(const ray& r, const vec3& outward_normal) - { - front_face = dot(r.direction(), outward_normal) < 0; - normal = front_face ? outward_normal : -outward_normal; - } -}; +#include "hit_record.h" class hittable { - public: - virtual bool hit(const ray& r, double tMin, double tMax, hit_record& rec) const = 0; +public: + virtual bool hit(const ray& r, double tMin, double tMax, hit_record& rec) const = 0; }; diff --git a/include/hittable_list.h b/include/hittable_list.h index 4ea27a9..86dbd00 100644 --- a/include/hittable_list.h +++ b/include/hittable_list.h @@ -20,21 +20,3 @@ class hittable_list : public hittable std::vector> objects_; }; -bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const -{ - hit_record temp_rec; - bool hit_anything = false; - auto closest_so_far = t_max; - - for (const auto& object : objects_) - { - if (object->hit(r, t_min, closest_so_far, temp_rec)) - { - hit_anything = true; - closest_so_far = temp_rec.t; - rec = temp_rec; - } - } - - return hit_anything; -} diff --git a/include/material.h b/include/material.h index 78a2ef3..8979faf 100644 --- a/include/material.h +++ b/include/material.h @@ -1,7 +1,7 @@ #pragma once -#include "rtweekend.h" #include "hittable.h" +#include "hit_record.h" class material { @@ -13,13 +13,6 @@ class material ray& scattered) const = 0; }; -double schlick(double cosine, double refraction_index) -{ - auto r0 = (1-refraction_index) / (1+refraction_index); - r0 = r0*r0; - return r0 + (1-r0)*pow(1-cosine, 5); -} - class lambertian : public material { public: @@ -106,4 +99,11 @@ class dielectric : public material private: double refraction_index_; + + double schlick(double cosine, double refraction_index) const + { + auto r0 = (1-refraction_index) / (1+refraction_index); + r0 = r0*r0; + return r0 + (1-r0)*pow(1-cosine, 5); + } }; diff --git a/include/rtweekend.h b/include/rtweekend.h deleted file mode 100644 index e5ae6a2..0000000 --- a/include/rtweekend.h +++ /dev/null @@ -1,18 +0,0 @@ -#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/include/scene.h b/include/scene.h deleted file mode 100644 index 2a2f7c0..0000000 --- a/include/scene.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include "math.h" -#include "sphere.h" -#include "colour.h" -#include "material.h" -#include "hittable.h" -#include "hittable_list.h" - -colour ray_colour(const ray& r, const hittable& world, int depth) -{ - hit_record rec; - if (depth <= 0) - { - return grey; - } - - if (world.hit(r, 0.001, math::infinity, rec)) - { - ray scattered; - colour attenuation; - - if (rec.mat_ptr->scatter(r, rec, attenuation, scattered)) - { - return attenuation * ray_colour(scattered, world, depth-1); - } - - return grey; - } - - vec3 unit_direction = normalize(r.direction()); - auto t = 0.5 * (unit_direction.y() + 1.0) + 0.5; - - return lerp(grey, pink, t); -} - -hittable_list random_scene() -{ - hittable_list world; - - - //auto ground_material = make_shared(pink); - //world.add(make_shared(point3(0,-1000,0), 1000, ground_material)); - - //for (int a = -11; a < 11; a++) - //{ - // for (int b = -11; b < 11; b++) - // { - // auto choose_mat = random_double(); - // point3 centre(a + 0.9*random_double(), 0.2, b + 0.9*random_double()); - - // if ((centre - point3(4, 0.2, 0)).length() > 0.9) - // { - // shared_ptr sphere_material; - - // if (choose_mat < 0.8) - // { - // // diffuse - // //auto albedo = colour::random() * colour::random(); - // sphere_material = make_shared(pink); - // world.add(make_shared(centre, 0.2, sphere_material)); - // } - // else if (choose_mat < 0.95) - // { - // // metal - // auto fuzz = random_double(0, 0.5); - // sphere_material = make_shared(pink, fuzz); - // world.add(make_shared(centre, 0.2, sphere_material)); - // } - // else - // { - // // glass - // sphere_material = make_shared(1.5); - // world.add(make_shared(centre,0.2, sphere_material)); - // } - // } - // } - //} - - auto material1 = make_shared(1.5); - world.add(make_shared(point3(0, 0, 0), 3.0, material1)); - - //auto material2 = make_shared(pink); - //world.add(make_shared(point3(-4, 1, 0), 1.0, material2)); - - auto material3 = make_shared(pink, 0.5); - int sphere_count = 10; - for (int i = 0; i < sphere_count; i++) - { - float a = 6.28 * (float)i/sphere_count - 100.0; - float r = 8.0; - float x = r*sin(a); - float y = 2.0*cos(a); - float z = r*cos(a); - point3 pos(x,y,z); - world.add(make_shared(pos, 2.0, material3)); - } - - return world; -} diff --git a/include/sphere.h b/include/sphere.h index 91c01f5..2f21979 100644 --- a/include/sphere.h +++ b/include/sphere.h @@ -7,7 +7,7 @@ class sphere : public hittable { public: sphere() {} - sphere(point3 centre, double r, shared_ptr m) : + sphere(point3 centre, double r, std::shared_ptr m) : centre_(centre), radius_(r), mat_ptr_(m) @@ -16,49 +16,8 @@ class sphere : public hittable virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const; private: - point3 centre_; - double radius_; - shared_ptr mat_ptr_; + point3 centre_; + double radius_; + std::shared_ptr mat_ptr_; }; -bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const -{ - vec3 oc = r.origin() - centre_; - auto a = r.direction().length_squared(); - auto half_b = dot(oc, r.direction()); - auto c = oc.length_squared() - radius_*radius_; - auto discriminant = half_b*half_b - a*c; - - if (discriminant > 0) - { - auto root = sqrt(discriminant); - - auto temp = (-half_b - root)/a; - if (temp < t_max && temp > t_min) - { - rec.t = temp; - rec.p = r.at(rec.t); - - vec3 outward_normal = (rec.p - centre_) / radius_; - rec.set_face_normal(r, outward_normal); - rec.mat_ptr = mat_ptr_; - - return true; - } - - temp = (-half_b + root) / a; - if (temp < t_max && temp > t_min) - { - rec.t = temp; - rec.p = r.at(rec.t); - - vec3 outward_normal = (rec.p - centre_) / radius_; - rec.set_face_normal(r, outward_normal); - rec.mat_ptr = mat_ptr_; - - return true; - } - } - - return false; -} diff --git a/include/vec3.h b/include/vec3.h index e591529..8313c92 100755 --- a/include/vec3.h +++ b/include/vec3.h @@ -52,5 +52,4 @@ private: // type aliases for vec3 using point3 = vec3; // 3D point -using colour = vec3; // RGB colour diff --git a/include/world.h b/include/world.h new file mode 100644 index 0000000..894ff22 --- /dev/null +++ b/include/world.h @@ -0,0 +1,17 @@ +#pragma once + +#include "math.h" +#include "sphere.h" +#include "colour.h" +#include "material.h" +#include "hittable_list.h" + +class world : public hittable_list +{ +public: + static world* close_glass_sphere(); + static world* orb_field(); + + friend colour trace(const world& world, const ray& ray, int depth); +}; + diff --git a/src/colour.cpp b/src/colour.cpp new file mode 100644 index 0000000..5916a21 --- /dev/null +++ b/src/colour.cpp @@ -0,0 +1,67 @@ +#include "colour.h" + +colour colour::correct_gamma(int samples) +{ + double r = x(); + double g = y(); + double b = z(); + + // divide the colour total by the number of samples and gamma-correct for gamma=2.0 + auto scale = 1.0 / samples; + r = sqrt(scale * r); + g = sqrt(scale * g); + b = sqrt(scale * b); + + return colour(r, g, b); +} + +int format_component(double component) +{ + return int(256 * math::clamp(component, 0.0, 0.999)); +} + +void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel) +{ + pixel_colour = pixel_colour.correct_gamma(samples_per_pixel); + + int r = format_component(pixel_colour.x()); + int g = format_component(pixel_colour.y()); + int b = format_component(pixel_colour.z()); + + // pack values + int len = 3; + char s[len]; + sprintf(s, "%c%c%c", r, g, b); + + int written = write(sockfd, s, len); + if (written < 0) + { + error("ERROR writing colour to socket"); + } +} + +void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel) +{ + pixel_colour = pixel_colour.correct_gamma(samples_per_pixel); + + auto r = pixel_colour.x(); + auto g = pixel_colour.y(); + auto b = pixel_colour.z(); + + // write the translated [0,255] value of each colour component. + out << format_component(r) << ' ' + << format_component(g) << ' ' + << format_component(b) << '\n'; +} + +colour operator*(const colour& u, const colour& v) +{ + vec3 value = (vec3)u * (vec3)v; + return colour(value.x(), value.y(), value.z()); +} + +colour lerp(const colour& a, const colour& b, double t) +{ + vec3 value = lerp((vec3)a, (vec3)b, t); + return colour(value.x(), value.y(), value.z()); +} diff --git a/src/error.cpp b/src/error.cpp new file mode 100644 index 0000000..d980071 --- /dev/null +++ b/src/error.cpp @@ -0,0 +1,7 @@ +#include "error.h" + +void error(const char* message) +{ + perror(message); + exit(1); +} diff --git a/src/foo.cpp b/src/foo.cpp deleted file mode 100644 index f4de601..0000000 --- a/src/foo.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "foo.h" diff --git a/src/hittable_list.cpp b/src/hittable_list.cpp new file mode 100644 index 0000000..170bf4e --- /dev/null +++ b/src/hittable_list.cpp @@ -0,0 +1,20 @@ +#include "hittable_list.h" + +bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const +{ + hit_record temp_rec; + bool hit_anything = false; + auto closest_so_far = t_max; + + for (const auto& object : objects_) + { + if (object->hit(r, t_min, closest_so_far, temp_rec)) + { + hit_anything = true; + closest_so_far = temp_rec.t; + rec = temp_rec; + } + } + + return hit_anything; +} diff --git a/src/main.cpp b/src/main.cpp index 9da9c1a..c5e0a25 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,10 @@ -#include "rtweekend.h" - -#include "scene.h" - #include "colour.h" #include "camera.h" #include "material.h" #include "image.h" +#include "world.h" #include - #include #include @@ -106,7 +102,7 @@ void send_image_dimensions(int sock, unsigned int width, unsigned int height) } } -void render(camera& cam, hittable_list& world, int client_sock) +void render(camera& cam, const world& world, int client_sock) { for (int j = HEIGHT - 1; j >= 0; --j) { @@ -120,7 +116,7 @@ void render(camera& cam, hittable_list& world, int client_sock) 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); + pixel_colour += trace(world, r, MAX_DEPTH); } // TODO: we should instead write our output to some buffer in memory @@ -142,8 +138,6 @@ int main() //std::cout << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n"; - hittable_list world = random_scene(); - auto dist_to_target = 10.0; auto dist_to_focus = dist_to_target + 1.0; auto cam_y = 1.0; @@ -154,7 +148,9 @@ int main() camera cam(lookfrom, lookat, vup, 47, ASPECT_RATIO, aperture, dist_to_focus); - render(cam, world, newsockfd); + const world* world = world::close_glass_sphere(); + + render(cam, *world, newsockfd); // close client socket close(newsockfd); diff --git a/src/sphere.cpp b/src/sphere.cpp new file mode 100644 index 0000000..7270f01 --- /dev/null +++ b/src/sphere.cpp @@ -0,0 +1,43 @@ +#include "sphere.h" + +bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const +{ + vec3 oc = r.origin() - centre_; + auto a = r.direction().length_squared(); + auto half_b = dot(oc, r.direction()); + auto c = oc.length_squared() - radius_*radius_; + auto discriminant = half_b*half_b - a*c; + + if (discriminant > 0) + { + auto root = sqrt(discriminant); + + auto temp = (-half_b - root)/a; + if (temp < t_max && temp > t_min) + { + rec.t = temp; + rec.p = r.at(rec.t); + + vec3 outward_normal = (rec.p - centre_) / radius_; + rec.set_face_normal(r, outward_normal); + rec.mat_ptr = mat_ptr_; + + return true; + } + + temp = (-half_b + root) / a; + if (temp < t_max && temp > t_min) + { + rec.t = temp; + rec.p = r.at(rec.t); + + vec3 outward_normal = (rec.p - centre_) / radius_; + rec.set_face_normal(r, outward_normal); + rec.mat_ptr = mat_ptr_; + + return true; + } + } + + return false; +} diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 0000000..3eb615d --- /dev/null +++ b/src/world.cpp @@ -0,0 +1,54 @@ +#include "world.h" + +colour trace(const world& world, const ray& r, int depth) +{ + hit_record rec; + if (depth <= 0) + { + return grey; + } + + if (world.hit(r, 0.001, math::infinity, rec)) + { + ray scattered; + colour attenuation; + + if (rec.mat_ptr->scatter(r, rec, attenuation, scattered)) + { + return attenuation * trace(world, scattered, depth-1); + } + + return grey; + } + + vec3 unit_direction = normalize(r.direction()); + auto t = 0.5 * (unit_direction.y() + 1.0) + 0.5; + + return lerp(grey, pink, t); +} + +world* world::close_glass_sphere() +{ + world* w = new world(); + + auto material1 = std::make_shared(1.5); + w->add(std::make_shared(point3(0, 0, 0), 3.0, material1)); + + //auto material2 = make_shared(pink); + //world.add(make_shared(point3(-4, 1, 0), 1.0, material2)); + + auto material3 = std::make_shared(pink, 0.5); + int sphere_count = 10; + for (int i = 0; i < sphere_count; i++) + { + float a = 6.28 * (float)i/sphere_count - 100.0; + float r = 8.0; + float x = r*sin(a); + float y = 2.0*cos(a); + float z = r*cos(a); + point3 pos(x,y,z); + w->add(std::make_shared(pos, 2.0, material3)); + } + + return w; +}