Skip to content

Commit ddaf7ae

Browse files
committed
Update camera code
In the prior code, changes to camera variables would require associated changes to a number of other related variables, in ways that were not apparent. This change uses variables a more consistent manner, where changing any particular variable should yield consistent results in other values. In addition, this provides a more consistent series of iterative steps as the camera develops through the text. Resolves #527
1 parent 55abc5f commit ddaf7ae

File tree

3 files changed

+126
-91
lines changed

3 files changed

+126
-91
lines changed

books/RayTracingInOneWeekend.html

Lines changed: 88 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -466,12 +466,21 @@
466466
that returns the color of the background (a simple gradient).
467467

468468
I’ve often gotten into trouble using square images for debugging because I transpose $x$ and $y$ too
469-
often, so I’ll stick with a 200×100 image. I’ll put the “eye” (or camera center if you think of a
470-
camera) at $(0,0,0)$. I will have the y-axis go up, and the x-axis to the right. In order to respect
471-
the convention of a right handed coordinate system, into the screen is the negative z-axis. I will
472-
traverse the screen from the lower left hand corner, and use two offset vectors along the screen
473-
sides to move the ray endpoint across the screen. Note that I do not make the ray direction a unit
474-
length vector because I think not doing that makes for simpler and slightly faster code.
469+
often, so I’ll use a non-square image. For now we'll use a 16:9 aspect ratio, since that's so
470+
common.
471+
472+
In addition to setting up the pixel dimensions for the rendered image, we also need to set up a
473+
virtual viewport through which to pass our scene rays. For the standard square pixel spacing, the
474+
viewport's aspect ratio should be the same as our rendered image. We'll just pick a viewport two
475+
units in height. Ultimately, changing the scale of the viewport (while holding the focal distance
476+
constant) is equivalent to changing the viewing angle, or “zoom” of the image.
477+
478+
I’ll put the “eye” (or camera center if you think of a camera) at $(0,0,0)$. I will have the y-axis
479+
go up, and the x-axis to the right. In order to respect the convention of a right handed coordinate
480+
system, into the screen is the negative z-axis. I will traverse the screen from the lower left hand
481+
corner, and use two offset vectors along the screen sides to move the ray endpoint across the
482+
screen. Note that I do not make the ray direction a unit length vector because I think not doing
483+
that makes for simpler and slightly faster code.
475484

476485
![Figure [cam-geom]: Camera geometry](../images/fig.cam-geom.jpg)
477486

@@ -497,19 +506,25 @@
497506

498507
std::cout << "P3\n" << image_width << " " << image_height << "\n255\n";
499508

