Skip to content

Commit 7ebf020

Browse files
committed
Final text to accompany animation changes
Resolves #799
1 parent 49c1e1e commit 7ebf020

File tree

1 file changed

+67
-42
lines changed

1 file changed

+67
-42
lines changed

books/RayTracingTheNextWeek.html

Lines changed: 67 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,27 @@
3939

4040
Motion Blur
4141
====================================================================================================
42-
When you decided to ray trace, you decided that visual quality was worth more than run-time. In your
43-
fuzzy reflection and defocus blur you needed multiple samples per pixel. Once you have taken a step
44-
down that road, the good news is that almost all effects can be brute-forced. Motion blur is
45-
certainly one of those. In a real camera, the shutter opens and stays open for a time interval, and
46-
the camera and objects may move during that time. Its really an average of what the camera sees over
47-
that interval that we want.
42+
When you decided to ray trace, you decided that visual quality was worth more than run-time. When
43+
rendering fuzzy reflection and defocus blur, we used multiple samples per pixel. Once you have taken
44+
a step down that road, the good news is that almost _all_ effects can be similarly brute-forced.
45+
Motion blur is certainly one of those.
46+
47+
In a real camera, the shutter remains open for a short time interval, during which the camera and
48+
objects in the world may move. To accurately reproduce such a camera shot, we seek an average of
49+
all the instant images that the camera perceives while its shutter is open to the world.
4850

4951

5052
Introduction of SpaceTime Ray Tracing
5153
--------------------------------------
52-
We can get a random estimate by sending each ray at some random time when the shutter is open. As
53-
long as the objects are where they should be at that time, we can get the right average answer with
54-
a ray that is at exactly a single time. This is fundamentally why random ray tracing tends to be
55-
simple.
56-
57-
The basic idea is to generate rays at random times while the shutter is open and intersect the model
58-
at that one time. The way it is usually done is to have the camera move and the objects move, but
59-
have each ray exist at exactly one time. This way the “engine” of the ray tracer can just make sure
60-
the objects are where they need to be for the ray, and the intersection guts don’t change much.
54+
We can get a random estimate of a single photon by sending a single ray at some random instant in
55+
time when the shutter is open. As long as the objects are where they should be at that instant, we
56+
can get an accurate measure of the light for that ray at that same instant. This is yet another
57+
example of how random (Monte Carlo) ray tracing ends up being quite simple. Brute force wins again!
6158

6259
<div class='together'>
63-
For this we will first need to have a ray store the time it exists at:
60+
Since the “engine” of the ray tracer can just make sure the objects are where they need to be for
61+
each ray, the intersection guts don’t change much. To accomplish this, we need to store the exact
62+
time for each ray:
6463

6564
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
6665
class ray {
@@ -82,7 +81,7 @@
8281
return orig + t*dir;
8382
}
8483

85-
public:
84+
private:
8685
point3 orig;
8786
vec3 dir;
8887
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
@@ -94,10 +93,35 @@
9493
</div>
9594

9695

96+
Managing Time
97+
--------------
98+
Before continuing, let's think about time, and how we might manage it across one or more renders.
99+
There are two aspects of shutter timing to think about: the time from one shutter opening to the
100+
next shutter opening, and how long the shutter stays open for each frame. Standard movie film used
101+
to be shot at 24 frames per second. Modern digital films can be 30 or even 60 frames per second.
102+
Each frame can have its own shutter speed, which need not be -- and typically isn't -- the maximum
103+
duration of the entire shutter period. You could have the shutter open for 1/1000th of a second per
104+
frame, or 1/60th of a second. It may surprise you to learn that for most film motion pictures, the
105+
screen is actually dark more than it is lit up with the movie frames!
106+
107+
If you wanted to render a sequence of images, you would need to set up the camera with the
108+
appropriate shutter timings: frame-to-frame period, shutter/render duration, and the total number of
109+
frames (or total shot time). If the camera is moving and the world is static, you're good to go.
110+
However, if anything in the world is moving, you would need to add a method to `hittable` to
111+
broadcast the current shot timing to every object in the world. This method would then provide a way
112+
for all animate objects to set up their motion during that frame.
113+
114+
This is fairly straight-forward, and definitely a fun avenue for you to experiment with if you wish.
115+
However, for our purposes right now, we're going to proceed with a drastically simplified model. We
116+
will be render only a single frame, assuming a start at time = 0 and ending at time = 1. Our first
117+
task is to modify the camera to launch rays with random times in $[0,1]$, and our second task will
118+
be the creation of an animate sphere class.
119+
120+
97121
Updating the Camera to Simulate Motion Blur
98122
--------------------------------------------
99-
Now we need to modify the camera to generate rays at a random time between the start time and the
100-
end time. Should the camera keep track of the time interval, or should that be up to the user of
123+
We need to modify the camera to generate rays at a random instant between the start time and the end
124+
time. Should the camera keep track of the time interval, or should that be up to the user of the
101125
camera when a ray is created? When in doubt, I like to make constructors complicated if it makes
102126
calls simple, so I will make the camera keep track, but that’s a personal preference. Not many
103127
changes are needed to camera because for now it is not allowed to move; it just sends out rays over
@@ -130,9 +154,9 @@
130154

