From c6f3f92f50884ad011dde4b7884f1a33c0f1d246 Mon Sep 17 00:00:00 2001 From: Steve Hollasch Date: Sat, 31 Oct 2020 00:08:28 -0700 Subject: [PATCH 1/3] Introduce interval class for hit() methods --- books/RayTracingInOneWeekend.html | 139 +++++++++++++++++++++++-- books/RayTracingTheNextWeek.html | 103 ++++++++---------- books/RayTracingTheRestOfYourLife.html | 21 ++-- src/InOneWeekend/hittable.h | 3 +- src/InOneWeekend/hittable_list.h | 9 +- src/InOneWeekend/main.cc | 2 +- src/InOneWeekend/sphere.h | 9 +- src/TheNextWeek/aarect.h | 21 ++-- src/TheNextWeek/box.h | 7 +- src/TheNextWeek/bvh.h | 11 +- src/TheNextWeek/constant_medium.h | 15 ++- src/TheNextWeek/hittable.h | 17 ++- src/TheNextWeek/hittable_list.h | 9 +- src/TheNextWeek/main.cc | 2 +- src/TheNextWeek/moving_sphere.h | 9 +- src/TheNextWeek/sphere.h | 9 +- src/TheRestOfYourLife/aarect.h | 23 ++-- src/TheRestOfYourLife/box.h | 7 +- src/TheRestOfYourLife/bvh.h | 11 +- src/TheRestOfYourLife/hittable.h | 23 ++-- src/TheRestOfYourLife/hittable_list.h | 9 +- src/TheRestOfYourLife/main.cc | 2 +- src/TheRestOfYourLife/sphere.h | 11 +- src/common/aabb.h | 8 +- src/common/interval.h | 28 +++++ src/common/rtweekend.h | 1 + 26 files changed, 306 insertions(+), 203 deletions(-) create mode 100644 src/common/interval.h diff --git a/books/RayTracingInOneWeekend.html b/books/RayTracingInOneWeekend.html index 6c1d4b14..d4771c28 100644 --- a/books/RayTracingInOneWeekend.html +++ b/books/RayTracingInOneWeekend.html @@ -1278,6 +1278,128 @@ +An Interval Class +------------------ +Before we continue, we'll implement an interval class to manage real-valued intervals with a minimum +and a maximum. We'll end up using this class quite often as we proceed. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + #ifndef INTERVAL_H + #define INTERVAL_H + + class interval { + public: + double min, max; + + interval(double _min, double _max) : min(_min), max(_max) {} + interval() : min(+infinity), max(-infinity) {} // Default interval is empty + + bool contains(double x) const { + return min <= x && x <= max; + } + }; + + const static interval empty (+infinity, -infinity); + const static interval universe(-infinity, +infinity); + + + #endif + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [interval-initial]: [interval.h] Introducing the new interval class] + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + class hittable { + public: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-with-interval]: [hittable.h] hittable::hit() using interval] + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + class hittable_list : public hittable { + ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + ... + }; + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + bool hittable_list::hit(const ray& r, interval ray_t, hit_record& rec) const { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + hit_record temp_rec; + bool hit_anything = false; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + auto closest_so_far = ray_t.max; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + + for (const auto& object : objects) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + if (object->hit(r, interval(ray_t.min, closest_so_far), temp_rec)) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + hit_anything = true; + closest_so_far = temp_rec.t; + rec = temp_rec; + } + } + + return hit_anything; + } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-list-with-interval]: [hittable.h] + hittable_list::hit() using interval] + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + class sphere : public hittable { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + ... + }; + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + bool sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + ... + + // Find the nearest root that lies in the acceptable range. + auto root = (-half_b - sqrtd) / a; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + if (!t.contains(root)) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + root = (-half_b + sqrtd) / a; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + if (!t.contains(root)) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + return false; + } + ... + } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sphere-with-interval]: [sphere.h] sphere using interval] + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + ... + color ray_color(const ray& r, const hittable& world) { + hit_record rec; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + if (world.hit(r, interval(0, infinity), rec)) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + return 0.5 * (rec.normal + color(1,1,1)); + } + ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-with-interval]: [main.cc] The new main using interval] Antialiasing @@ -1570,7 +1692,7 @@ color ray_color(const ray& r, const hittable& world) { hit_record rec; - if (world.hit(r, 0, infinity, rec)) { + if (world.hit(r, interval(0, infinity), rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight point3 target = rec.p + rec.normal + random_in_unit_sphere(); return 0.5 * ray_color(ray(rec.p, target - rec.p), world); @@ -1606,7 +1728,7 @@ return color(0,0,0); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - if (world.hit(r, 0, infinity, rec)) { + if (world.hit(r, interval(0, infinity), rec)) { point3 target = rec.p + rec.normal + random_in_unit_sphere(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1); @@ -1721,7 +1843,7 @@ point approximation the sphere intersector gives us. So we need to ignore hits very near zero: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - if (world.hit(r, 0.001, infinity, rec)) { + if (world.hit(r, interval(0.001, infinity), rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Listing [reflect-tolerance]: [main.cc] Calculating reflected ray origins with tolerance] @@ -1772,7 +1894,7 @@ if (depth <= 0) return color(0,0,0); - if (world.hit(r, 0.001, infinity, rec)) { + if (world.hit(r, interval(0.001, infinity), rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight point3 target = rec.p + rec.normal + random_unit_vector(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ @@ -1854,7 +1976,7 @@ if (depth <= 0) return color(0,0,0); - if (world.hit(r, 0.001, infinity, rec)) { + if (world.hit(r, interval(0.001, infinity), rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight point3 target = rec.p + random_in_hemisphere(rec.normal); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ @@ -1976,8 +2098,7 @@ : center(ctr), radius(r), mat_ptr(m) {}; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; public: point3 center; @@ -1987,7 +2108,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; - bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { ... rec.t = root; @@ -2146,7 +2267,7 @@ if (depth <= 0) return color(0,0,0); - if (world.hit(r, 0.001, infinity, rec)) { + if (world.hit(r, interval(0.001, infinity), rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight ray scattered; color attenuation; diff --git a/books/RayTracingTheNextWeek.html b/books/RayTracingTheNextWeek.html index 984594c8..6aa2e9a3 100644 --- a/books/RayTracingTheNextWeek.html +++ b/books/RayTracingTheNextWeek.html @@ -197,8 +197,7 @@ time0(time_start), time1(time_end) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; point3 center(double time) const; @@ -226,7 +225,7 @@ just needs to become a function `center(time)`: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool moving_sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool moving_sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight vec3 oc = r.origin() - center(r.time()); @@ -241,9 +240,9 @@ // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) { + if (!ray_t.contains(root)) { root = (-half_b + sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) + if (!ray_t.contains(root)) return false; } @@ -662,14 +661,14 @@ point3 min() const {return minimum; } point3 max() const {return maximum; } - bool hit(const ray& r, double ray_tmin, double ray_tmax) const { + bool hit(const ray& r, interval ray_t) const { for (int a = 0; a < 3; a++) { auto t0 = fmin((minimum[a] - r.origin()[a]) / r.direction()[a], (maximum[a] - r.origin()[a]) / r.direction()[a]); auto t1 = fmax((minimum[a] - r.origin()[a]) / r.direction()[a], (maximum[a] - r.origin()[a]) / r.direction()[a]); - ray_tmin = fmax(t0, ray_tmin); - ray_tmax = fmin(t1, ray_tmax); + auto ray_tmin = fmax(t0, ray_t.min); + auto ray_tmax = fmin(t1, ray_t.max); if (ray_tmax <= ray_tmin) return false; } @@ -694,15 +693,15 @@ as my go-to method: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - inline bool aabb::hit(const ray& r, double ray_tmin, double ray_tmax) const { + inline bool aabb::hit(const ray& r, interval ray_t) const { for (int a = 0; a < 3; a++) { auto invD = 1.0f / r.direction()[a]; auto t0 = (min()[a] - r.origin()[a]) * invD; auto t1 = (max()[a] - r.origin()[a]) * invD; if (invD < 0.0f) std::swap(t0, t1); - ray_tmin = t0 > ray_tmin ? t0 : ray_tmin; - ray_tmax = t1 < ray_tmax ? t1 : ray_tmax; + auto ray_tmin = t0 > ray_t.min ? t0 : ray_t.min; + auto ray_tmax = t1 < ray_t.max ? t1 : ray_t.max; if (ray_tmax <= ray_tmin) return false; } @@ -730,8 +729,7 @@ class hittable { public: ... - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const = 0; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -751,8 +749,7 @@ class sphere : public hittable { public: ... - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -788,8 +785,7 @@ class moving_sphere : public hittable { public: ... - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -833,8 +829,7 @@ class hittable_list : public hittable { public: ... - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -917,8 +912,7 @@ const std::vector>& src_objects, size_t start, size_t end, double time_start, double time_end); - virtual bool hit( - const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -947,12 +941,12 @@ check the children and sort out any details: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool bvh_node::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - if (!box.hit(r, ray_tmin, ray_tmax)) + bool bvh_node::hit(const ray& r, interval ray_t, hit_record& rec) const { + if (!box.hit(r, ray_t)) return false; - bool hit_left = left->hit(r, ray_tmin, ray_tmax, rec); - bool hit_right = right->hit(r, ray_tmin, hit_left ? rec.t : ray_tmax, rec); + bool hit_left = left->hit(r, ray_t, rec); + bool hit_right = right->hit(r, interval(ray_t.min, hit_left ? rec.t : ray_t.max), rec); return hit_left || hit_right; } @@ -2313,7 +2307,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ray scattered; @@ -2469,8 +2463,7 @@ shared_ptr mat) : x0(_x0), x1(_x1), y0(_y0), y1(_y1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -2494,9 +2487,9 @@ And the hit function is: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool xy_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool xy_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().z()) / r.direction().z(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); auto y = r.origin().y() + t*r.direction().y(); @@ -2612,8 +2605,7 @@ shared_ptr mat) : x0(_x0), x1(_x1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -2636,8 +2628,7 @@ shared_ptr mat) : y0(_y0), y1(_y1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -2659,9 +2650,9 @@ With unsurprising hit functions: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool xz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool xz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().y()) / r.direction().y(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); auto z = r.origin().z() + t*r.direction().z(); @@ -2677,9 +2668,9 @@ return true; } - bool yz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool yz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().x()) / r.direction().x(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto y = r.origin().y() + t*r.direction().y(); auto z = r.origin().z() + t*r.direction().z(); @@ -2795,8 +2786,7 @@ box() {} box(const point3& p0, const point3& p1, shared_ptr ptr); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -2824,8 +2814,8 @@ sides.add(make_shared(p0.y(), p1.y(), p0.z(), p1.z(), p0.x(), ptr)); } - bool box::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - return sides.hit(r, ray_tmin, ray_tmax, rec); + bool box::hit(const ray& r, interval ray_t, hit_record& rec) const { + return sides.hit(r, ray_t, rec); } #endif @@ -2878,8 +2868,7 @@ translate(shared_ptr p, const vec3& displacement) : ptr(p), offset(displacement) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -2889,9 +2878,9 @@ vec3 offset; }; - bool translate::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool translate::hit(const ray& r, interval ray_t, hit_record& rec) const { ray moved_r(r.origin() - offset, r.direction(), r.time()); - if (!ptr->hit(moved_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(moved_r, ray_t, rec)) return false; rec.p += offset; @@ -2966,8 +2955,7 @@ public: rotate_y(shared_ptr p, double angle); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -3029,7 +3017,7 @@ And the hit function: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool rotate_y::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { + bool rotate_y::hit(const ray& r, interval ray_t, hit_record& rec) const { auto origin = r.origin(); auto direction = r.direction(); @@ -3041,7 +3029,7 @@ ray rotated_r(origin, direction, r.time()); - if (!ptr->hit(rotated_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(rotated_r, ray_t, rec)) return false; auto p = rec.p; @@ -3146,8 +3134,7 @@ phase_function(make_shared(c)) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -3193,25 +3180,23 @@ And the hit function is: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - bool constant_medium::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const { - + bool constant_medium::hit(const ray& r, interval ray_t, hit_record& rec) const { // Print occasional samples when debugging. To enable, set enableDebug true. const bool enableDebug = false; const bool debugging = enableDebug && random_double() < 0.00001; hit_record rec1, rec2; - if (!boundary->hit(r, -infinity, infinity, rec1)) + if (!boundary->hit(r, universe, rec1)) return false; - if (!boundary->hit(r, rec1.t+0.0001, infinity, rec2)) + if (!boundary->hit(r, interval(rec1.t+0.0001, infinity), rec2)) return false; if (debugging) std::cerr << "\nray_tmin=" << rec1.t << ", ray_tmax=" << rec2.t << '\n'; - if (rec1.t < ray_tmin) rec1.t = ray_tmin; - if (rec2.t > ray_tmax) rec2.t = ray_tmax; + if (rec1.t < ray_t.min) rec1.t = ray_t.min; + if (rec2.t > ray_t.max) rec2.t = ray_t.max; if (rec1.t >= rec2.t) return false; diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html index 13f38bce..bbfeb870 100644 --- a/books/RayTracingTheRestOfYourLife.html +++ b/books/RayTracingTheRestOfYourLife.html @@ -913,7 +913,7 @@ return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ray scattered; @@ -1409,7 +1409,7 @@ return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ray scattered; @@ -1486,10 +1486,8 @@ public: flip_face(shared_ptr p) : ptr(p) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override { - - if (!ptr->hit(r, ray_tmin, ray_tmax, rec)) + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override { + if (!ptr->hit(r, ray_t, rec)) return false; rec.front_face = !rec.front_face; @@ -1659,7 +1657,7 @@ return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ray scattered; @@ -1727,8 +1725,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ class hittable { public: - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const = 0; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const = 0; @@ -1758,7 +1755,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight virtual double pdf_value(const point3& origin, const vec3& v) const override { hit_record rec; - if (!this->hit(ray(origin, v), 0.001, infinity, rec)) + if (!this->hit(ray(origin, v), interval(0.001, infinity), rec)) return 0; auto area = (x1-x0)*(z1-z0); @@ -2083,7 +2080,7 @@ return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -2339,7 +2336,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ double sphere::pdf_value(const point3& o, const vec3& v) const { hit_record rec; - if (!this->hit(ray(o, v), 0.001, infinity, rec)) + if (!this->hit(ray(o, v), interval(0.001, infinity), rec)) return 0; auto cos_theta_max = sqrt(1 - radius*radius/(center-o).length_squared()); diff --git a/src/InOneWeekend/hittable.h b/src/InOneWeekend/hittable.h index 75073e84..1070fc3c 100644 --- a/src/InOneWeekend/hittable.h +++ b/src/InOneWeekend/hittable.h @@ -32,8 +32,7 @@ struct hit_record { class hittable { public: - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const = 0; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; }; diff --git a/src/InOneWeekend/hittable_list.h b/src/InOneWeekend/hittable_list.h index 721ded14..84eeaf16 100644 --- a/src/InOneWeekend/hittable_list.h +++ b/src/InOneWeekend/hittable_list.h @@ -27,21 +27,20 @@ class hittable_list : public hittable { void clear() { objects.clear(); } void add(shared_ptr object) { objects.push_back(object); } - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; public: std::vector> objects; }; -bool hittable_list::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool hittable_list::hit(const ray& r, interval ray_t, hit_record& rec) const { hit_record temp_rec; auto hit_anything = false; - auto closest_so_far = ray_tmax; + auto closest_so_far = ray_t.max; for (const auto& object : objects) { - if (object->hit(r, ray_tmin, closest_so_far, temp_rec)) { + if (object->hit(r, interval(ray_t.min, closest_so_far), temp_rec)) { hit_anything = true; closest_so_far = temp_rec.t; rec = temp_rec; diff --git a/src/InOneWeekend/main.cc b/src/InOneWeekend/main.cc index 86576d34..02b423b7 100644 --- a/src/InOneWeekend/main.cc +++ b/src/InOneWeekend/main.cc @@ -27,7 +27,7 @@ color ray_color(const ray& r, const hittable& world, int depth) { if (depth <= 0) return color(0,0,0); - if (world.hit(r, 0.001, infinity, rec)) { + if (world.hit(r, interval(0.001, infinity), rec)) { ray scattered; color attenuation; if (rec.mat_ptr->scatter(r, rec, attenuation, scattered)) diff --git a/src/InOneWeekend/sphere.h b/src/InOneWeekend/sphere.h index af8686eb..423460b1 100644 --- a/src/InOneWeekend/sphere.h +++ b/src/InOneWeekend/sphere.h @@ -22,8 +22,7 @@ class sphere : public hittable { sphere(point3 ctr, double r, shared_ptr m) : center(ctr), radius(r), mat_ptr(m) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; public: point3 center; @@ -32,7 +31,7 @@ class sphere : public hittable { }; -bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { vec3 oc = r.origin() - center; auto a = r.direction().length_squared(); auto half_b = dot(oc, r.direction()); @@ -44,9 +43,9 @@ bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) { + if (!ray_t.contains(root)) { root = (-half_b + sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) + if (!ray_t.contains(root)) return false; } diff --git a/src/TheNextWeek/aarect.h b/src/TheNextWeek/aarect.h index a60d0113..7e844e5c 100644 --- a/src/TheNextWeek/aarect.h +++ b/src/TheNextWeek/aarect.h @@ -24,8 +24,7 @@ class xy_rect : public hittable { double _x0, double _x1, double _y0, double _y1, double _k, shared_ptr mat ) : x0(_x0), x1(_x1), y0(_y0), y1(_y1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -50,8 +49,7 @@ class xz_rect : public hittable { double _x0, double _x1, double _z0, double _z1, double _k, shared_ptr mat ) : x0(_x0), x1(_x1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -76,8 +74,7 @@ class yz_rect : public hittable { double _y0, double _y1, double _z0, double _z1, double _k, shared_ptr mat ) : y0(_y0), y1(_y1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -94,9 +91,9 @@ class yz_rect : public hittable { }; -bool xy_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool xy_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().z()) / r.direction().z(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); @@ -116,9 +113,9 @@ bool xy_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& re } -bool xz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool xz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().y()) / r.direction().y(); - if (t < ray_tmin || ray_tmax < t) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); @@ -138,9 +135,9 @@ bool xz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& re } -bool yz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool yz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().x()) / r.direction().x(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto y = r.origin().y() + t*r.direction().y(); diff --git a/src/TheNextWeek/box.h b/src/TheNextWeek/box.h index 6fa2fabd..31347354 100644 --- a/src/TheNextWeek/box.h +++ b/src/TheNextWeek/box.h @@ -22,8 +22,7 @@ class box : public hittable { box() {} box(const point3& p0, const point3& p1, shared_ptr ptr); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -54,8 +53,8 @@ box::box(const point3& p0, const point3& p1, shared_ptr ptr) { } -bool box::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - return sides.hit(r, ray_tmin, ray_tmax, rec); +bool box::hit(const ray& r, interval ray_t, hit_record& rec) const { + return sides.hit(r, ray_t, rec); } diff --git a/src/TheNextWeek/bvh.h b/src/TheNextWeek/bvh.h index 159d4d90..c7df5bc5 100644 --- a/src/TheNextWeek/bvh.h +++ b/src/TheNextWeek/bvh.h @@ -31,8 +31,7 @@ class bvh_node : public hittable { const std::vector>& src_objects, size_t start, size_t end, double time0, double time1); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time0, double time1, aabb& output_box) const override; @@ -109,12 +108,12 @@ bvh_node::bvh_node( } -bool bvh_node::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - if (!box.hit(r, ray_tmin, ray_tmax)) +bool bvh_node::hit(const ray& r, interval ray_t, hit_record& rec) const { + if (!box.hit(r, ray_t)) return false; - bool hit_left = left->hit(r, ray_tmin, ray_tmax, rec); - bool hit_right = right->hit(r, ray_tmin, hit_left ? rec.t : ray_tmax, rec); + bool hit_left = left->hit(r, ray_t, rec); + bool hit_right = right->hit(r, interval(ray_t.min, hit_left ? rec.t : ray_t.max), rec); return hit_left || hit_right; } diff --git a/src/TheNextWeek/constant_medium.h b/src/TheNextWeek/constant_medium.h index c22dd866..430d0e20 100644 --- a/src/TheNextWeek/constant_medium.h +++ b/src/TheNextWeek/constant_medium.h @@ -32,8 +32,7 @@ class constant_medium : public hittable { phase_function(make_shared(c)) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override { @@ -48,25 +47,23 @@ class constant_medium : public hittable { }; -bool constant_medium::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const { - +bool constant_medium::hit(const ray& r, interval ray_t, hit_record& rec) const { // Print occasional samples when debugging. To enable, set enableDebug true. const bool enableDebug = false; const bool debugging = enableDebug && random_double() < 0.00001; hit_record rec1, rec2; - if (!boundary->hit(r, -infinity, infinity, rec1)) + if (!boundary->hit(r, universe, rec1)) return false; - if (!boundary->hit(r, rec1.t+0.0001, infinity, rec2)) + if (!boundary->hit(r, interval(rec1.t+0.0001, infinity), rec2)) return false; if (debugging) std::cerr << "\nt_min=" << rec1.t << ", t_max=" << rec2.t << '\n'; - if (rec1.t < ray_tmin) rec1.t = ray_tmin; - if (rec2.t > ray_tmax) rec2.t = ray_tmax; + if (rec1.t < ray_t.min) rec1.t = ray_t.min; + if (rec2.t > ray_t.max) rec2.t = ray_t.max; if (rec1.t >= rec2.t) return false; diff --git a/src/TheNextWeek/hittable.h b/src/TheNextWeek/hittable.h index d0b8d645..431bba93 100644 --- a/src/TheNextWeek/hittable.h +++ b/src/TheNextWeek/hittable.h @@ -37,8 +37,7 @@ struct hit_record { class hittable { public: - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const = 0; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const = 0; @@ -49,8 +48,7 @@ class translate : public hittable { translate(shared_ptr p, const vec3& displacement) : ptr(p), offset(displacement) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -61,9 +59,9 @@ class translate : public hittable { }; -bool translate::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool translate::hit(const ray& r, interval ray_t, hit_record& rec) const { ray moved_r(r.origin() - offset, r.direction(), r.time()); - if (!ptr->hit(moved_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(moved_r, ray_t, rec)) return false; rec.p += offset; @@ -89,8 +87,7 @@ class rotate_y : public hittable { public: rotate_y(shared_ptr p, double angle); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -141,7 +138,7 @@ rotate_y::rotate_y(shared_ptr p, double angle) : ptr(p) { } -bool rotate_y::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool rotate_y::hit(const ray& r, interval ray_t, hit_record& rec) const { auto origin = r.origin(); auto direction = r.direction(); @@ -153,7 +150,7 @@ bool rotate_y::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& r ray rotated_r(origin, direction, r.time()); - if (!ptr->hit(rotated_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(rotated_r, ray_t, rec)) return false; auto p = rec.p; diff --git a/src/TheNextWeek/hittable_list.h b/src/TheNextWeek/hittable_list.h index 54249880..9f4d522a 100644 --- a/src/TheNextWeek/hittable_list.h +++ b/src/TheNextWeek/hittable_list.h @@ -27,8 +27,7 @@ class hittable_list : public hittable { void clear() { objects.clear(); } void add(shared_ptr object) { objects.push_back(object); } - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -38,13 +37,13 @@ class hittable_list : public hittable { }; -bool hittable_list::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool hittable_list::hit(const ray& r, interval ray_t, hit_record& rec) const { hit_record temp_rec; auto hit_anything = false; - auto closest_so_far = ray_tmax; + auto closest_so_far = ray_t.max; for (const auto& object : objects) { - if (object->hit(r, ray_tmin, closest_so_far, temp_rec)) { + if (object->hit(r, interval(ray_t.min, closest_so_far), temp_rec)) { hit_anything = true; closest_so_far = temp_rec.t; rec = temp_rec; diff --git a/src/TheNextWeek/main.cc b/src/TheNextWeek/main.cc index a370339e..dd431676 100644 --- a/src/TheNextWeek/main.cc +++ b/src/TheNextWeek/main.cc @@ -33,7 +33,7 @@ color ray_color(const ray& r, const color& background, const hittable& world, in return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; ray scattered; diff --git a/src/TheNextWeek/moving_sphere.h b/src/TheNextWeek/moving_sphere.h index 135196dc..a56fef52 100644 --- a/src/TheNextWeek/moving_sphere.h +++ b/src/TheNextWeek/moving_sphere.h @@ -27,8 +27,7 @@ class moving_sphere : public hittable { time0(time_start), time1(time_end) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -60,7 +59,7 @@ bool moving_sphere::bounding_box(double time_start, double time_end, aabb& outpu } -bool moving_sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool moving_sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { vec3 oc = r.origin() - center(r.time()); auto a = r.direction().length_squared(); auto half_b = dot(oc, r.direction()); @@ -72,9 +71,9 @@ bool moving_sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_reco // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) { + if (!ray_t.contains(root)) { root = (-half_b + sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) + if (!ray_t.contains(root)) return false; } diff --git a/src/TheNextWeek/sphere.h b/src/TheNextWeek/sphere.h index 47f442b2..a724dbe8 100644 --- a/src/TheNextWeek/sphere.h +++ b/src/TheNextWeek/sphere.h @@ -22,8 +22,7 @@ class sphere : public hittable { sphere(point3 ctr, double r, shared_ptr m) : center(ctr), radius(r), mat_ptr(m) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -59,7 +58,7 @@ bool sphere::bounding_box(double time_start, double time_end, aabb& output_box) } -bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { vec3 oc = r.origin() - center; auto a = r.direction().length_squared(); auto half_b = dot(oc, r.direction()); @@ -71,9 +70,9 @@ bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) { + if (!ray_t.contains(root)) { root = (-half_b + sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) + if (!ray_t.contains(root)) return false; } diff --git a/src/TheRestOfYourLife/aarect.h b/src/TheRestOfYourLife/aarect.h index eaf1cd8d..fdba358a 100644 --- a/src/TheRestOfYourLife/aarect.h +++ b/src/TheRestOfYourLife/aarect.h @@ -24,8 +24,7 @@ class xy_rect : public hittable { double _x0, double _x1, double _y0, double _y1, double _k, shared_ptr mat ) : x0(_x0), x1(_x1), y0(_y0), y1(_y1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -50,8 +49,7 @@ class xz_rect : public hittable { double _x0, double _x1, double _z0, double _z1, double _k, shared_ptr mat ) : x0(_x0), x1(_x1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -64,7 +62,7 @@ class xz_rect : public hittable { virtual double pdf_value(const point3& origin, const vec3& v) const override { hit_record rec; - if (!this->hit(ray(origin, v), 0.001, infinity, rec)) + if (!this->hit(ray(origin, v), interval(0.001, infinity), rec)) return 0; auto area = (x1-x0)*(z1-z0); @@ -93,8 +91,7 @@ class yz_rect : public hittable { double _y0, double _y1, double _z0, double _z1, double _k, shared_ptr mat ) : y0(_y0), y1(_y1), z0(_z0), z1(_z1), k(_k), mp(mat) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -111,9 +108,9 @@ class yz_rect : public hittable { }; -bool xy_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool xy_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().z()) / r.direction().z(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); @@ -133,9 +130,9 @@ bool xy_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& re } -bool xz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool xz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().y()) / r.direction().y(); - if (t < ray_tmin || ray_tmax < t) + if (!ray_t.contains(t)) return false; auto x = r.origin().x() + t*r.direction().x(); @@ -155,9 +152,9 @@ bool xz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& re } -bool yz_rect::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool yz_rect::hit(const ray& r, interval ray_t, hit_record& rec) const { auto t = (k-r.origin().x()) / r.direction().x(); - if (t < ray_tmin || t > ray_tmax) + if (!ray_t.contains(t)) return false; auto y = r.origin().y() + t*r.direction().y(); diff --git a/src/TheRestOfYourLife/box.h b/src/TheRestOfYourLife/box.h index 6fa2fabd..31347354 100644 --- a/src/TheRestOfYourLife/box.h +++ b/src/TheRestOfYourLife/box.h @@ -22,8 +22,7 @@ class box : public hittable { box() {} box(const point3& p0, const point3& p1, shared_ptr ptr); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -54,8 +53,8 @@ box::box(const point3& p0, const point3& p1, shared_ptr ptr) { } -bool box::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - return sides.hit(r, ray_tmin, ray_tmax, rec); +bool box::hit(const ray& r, interval ray_t, hit_record& rec) const { + return sides.hit(r, ray_t, rec); } diff --git a/src/TheRestOfYourLife/bvh.h b/src/TheRestOfYourLife/bvh.h index 159d4d90..8254ee09 100644 --- a/src/TheRestOfYourLife/bvh.h +++ b/src/TheRestOfYourLife/bvh.h @@ -31,8 +31,7 @@ class bvh_node : public hittable { const std::vector>& src_objects, size_t start, size_t end, double time0, double time1); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time0, double time1, aabb& output_box) const override; @@ -109,12 +108,12 @@ bvh_node::bvh_node( } -bool bvh_node::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { - if (!box.hit(r, ray_tmin, ray_tmax)) +bool bvh_node::hit(const ray& r, interval ray_t, hit_record& rec) const { + if (!box.hit(r, ray_t)) return false; - bool hit_left = left->hit(r, ray_tmin, ray_tmax, rec); - bool hit_right = right->hit(r, ray_tmin, hit_left ? rec.t : ray_tmax, rec); + bool hit_left = left->hit(r, ray_t, rec); + bool hit_right = right->hit(r, interval(ray_tmin, hit_left ? rec.t : ray_tmax), rec); return hit_left || hit_right; } diff --git a/src/TheRestOfYourLife/hittable.h b/src/TheRestOfYourLife/hittable.h index 43f848fc..efd2e229 100644 --- a/src/TheRestOfYourLife/hittable.h +++ b/src/TheRestOfYourLife/hittable.h @@ -37,8 +37,7 @@ struct hit_record { class hittable { public: - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const = 0; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const = 0; @@ -57,10 +56,8 @@ class flip_face : public hittable { public: flip_face(shared_ptr p) : ptr(p) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override { - - if (!ptr->hit(r, ray_tmin, ray_tmax, rec)) + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override { + if (!ptr->hit(r, ray_t, rec)) return false; rec.front_face = !rec.front_face; @@ -83,8 +80,7 @@ class translate : public hittable { translate(shared_ptr p, const vec3& displacement) : ptr(p), offset(displacement) {} - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -95,9 +91,9 @@ class translate : public hittable { }; -bool translate::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool translate::hit(const ray& r, interval ray_t, hit_record& rec) const { ray moved_r(r.origin() - offset, r.direction(), r.time()); - if (!ptr->hit(moved_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(moved_r, ray_t, rec)) return false; rec.p += offset; @@ -123,8 +119,7 @@ class rotate_y : public hittable { public: rotate_y(shared_ptr p, double angle); - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override @@ -175,7 +170,7 @@ rotate_y::rotate_y(shared_ptr p, double angle) : ptr(p) { } -bool rotate_y::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool rotate_y::hit(const ray& r, interval ray_t, hit_record& rec) const { auto origin = r.origin(); auto direction = r.direction(); @@ -187,7 +182,7 @@ bool rotate_y::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& r ray rotated_r(origin, direction, r.time()); - if (!ptr->hit(rotated_r, ray_tmin, ray_tmax, rec)) + if (!ptr->hit(rotated_r, ray_t, rec)) return false; auto p = rec.p; diff --git a/src/TheRestOfYourLife/hittable_list.h b/src/TheRestOfYourLife/hittable_list.h index bc5116c9..33fbad50 100644 --- a/src/TheRestOfYourLife/hittable_list.h +++ b/src/TheRestOfYourLife/hittable_list.h @@ -27,8 +27,7 @@ class hittable_list : public hittable { void clear() { objects.clear(); } void add(shared_ptr object) { objects.push_back(object); } - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -41,13 +40,13 @@ class hittable_list : public hittable { }; -bool hittable_list::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool hittable_list::hit(const ray& r, interval ray_t, hit_record& rec) const { hit_record temp_rec; auto hit_anything = false; - auto closest_so_far = ray_tmax; + auto closest_so_far = ray_t.max; for (const auto& object : objects) { - if (object->hit(r, ray_tmin, closest_so_far, temp_rec)) { + if (object->hit(r, interval(ray_t.min, closest_so_far), temp_rec)) { hit_anything = true; closest_so_far = temp_rec.t; rec = temp_rec; diff --git a/src/TheRestOfYourLife/main.cc b/src/TheRestOfYourLife/main.cc index b5ffbbcd..82ada93f 100644 --- a/src/TheRestOfYourLife/main.cc +++ b/src/TheRestOfYourLife/main.cc @@ -36,7 +36,7 @@ color ray_color( return color(0,0,0); // If the ray hits nothing, return the background color. - if (!world.hit(r, 0.001, infinity, rec)) + if (!world.hit(r, interval(0.001, infinity), rec)) return background; scatter_record srec; diff --git a/src/TheRestOfYourLife/sphere.h b/src/TheRestOfYourLife/sphere.h index 6069b731..ed8e0fa6 100644 --- a/src/TheRestOfYourLife/sphere.h +++ b/src/TheRestOfYourLife/sphere.h @@ -23,8 +23,7 @@ class sphere : public hittable { sphere(point3 ctr, double r, shared_ptr m) : center(ctr), radius(r), mat_ptr(m) {}; - virtual bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) - const override; + virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const override; virtual bool bounding_box(double time_start, double time_end, aabb& output_box) const override; @@ -57,7 +56,7 @@ class sphere : public hittable { double sphere::pdf_value(const point3& o, const vec3& v) const { hit_record rec; - if (!this->hit(ray(o, v), 0.001, infinity, rec)) + if (!this->hit(ray(o, v), interval(0.001, infinity), rec)) return 0; auto cos_theta_max = sqrt(1 - radius*radius/(center-o).length_squared()); @@ -84,7 +83,7 @@ bool sphere::bounding_box(double time_start, double time_end, aabb& output_box) } -bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const { +bool sphere::hit(const ray& r, interval ray_t, hit_record& rec) const { vec3 oc = r.origin() - center; auto a = r.direction().length_squared(); auto half_b = dot(oc, r.direction()); @@ -96,9 +95,9 @@ bool sphere::hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) { + if (!ray_t.contains(root)) { root = (-half_b + sqrtd) / a; - if (root < ray_tmin || ray_tmax < root) + if (!ray_t.contains(root)) return false; } diff --git a/src/common/aabb.h b/src/common/aabb.h index ea2b7fdc..6fc9dbe1 100644 --- a/src/common/aabb.h +++ b/src/common/aabb.h @@ -22,15 +22,15 @@ class aabb { point3 min() const {return minimum; } point3 max() const {return maximum; } - bool hit(const ray& r, double ray_tmin, double ray_tmax) const { + bool hit(const ray& r, interval ray_t) const { for (int a = 0; a < 3; a++) { auto t0 = fmin((minimum[a] - r.origin()[a]) / r.direction()[a], (maximum[a] - r.origin()[a]) / r.direction()[a]); auto t1 = fmax((minimum[a] - r.origin()[a]) / r.direction()[a], (maximum[a] - r.origin()[a]) / r.direction()[a]); - ray_tmin = fmax(t0, ray_tmin); - ray_tmax = fmin(t1, ray_tmax); - if (ray_tmax <= ray_tmin) + ray_t.min = fmax(t0, ray_t.min); + ray_t.max = fmin(t1, ray_t.max); + if (ray_t.max <= ray_t.min) return false; } return true; diff --git a/src/common/interval.h b/src/common/interval.h new file mode 100644 index 00000000..c03a0d71 --- /dev/null +++ b/src/common/interval.h @@ -0,0 +1,28 @@ +#ifndef INTERVAL_H +#define INTERVAL_H +//============================================================================================== +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is +// distributed without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication +// along with this software. If not, see . +//============================================================================================== + +class interval { + public: + double min, max; + + interval(double _min, double _max) : min(_min), max(_max) {} + interval() : min(+infinity), max(-infinity) {} // Default interval is empty + + bool contains(double x) const { + return min <= x && x <= max; + } +}; + +const static interval empty (+infinity, -infinity); +const static interval universe(-infinity, +infinity); + + +#endif diff --git a/src/common/rtweekend.h b/src/common/rtweekend.h index 797a9e13..c4fdbbcd 100644 --- a/src/common/rtweekend.h +++ b/src/common/rtweekend.h @@ -55,6 +55,7 @@ inline int random_int(int min, int max) { // Common Headers +#include "interval.h" #include "ray.h" #include "vec3.h" From d9a30fb42e22253652eed0aee9cd183a87b60bd3 Mon Sep 17 00:00:00 2001 From: Steve Hollasch Date: Sat, 31 Oct 2020 12:11:05 -0700 Subject: [PATCH 2/3] Fix dangling problem with interval use --- books/RayTracingInOneWeekend.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/books/RayTracingInOneWeekend.html b/books/RayTracingInOneWeekend.html index d4771c28..6c3ce6ce 100644 --- a/books/RayTracingInOneWeekend.html +++ b/books/RayTracingInOneWeekend.html @@ -1373,11 +1373,11 @@ // Find the nearest root that lies in the acceptable range. auto root = (-half_b - sqrtd) / a; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - if (!t.contains(root)) { + if (!ray_t.contains(root)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ root = (-half_b + sqrtd) / a; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - if (!t.contains(root)) + if (!ray_t.contains(root)) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ return false; } From d2dc5b9ef5c8bfc743284ca4f10c38dc10708539 Mon Sep 17 00:00:00 2001 From: Steve Hollasch Date: Mon, 2 Nov 2020 19:00:30 -0800 Subject: [PATCH 3/3] CHANGELOG += new interval class --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4f0d4c..9cffc92a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Change Log -- Ray Tracing in One Weekend # v4.0.0 (pending, targeted for 2020-12-25) ### Common + - Change: Introduce new `interval` class used throughout codebase (#777) + - Change: `hittable:hit()` methods use new interval class for ray t parameter ### In One Weekend