509+
500510
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
501-
point3 origin(0.0, 0.0, 0.0);
502-
vec3 horizontal(4.0, 0.0, 0.0);
503-
vec3 vertical(0.0, 2.25, 0.0);
504-
point3 lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0,0,1);
511+
auto viewport_height = 2.0;
512+
auto viewport_width = aspect_ratio * viewport_height;
513+
auto focal_length = 1.0;
514+
515+
auto origin = point3(0, 0, 0);
516+
auto horizontal = vec3(viewport_width, 0, 0);
517+
auto vertical = vec3(0, viewport_height, 0);
518+
auto lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
505519
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
520+
506521
for (int j = image_height-1; j >= 0; --j) {
507522
std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
508523
for (int i = 0; i < image_width; ++i) {
509524
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
510525
auto u = double(i) / (image_width-1);
511526
auto v = double(j) / (image_height-1);
512-
ray r(origin, lower_left_corner + u*horizontal + v*vertical);
527+
ray r(origin, lower_left_corner + u*horizontal + v*vertical - origin);
513528
color pixel_color = ray_color(r);
514529
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
515530
write_color(std::cout, pixel_color);
@@ -1201,10 +1216,14 @@
12011216

12021217
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
12031218

1204-
point3 lower_left_corner(-2.0, -1.0, -1.0);
1205-
vec3 horizontal(4.0, 0.0, 0.0);
1206-
vec3 vertical(0.0, 2.0, 0.0);
1207-
point3 origin(0.0, 0.0, 0.0);
1219+
auto viewport_height = 2.0;
1220+
auto viewport_width = aspect_ratio * viewport_height;
1221+
auto focal_length = 1.0;
1222+
1223+
auto origin = point3(0, 0, 0);
1224+
auto horizontal = vec3(viewport_width, 0, 0);
1225+
auto vertical = vec3(0, viewport_height, 0);
1226+
auto lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
12081227

12091228

12101229
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
@@ -1313,7 +1332,8 @@
13131332
</div>
13141333

13151334
<div class='together'>
1316-
Putting that all together yields a camera class encapsulating our simple axis-aligned camera from
1335+
Now's a good time to create a `camera` class to manage our virtual camera and the related tasks of
1336+
scene scampling. The following class implements a simple camera using the axis-aligned camera from
13171337
before:
13181338

13191339
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
@@ -1325,10 +1345,15 @@
13251345
class camera {
13261346
public:
13271347
camera() {
1328-
lower_left_corner = point3(-2.0, -1.0, -1.0);
1329-
horizontal = vec3(4.0, 0.0, 0.0);
1330-
vertical = vec3(0.0, 2.0, 0.0);
1331-
origin = point3(0.0, 0.0, 0.0);
1348+
auto aspect_ratio = 16.0 / 9.0;
1349+
auto viewport_height = 2.0;
1350+
auto viewport_width = aspect_ratio * viewport_height;
1351+
auto focal_length = 1.0;
1352+
1353+
origin = point3(0, 0, 0);
1354+
horizontal = vec3(viewport_width, 0.0, 0.0);
1355+
vertical = vec3(0.0, viewport_height, 0.0);
1356+
lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
13321357
}
13331358

13341359
ray get_ray(double u, double v) const {
@@ -1399,9 +1424,11 @@
13991424
world.add(make_shared<sphere>(point3(0,0,-1), 0.5));
14001425
world.add(make_shared<sphere>(point3(0,-100.5,-1), 100));
14011426

1427+
14021428
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
14031429
camera cam;
14041430
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1431+
14051432
for (int j = image_height-1; j >= 0; --j) {
14061433
std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
14071434
for (int i = 0; i < image_width; ++i) {
@@ -1882,7 +1909,6 @@
18821909
double t;
18831910
bool front_face;
18841911

1885-
18861912
inline void set_face_normal(const ray& r, const vec3& outward_normal) {
18871913
front_face = dot(r.direction(), outward_normal) < 0;
18881914
normal = front_face ? outward_normal :-outward_normal;
@@ -2107,6 +2133,7 @@
21072133
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
21082134

21092135
camera cam;
2136+
21102137
for (int j = image_height-1; j >= 0; --j) {
21112138
std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
21122139
for (int i = 0; i < image_width; ++i) {
@@ -2551,16 +2578,17 @@
25512578
double vfov, // vertical field-of-view in degrees
25522579
double aspect_ratio
25532580
) {
2554-
origin = point3(0.0, 0.0, 0.0);
2555-
25562581
auto theta = degrees_to_radians(vfov);
2557-
auto half_height = tan(theta/2);
2558-
auto half_width = aspect_ratio * half_height;
2582+
auto h = tan(theta/2);
2583+
auto viewport_height = 2.0 * h;
2584+
auto viewport_width = aspect_ratio * viewport_height;
25592585

2560-
lower_left_corner = point3(-half_width, -half_height, -1.0);
2586+
auto focal_length = 1.0;
25612587

2562-
horizontal = vec3(2*half_width, 0.0, 0.0);
2563-
vertical = vec3(0.0, 2*half_height, 0.0);
2588+
origin = point3(0, 0, 0);
2589+
horizontal = vec3(viewport_width, 0.0, 0.0);
2590+
vertical = vec3(0.0, viewport_height, 0.0);
2591+
lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
25642592
}
25652593
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
25662594

@@ -2626,29 +2654,28 @@
26262654
public:
26272655
camera(
26282656
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2629-
point3 lookfrom, point3 lookat, vec3 vup,
2657+
point3 lookfrom,
2658+
point3 lookat,
2659+
vec3 vup,
26302660
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
26312661
double vfov, // vertical field-of-view in degrees
26322662
double aspect_ratio
26332663
) {
2634-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2635-
origin = lookfrom;
2636-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2637-
vec3 u, v, w;
2638-
26392664
auto theta = degrees_to_radians(vfov);
2640-
auto half_height = tan(theta/2);
2641-
auto half_width = aspect_ratio * half_height;
2665+
auto h = tan(theta/2);
2666+
auto viewport_height = 2.0 * h;
2667+
auto viewport_width = aspect_ratio * viewport_height;
26422668

2643-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2644-
w = unit_vector(lookfrom - lookat);
2645-
u = unit_vector(cross(vup, w));
2646-
v = cross(w, u);
26472669

2648-
lower_left_corner = origin - half_width*u - half_height*v - w;
2670+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2671+
auto w = unit_vector(lookfrom - lookat);
2672+
auto u = unit_vector(cross(vup, w));
2673+
auto v = cross(w, u);
26492674

2650-
horizontal = 2*half_width*u;
2651-
vertical = 2*half_height*v;
2675+
origin = lookfrom;
2676+
horizontal = viewport_width * u;
2677+
vertical = viewport_height * v;
2678+
lower_left_corner = origin - horizontal/2 - vertical/2 - w;
26522679
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
26532680
}
26542681

@@ -2759,31 +2786,35 @@
27592786
class camera {
27602787
public:
27612788
camera(
2762-
point3 lookfrom, point3 lookat, vec3 vup,
2789+
point3 lookfrom,
2790+
point3 lookat,
2791+
vec3 vup,
27632792
double vfov, // vertical field-of-view in degrees
2793+
double aspect_ratio,
27642794
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2765-
double aspect_ratio, double aperture, double focus_dist
2766-
) {
2767-
origin = lookfrom;
2768-
lens_radius = aperture / 2;
2795+
double aperture,
2796+
double focus_dist
27692797
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2770-
2798+
) {
27712799
auto theta = degrees_to_radians(vfov);
2772-
auto half_height = tan(theta/2);
2773-
auto half_width = aspect_ratio * half_height;
2800+
auto h = tan(theta/2);
2801+
auto viewport_height = 2.0 * h;
2802+
auto viewport_width = aspect_ratio * viewport_height;
27742803

2804+
2805+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
27752806
w = unit_vector(lookfrom - lookat);
27762807
u = unit_vector(cross(vup, w));
27772808
v = cross(w, u);
2809+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
27782810

2811+
origin = lookfrom;
27792812
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2780-
lower_left_corner = origin
2781-
- half_width * focus_dist * u
2782-
- half_height * focus_dist * v
2783-
- focus_dist * w;
2813+
horizontal = focus_dist * viewport_width * u;
2814+
vertical = focus_dist * viewport_height * v;
2815+
lower_left_corner = origin - horizontal/2 - vertical/2 - focus_dist*w;
27842816

2785-
horizontal = 2*half_width*focus_dist*u;
2786-
vertical = 2*half_height*focus_dist*v;
2817+
lens_radius = aperture / 2;
27872818
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
27882819
}
27892820

books/RayTracingTheNextWeek.html

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,35 +108,37 @@
108108
class camera {
109109
public:
110110
camera(
111-
point3 lookfrom, point3 lookat, vec3 vup,
111+
point3 lookfrom,
112+
point3 lookat,
113+
vec3 vup,
112114
double vfov, // vertical field-of-view in degrees
113-
double aspect_ratio, double aperture, double focus_dist,
115+
double aspect_ratio,
116+
double aperture,
117+
double focus_dist,
114118
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
115-
double t0 = 0, double t1 = 0
119+
double t0 = 0,
120+
double t1 = 0
116121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
117122
) {
118-
origin = lookfrom;
119-
lens_radius = aperture / 2;
120-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
121-
time0 = t0;
122-
time1 = t1;
123-
124-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
125123
auto theta = degrees_to_radians(vfov);
126-
auto half_height = tan(theta/2);
127-
auto half_width = aspect * half_height;
124+
auto h = tan(theta/2);
125+
auto viewport_height = 2.0 * h;
126+
auto viewport_width = aspect_ratio * viewport_height;
128127

129128
w = unit_vector(lookfrom - lookat);
130129
u = unit_vector(cross(vup, w));
131130
v = cross(w, u);
132131

133-
lower_left_corner = origin
134-
- half_width*focus_dist*u
135-
- half_height*focus_dist*v
136-
- focus_dist*w;
132+
origin = lookfrom;
133+
horizontal = focus_dist * viewport_width * u;
134+
vertical = focus_dist * viewport_height * v;
135+
lower_left_corner = origin - horizontal/2 - vertical/2 - focus_dist*w;
137136

138-
horizontal = 2*half_width*focus_dist*u;
139-
vertical = 2*half_height*focus_dist*v;
137+
lens_radius = aperture / 2;
138+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
139+
time0 = t0;
140+
time1 = t1;
141+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
140142
}
141143

142144
ray get_ray(double s, double t) const {

src/common/camera.h

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,33 @@ class camera {
1919
camera() : camera(point3(0,0,-1), point3(0,0,0), vec3(0,1,0), 40, 1, 0, 10) {}
2020

2121
camera(
22-
point3 lookfrom, point3 lookat, vec3 vup,
22+
point3 lookfrom,
23+
point3 lookat,
24+
vec3 vup,
2325
double vfov, // vertical field-of-view in degrees
24-
double aspect_ratio, double aperture, double focus_dist,
25-
double t0 = 0, double t1 = 0
26+
double aspect_ratio,
27+
double aperture,
28+
double focus_dist,
29+
double t0 = 0,
30+
double t1 = 0
2631
) {
27-
origin = lookfrom;
28-
lens_radius = aperture / 2;
29-
time0 = t0;
30-
time1 = t1;
31-
3232
auto theta = degrees_to_radians(vfov);
33-
auto half_height = tan(theta/2);
34-
auto half_width = aspect_ratio * half_height;
33+
auto h = tan(theta/2);
34+
auto viewport_height = 2.0 * h;
35+
auto viewport_width = aspect_ratio * viewport_height;
3536

3637
w = unit_vector(lookfrom - lookat);
3738
u = unit_vector(cross(vup, w));
3839
v = cross(w, u);
3940

40-
lower_left_corner = origin
41-
- half_width*focus_dist*u
42-
- half_height*focus_dist*v
43-
- focus_dist*w;
41+
origin = lookfrom;
42+
horizontal = focus_dist * viewport_width * u;
43+
vertical = focus_dist * viewport_height * v;
44+
lower_left_corner = origin - horizontal/2 - vertical/2 - focus_dist*w;
4445

45-
horizontal = 2*half_width*focus_dist*u;
46-
vertical = 2*half_height*focus_dist*v;
46+
lens_radius = aperture / 2;
47+
time0 = t0;
48+
time1 = t1;
4749
}
4850

4951
ray get_ray(double s, double t) const {

0 commit comments

Comments
 (0)