131155
Adding Moving Spheres
132156
----------------------
133-
We also need a moving object. I’ll create a sphere class that has its center move linearly from
134-
`center0` at `time_start` to `center1` at `time_end`. Outside that time interval it continues on, so
135-
those times need not match up with the camera aperture open and close.
157+
Now to create a moving object. I’ll create a sphere class that has its center move linearly from
158+
`center0` at time 0 to `center1` at time 1. (It continues on outside that time interval, so it
159+
really can be sampled at any time.)
136160

137161
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
138162
#ifndef MOVING_SPHERE_H
@@ -147,17 +171,10 @@
147171
moving_sphere() {}
148172
moving_sphere(point3 c0, point3 c1, double r, shared_ptr<material> m)
149173
: center0(c0), center1(c1), center_vec(c1 - c0), radius(r), mat_ptr(m)
150-
{
151-
// To Be Implemented
152-
};
174+
{ };
153175

154176
bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
155-
// To Be Implemented
156-
}
157-
158-
bool bounding_box(aabb& output_box) const override {
159-
output_box = bbox;
160-
return true;
177+
// Implementation below.
161178
}
162179

163180
point3 center(double time) const {
@@ -171,7 +188,6 @@
171188
vec3 center_vec;
172189
double radius;
173190
shared_ptr<material> mat_ptr;
174-
aabb bbox;
175191
};
176192

177193
#endif
@@ -226,7 +242,7 @@
226242
[Listing [moving-sphere-hit]: <kbd>[moving_sphere.h]</kbd> Moving sphere hit function]
227243
</div>
228244

229-
We need to implement the `interval::contains()` method mentioned above:
245+
We need to implement the new `interval::contains()` method mentioned above:
230246

231247
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
232248
class interval {
@@ -305,9 +321,8 @@
305321
----------------------------
306322
<div class='together'>
307323
The code below takes the example diffuse spheres from the scene at the end of the last book, and
308-
makes them move during the image render. (Think of a camera with shutter opening at time 0 and
309-
closing at time 1.) Each sphere moves from its center $\mathbf{C}$ at time $t=0$ to $\mathbf{C} +
310-
(0, r/2, 0)$ at time $t=1$, where $r$ is a random number in $[0,1)$:
324+
makes them move during the image render. Each sphere moves from its center $\mathbf{C}$ at time
325+
$t=0$ to $\mathbf{C} + (0, r/2, 0)$ at time $t=1$:
311326

312327
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
313328
...
@@ -725,7 +740,8 @@
725740
</div>
726741

727742
<div class='together'>
728-
For `moving sphere`, we can take the box of the sphere at $t_0$, and the box of the sphere at $t_1$,
743+
For `moving sphere`, we want the bounds of all places the moving sphere could occupy while it moves.
744+
To do this, we can take the box of the sphere at time = 0, and the box of the sphere at time = 1,
729745
and compute the box of those two boxes. We'll add a new `aabb` constructor that takes two boxes as
730746
input below.
731747

@@ -739,6 +755,7 @@
739755
class moving_sphere : public hittable {
740756
public:
741757
...
758+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
742759
moving_sphere(point3 c0, point3 c1, double r, shared_ptr<material> m)
743760
: center0(c0), center1(c1), center_vec(c1 - c0), radius(r), mat_ptr(m)
744761
{
@@ -747,16 +764,28 @@
747764
const aabb box1(center1 - rvec, center1 + rvec);
748765
bbox = aabb(box0, box1);
749766
};
767+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
750768

751769
...
752770

771+
753772
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
754773
bool bounding_box(aabb& output_box) const override {
755774
output_box = bbox;
756775
return true;
757776
}
758777
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
778+
759779
...
780+
781+
public:
782+
point3 center0, center1;
783+
vec3 center_vec;
784+
double radius;
785+
shared_ptr<material> mat_ptr;
786+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
787+
aabb bbox;
788+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
760789
};
761790
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
762791
[Listing [moving-sphere-bbox]: <kbd>[moving_sphere.h]</kbd> Moving sphere with bounding box]
@@ -1241,8 +1270,6 @@
12411270

12421271
scene_desc.cam.vup = vec3(0,1,0);
12431272
scene_desc.cam.focus_dist = 10.0;
1244-
scene_desc.cam.time_start = 0;
1245-
scene_desc.cam.time_end = 1;
12461273

12471274
switch (0) {
12481275
case 1: random_spheres(scene_desc); break;
@@ -2350,8 +2377,6 @@
23502377

23512378
scene_desc.cam.vup = vec3(0,1,0);
23522379
scene_desc.cam.focus_dist = 10.0;
2353-
scene_desc.cam.time_start = 0;
2354-
scene_desc.cam.time_end = 1;
23552380

23562381
...
23572382
}
@@ -3275,7 +3300,7 @@
32753300
auto center1 = point3(400, 400, 200);
32763301
auto center2 = center1 + vec3(30,0,0);
32773302
auto moving_sphere_material = make_shared<lambertian>(color(0.7, 0.3, 0.1));
3278-
world.add(make_shared<moving_sphere>(center1, center2, 50, moving_sphere_material, 0, 1));
3303+
world.add(make_shared<moving_sphere>(center1, center2, 50, moving_sphere_material));
32793304

32803305
world.add(make_shared<sphere>(point3(260, 150, 45), 50, make_shared<dielectric>(1.5)));
32813306
world.add(make_shared<sphere>(

0 commit comments

Comments
 (0)