mat;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
+ bool is_moving;
+ vec3 center_vec;
+
+ point3 center(double time) const {
+ // Linearly interpolate from center1 to center2 according to time, where t=0 yields
+ // center1, and t=1 yields center2.
+ return center0 + time*center_vec;
+ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
};
#endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [moving-sphere]: [moving_sphere.h] A moving sphere]
+ [Listing [moving-sphere]: [sphere.h] A moving sphere]
-An alternative to making a new moving sphere class is to just make them all move, while stationary
-spheres have the same begin and end position. I’m on the fence about that trade-off between fewer
-classes and more efficient stationary spheres, so let your design taste guide you.
+An alternative to making special stationary spheres is to just make them all move, but stationary
+spheres have the same begin and end position. I’m on the fence about that trade-off between simpler
+code and more efficient stationary spheres, so let your design taste guide you.
-The `moving_sphere::hit()` function is almost identical to the `sphere::hit()` function: `center`
-just needs to become a function `center(time)`:
+The updated `sphere::hit()` function is almost identical to the old `sphere::hit()` function:
+`center` just needs to query a function `sphere_center(time)`:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- class moving_sphere : public hittable {
+ class sphere : public hittable {
public:
...
bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- vec3 oc = r.origin() - center(r.time());
+ point3 center = is_moving ? sphere_center(r.time()) : center1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ 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 (!ray_t.surrounds(root)) {
- root = (-half_b + sqrtd) / a;
- if (!ray_t.surrounds(root))
- return false;
- }
-
- rec.t = root;
- rec.p = r.at(rec.t);
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- auto outward_normal = (rec.p - center(r.time())) / radius;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- rec.set_face_normal(r, outward_normal);
- rec.mat = mat;
-
- return true;
+ ...
}
...
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [moving-sphere-hit]: [moving_sphere.h] Moving sphere hit function]
+ [Listing [moving-sphere-hit]: [sphere.h] Moving sphere hit function]
We need to implement the new `interval::contains()` method mentioned above:
@@ -747,16 +733,19 @@
-For a sphere, the `bounding_box` function is easy:
+For a stationary sphere, the `bounding_box` function is easy:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
class sphere : public hittable {
public:
+ // Stationary Sphere
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- sphere(point3 ctr, double r, shared_ptr m) : center(ctr), radius(r), mat(m) {
+ sphere(point3 _center, double _radius, shared_ptr _material)
+ : center1(_center), radius(_radius), mat(_material), is_moving(false)
+ {
auto rvec = vec3(radius, radius, radius);
- bbox = aabb(center - rvec, center + rvec);
- };
+ bbox = aabb(center1 - rvec, center1 + rvec);
+ }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
@@ -764,57 +753,42 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
private:
- point3 center;
+ point3 center1;
double radius;
shared_ptr mat;
+ bool is_moving;
+ vec3 center_vec;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
aabb bbox;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ ...
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Listing [sphere-bbox]: [sphere.h] Sphere with bounding box]
-For `moving sphere`, we want the bounds of its entire range of motion. To do this, we can take the
+For a moving sphere, we want the bounds of its entire range of motion. To do this, we can take the
box of the sphere at time=0, and the box of the sphere at time=1, and compute the box around those
two boxes.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- #include "aabb.h"
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
-
- class moving_sphere : public hittable {
+ class sphere : public hittable {
public:
...
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- moving_sphere(point3 c0, point3 c1, double r, shared_ptr m)
- : center0(c0), center1(c1), center_vec(c1 - c0), radius(r), mat(m)
+ // Moving Sphere
+ sphere(point3 _center1, point3 _center2, double _radius, shared_ptr _material)
+ : center1(_center1), radius(_radius), mat(_material), is_moving(true)
{
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
auto rvec = vec3(radius, radius, radius);
- aabb box0(center0 - rvec, center0 + rvec);
- aabb box1(center1 - rvec, center1 + rvec);
- bbox = aabb(box0, box1);
- };
+ aabb box1(_center1 - rvec, _center1 + rvec);
+ aabb box2(_center2 - rvec, _center2 + rvec);
+ bbox = aabb(box1, box2);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- aabb bounding_box() const override { return bbox; }
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ center_vec = _center2 - _center1;
+ }
...
-
- private:
- point3 center0, center1;
- vec3 center_vec;
- double radius;
- shared_ptr mat;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- aabb bbox;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Listing [moving-sphere-bbox]: [moving_sphere.h] Moving sphere with bounding box]
diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html
index 63ff1856..9ea8311f 100644
--- a/books/RayTracingTheRestOfYourLife.html
+++ b/books/RayTracingTheRestOfYourLife.html
@@ -3451,25 +3451,26 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
double pdf_value(const point3& o, const vec3& v) const override {
+ // This method only works for stationary spheres.
+
hit_record 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());
+ auto cos_theta_max = sqrt(1 - radius*radius/(center1 - o).length_squared());
auto solid_angle = 2*pi*(1-cos_theta_max);
return 1 / solid_angle;
}
vec3 random(const point3& o) const override {
- vec3 direction = center - o;
+ vec3 direction = center1 - o;
auto distance_squared = direction.length_squared();
onb uvw;
uvw.build_from_w(direction);
return uvw.local(random_to_sphere(radius, distance_squared));
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
private:
...