diff --git a/rtiww/CMakeLists.txt b/rtiww/CMakeLists.txt index 42527f8..6b22a59 100644 --- a/rtiww/CMakeLists.txt +++ b/rtiww/CMakeLists.txt @@ -3,4 +3,9 @@ project(rtiww) set(CMAKE_CXX_STANDARD 17) -add_executable(rtiww src/main.cpp src/vec3.h src/color.h src/ray.h) +add_executable(rtiww src/main.cpp + src/vec3.h src/ray.h + src/color.h + src/hittable.h src/hittable_list.h + src/sphere.h + src/rtweekend.h) diff --git a/rtiww/src/hittable.h b/rtiww/src/hittable.h new file mode 100644 index 0000000..90140f3 --- /dev/null +++ b/rtiww/src/hittable.h @@ -0,0 +1,25 @@ +#ifndef HITTABLE_H_ +#define HITTABLE_H_ + +#include "ray.h" +#include "vec3.h" + +struct hit_record { + point3 p; + vec3 normal; + 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; + } +}; + +class hittable { +public: + virtual bool hit(const ray &r, double t_min, double t_max, + hit_record &rec) const = 0; +}; + +#endif // HITTABLE_H_ diff --git a/rtiww/src/hittable_list.h b/rtiww/src/hittable_list.h new file mode 100644 index 0000000..3a1d065 --- /dev/null +++ b/rtiww/src/hittable_list.h @@ -0,0 +1,44 @@ +#ifndef HITTABLE_LIST_H_ +#define HITTABLE_LIST_H_ + +#include "hittable.h" + +#include +#include + +using std::shared_ptr; +using std::vector; + +class hittable_list : public hittable { +public: + hittable_list() {} + hittable_list(shared_ptr object) { add(object); } + + void clear() { objects.clear(); } + void add(shared_ptr object) { objects.push_back(object); } + + virtual bool hit(const ray &r, double t_min, double t_max, + hit_record &rec) const override; + +public: + 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; +} + +#endif // HITTABLE_LIST_H_ diff --git a/rtiww/src/main.cpp b/rtiww/src/main.cpp index 7895dae..466117c 100644 --- a/rtiww/src/main.cpp +++ b/rtiww/src/main.cpp @@ -1,33 +1,19 @@ +#include "hittable.h" +#include "rtweekend.h" + #include "color.h" -#include "vec3.h" -#include "ray.h" +#include "hittable_list.h" +#include "sphere.h" #include -double hit_sphere(const point3 ¢er, double radius, const ray &r) { - vec3 oc = r.origin() - center; - - 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) { - return -1.0; - } else { - return (-half_b - sqrt(discriminant)) / a; +color ray_color(const ray &r, const hittable& world) { + hit_record rec; + if(world.hit(r, 0, infinity, rec)) { + return 0.5 * (rec.normal + color(1,1,1)); } -} - -color ray_color(const ray &r) { - auto t = hit_sphere(point3(0,0,-1), 0.5, r); - - if(t > 0.0) { - vec3 N = unit_vector(r.at(t) - vec3(0,0,-1)); - return 0.5*color(N.x()+1, N.y()+1, N.z()+1); - } - vec3 unit_direction = unit_vector(r.direction()); - t = 0.5*(unit_direction.y() + 1.0); + auto t = 0.5*(unit_direction.y() + 1.0); return (1.0 - t) * color(1.0, 1.0, 1.0) + t * color(0.5, 0.7, 1.0); } @@ -38,6 +24,11 @@ int main() { const int image_width = 400; const int image_height = static_cast(image_width / aspect_ratio); + // World + hittable_list world; + world.add(make_shared(point3(0,0,-1), 0.5)); + world.add(make_shared(point3(0,-100.5,-1), 100)); + // Camera auto viewport_height = 2.0; auto viewport_width = aspect_ratio * viewport_height; @@ -58,7 +49,7 @@ int main() { auto v = double(j) / (image_height - 1); ray r(origin, lower_left_corner + u * horizontal + v * vertical - origin); - color pixel_color = ray_color(r); + color pixel_color = ray_color(r, world); write_color(std::cout, pixel_color); } } diff --git a/rtiww/src/rtweekend.h b/rtiww/src/rtweekend.h new file mode 100644 index 0000000..d81cea4 --- /dev/null +++ b/rtiww/src/rtweekend.h @@ -0,0 +1,32 @@ +#ifndef RTWEEKEND_H_ +#define RTWEEKEND_H_ + +#include +#include +#include + +using std::shared_ptr; +using std::make_shared; +using std::sqrt; + +const double infinity = std::numeric_limits::infinity(); +const double pi = 3.1415926535897932385; + +inline double degrees_to_radians(double degrees) { + return degrees * pi / 180.0; +} + +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(); +} + +#include "ray.h" +#include "vec3.h" + +#endif // RTWEEKEND_H_ diff --git a/rtiww/src/sphere.h b/rtiww/src/sphere.h new file mode 100644 index 0000000..4f2705c --- /dev/null +++ b/rtiww/src/sphere.h @@ -0,0 +1,42 @@ +#ifndef SPHERE_H_ +#define SPHERE_H_ + +#include "hittable.h" + +class sphere: public hittable { +public: + sphere() {} + sphere(point3 cen, double r): center(cen), radius(r) {}; + virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const override; + +public: + point3 center; + double radius; +}; + +bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const { + vec3 oc = r.origin() - center; + 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) return false; + auto sqrtd = sqrt(discriminant); + + // Find the nearest root that lies in the acceptable range + auto root = (-half_b - sqrtd) / a; + if(root < t_min || t_max