Skip to content

Commit 837c26b

Browse files
committed
Move vec3::write_color to standalone helper
This change introduces a new common project header: color.h. Updated books and source code. Resolves #502
1 parent b363815 commit 837c26b

File tree

7 files changed

+123
-51
lines changed

7 files changed

+123
-51
lines changed

CHANGELOG.md

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
Change Log -- Ray Tracing in One Weekend
22
====================================================================================================
33

4-
----------------------------------------------------------------------------------------------------
4+
55
# v3.1.0 (in progress)
66

77
### Common
88
- Fix: Scattered improvements to the text.
99
- New: subchapters throughout all three books (#267)
1010
- Change: Minor change to use new `point3` and `color` type aliases for `vec3` (#422)
1111
- Change: Renamed `constant_texture` to `solid_color`, add RGB constructor (#452)
12+
- Change: Moved `vec3::write_color()` method to utility function in `color.h` header (#502)
1213

1314
### _In One Weekend_
1415
- Fix: Update image and size for first PPM image
@@ -18,6 +19,8 @@ Change Log -- Ray Tracing in One Weekend
1819
- Fix: Improve image size and aspect ratio calculation to make size changes easier
1920
- Fix: Added `t` parameter back into `hit_record` at correct place
2021
- Fix: image basic vectors off by one
22+
- Fix: Correct typo in "What's next?" list to rejoin split paragraph on "Lights." Adjust numbering
23+
in rest of list.
2124
- Change: First image size changed to 256x256
2225
- Change: Default image sizes changed from 200x100 to 384x216
2326
- Change: Define image aspect ratio up front, then image height from that and the image width
@@ -26,14 +29,6 @@ Change Log -- Ray Tracing in One Weekend
2629
- Change: Large rewrite of the `image_texture` class. Now handles image loading too. (#434)
2730

2831

29-
---------------------------------------------------------------------------------------------------
30-
# v3.0.3 (in progress)
31-
32-
### _In One Weekend_
33-
- Fix: Correct typo in "What's next?" list to rejoin split paragraph on "Lights." Adjust numbering
34-
in rest of list.
35-
36-
3732
----------------------------------------------------------------------------------------------------
3833
# v3.0.2 (2020-04-11)
3934

books/RayTracingInOneWeekend.html

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,6 @@
275275
return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
276276
}
277277

278-
void write_color(std::ostream &out) {
279-
// Write the translated [0,255] value of each color component.
280-
out << static_cast<int>(255.999 * e[0]) << ' '
281-
<< static_cast<int>(255.999 * e[1]) << ' '
282-
<< static_cast<int>(255.999 * e[2]) << '\n';
283-
}
284-
285278
public:
286279
double e[3];
287280
};
@@ -352,10 +345,38 @@
352345
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
353346
[Listing [vec3-utility]: <kbd>[vec3.h]</kbd> vec3 utility functions]
354347

348+
349+
Color Utility Functions
350+
------------------------
351+
Using our new `vec3` class, we'll create a utility function to write a single pixel's color out to
352+
the standard output stream.
353+
354+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
355+
#ifndef COLOR_H
356+
#define COLOR_H
357+
358+
#include "vec3.h"
359+
360+
#include <iostream>
361+
362+
void write_color(std::ostream &out, color pixel_color) {
363+
// Write the translated [0,255] value of each color component.
364+
out << static_cast<int>(255.999 * pixel_color.x()) << ' '
365+
<< static_cast<int>(255.999 * pixel_color.y()) << ' '
366+
<< static_cast<int>(255.999 * pixel_color.z()) << '\n';
367+
}
368+
369+
#endif
370+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
371+
[Listing [color]: <kbd>[color.h]</kbd> color utility functions]
372+
373+
374+
355375
<div class='together'>
356376
Now we can change our main to use this:
357377

358378
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
379+
#include "color.h"
359380
#include "vec3.h"
360381

361382
#include <iostream>
@@ -371,7 +392,7 @@
371392
for (int i = 0; i < image_width; ++i) {
372393
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
373394
color pixel_color(double(i)/(image_width-1), double(j)/(image_height-1), 0.25);
374-
pixel_color.write_color(std::cout);
395+
write_color(std::cout, pixel_color);
375396
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
376397
}
377398
}
@@ -492,7 +513,7 @@
492513
ray r(origin, lower_left_corner + u*horizontal + v*vertical);
493514
color pixel_color = ray_color(r);
494515
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
495-
pixel_color.write_color(std::cout);
516+
write_color(std::cout, pixel_color);
496517
}
497518
}
498519

@@ -1217,7 +1238,7 @@
12171238
color pixel_color = ray_color(r, world);
12181239
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
12191240

1220-
pixel_color.write_color(std::cout);
1241+
write_color(std::cout, pixel_color);
12211242
}
12221243
}
12231244

@@ -1344,7 +1365,7 @@
13441365
[Listing [camera-initial]: <kbd>[camera.h]</kbd> The camera class]
13451366
</div>
13461367

1347-
To handle the multi-sampled color computation, we update the `vec3::write_color()` function. Rather
1368+
To handle the multi-sampled color computation, we'll update the `write_color()` function. Rather
13481369
than adding in a fractional contribution each time we accumulate more light to the color, just add
13491370
the full color each iteration, and then perform a single divide at the end (by the number of
13501371
samples) when writing out the color. In addition, we'll add a handy utility function to the
@@ -1360,20 +1381,24 @@
13601381
[Listing [clamp]: <kbd>[rtweekend.h]</kbd> The clamp() utility function]
13611382

13621383
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1363-
void write_color(std::ostream &out, int samples_per_pixel) {
1384+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
1385+
auto r = pixel_color.x();
1386+
auto g = pixel_color.y();
1387+
auto b = pixel_color.z();
1388+
13641389
// Divide the color total by the number of samples.
13651390
auto scale = 1.0 / samples_per_pixel;
1366-
auto r = scale * e[0];
1367-
auto g = scale * e[1];
1368-
auto b = scale * e[2];
1391+
r *= scale;
1392+
g *= scale;
1393+
b *= scale;
13691394

13701395
// Write the translated [0,255] value of each color component.
13711396
out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
13721397
<< static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
13731398
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
13741399
}
13751400
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1376-
[Listing [write-color-clamped]: <kbd>[vec3.h]</kbd> The write_color() function]
1401+
[Listing [write-color-clamped]: <kbd>[color.h]</kbd> The multi-sample write_color() function]
13771402

13781403
<div class='together'>
13791404
Main is also changed:
@@ -1407,7 +1432,7 @@
14071432
ray r = cam.get_ray(u, v);
14081433
pixel_color += ray_color(r, world);
14091434
}
1410-
pixel_color.write_color(std::cout, samples_per_pixel);
1435+
write_color(std::cout, pixel_color, samples_per_pixel);
14111436
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
14121437
}
14131438
}
@@ -1588,7 +1613,7 @@
15881613
pixel_color += ray_color(r, world, max_depth);
15891614
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
15901615
}
1591-
pixel_color.write_color(std::cout, samples_per_pixel);
1616+
write_color(std::cout, pixel_color, samples_per_pixel);
15921617
}
15931618
}
15941619

@@ -1623,14 +1648,17 @@
16231648
square-root:
16241649

16251650
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1626-
void write_color(std::ostream &out, int samples_per_pixel) {
1651+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
1652+
auto r = pixel_color.x();
1653+
auto g = pixel_color.y();
1654+
auto b = pixel_color.z();
1655+
16271656
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1628-
// Divide the color total by the number of samples and gamma-correct
1629-
// for a gamma value of 2.0.
1657+
// Divide the color total by the number of samples and gamma-correct for gamma=2.0.
16301658
auto scale = 1.0 / samples_per_pixel;
1631-
auto r = sqrt(scale * e[0]);
1632-
auto g = sqrt(scale * e[1]);
1633-
auto b = sqrt(scale * e[2]);
1659+
r = sqrt(scale * r);
1660+
g = sqrt(scale * g);
1661+
b = sqrt(scale * b);
16341662
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
16351663

16361664
// Write the translated [0,255] value of each color component.
@@ -1639,7 +1667,7 @@
16391667
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
16401668
}
16411669
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1642-
[Listing [write-color-gamma]: <kbd>[vec3.h]</kbd> write_color(), with gamma correction]
1670+
[Listing [write-color-gamma]: <kbd>[color.h]</kbd> write_color(), with gamma correction]
16431671

16441672
</div>
16451673

@@ -2127,7 +2155,7 @@
21272155
ray r = cam.get_ray(u, v);
21282156
pixel_color += ray_color(r, world, max_depth);
21292157
}
2130-
pixel_color.write_color(std::cout, samples_per_pixel);
2158+
write_color(std::cout, pixel_color, samples_per_pixel);
21312159
}
21322160
}
21332161

books/RayTracingTheRestOfYourLife.html

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,32 +2422,36 @@
24222422
So big decision: sweep this bug under the rug and check for `NaN`s, or just kill `NaN`s and hope
24232423
this doesn't come back to bite us later. I will always opt for the lazy strategy, especially when I
24242424
know floating point is hard. First, how do we check for a `NaN`? The one thing I always remember
2425-
for `NaN`s is that a `NaN` does not equal itself. Using this trick, we update the
2426-
`vec3::write_color()` function to replace any NaN components with zero:
2425+
for `NaN`s is that a `NaN` does not equal itself. Using this trick, we update the `write_color()`
2426+
function to replace any NaN components with zero:
24272427

24282428
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2429-
void write_color(std::ostream &out, int samples_per_pixel) {
2429+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
2430+
auto r = pixel_color.x();
2431+
auto g = pixel_color.y();
2432+
auto b = pixel_color.z();
2433+
24302434
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2431-
// Replace NaN component values with zero.
2432-
if (e[0] != e[0]) e[0] = 0.0;
2433-
if (e[1] != e[1]) e[1] = 0.0;
2434-
if (e[2] != e[2]) e[2] = 0.0;
2435+
// Replace NaN components with zero. See explanation in Ray Tracing: The Rest of Your Life.
2436+
if (r != r) r = 0.0;
2437+
if (g != g) g = 0.0;
2438+
if (b != b) b = 0.0;
2439+
24352440
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
24362441

2437-
// Divide the color total by the number of samples and gamma-correct
2438-
// for a gamma value of 2.0.
2442+
// Divide the color by the number of samples and gamma-correct for gamma=2.0.
24392443
auto scale = 1.0 / samples_per_pixel;
2440-
auto r = sqrt(scale * e[0]);
2441-
auto g = sqrt(scale * e[1]);
2442-
auto b = sqrt(scale * e[2]);
2444+
r = sqrt(scale * r);
2445+
g = sqrt(scale * g);
2446+
b = sqrt(scale * b);
24432447

24442448
// Write the translated [0,255] value of each color component.
24452449
out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
24462450
<< static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
24472451
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
24482452
}
24492453
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2450-
[Listing [write-color-nan]: <kbd>[vec3.h]</kbd> NaN-tolerant write_color function]
2454+
[Listing [write-color-nan]: <kbd>[color.h]</kbd> NaN-tolerant write_color function]
24512455
</div>
24522456

24532457
<div class='together'>

src/InOneWeekend/main.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "rtweekend.h"
1313

1414
#include "camera.h"
15+
#include "color.h"
1516
#include "hittable_list.h"
1617
#include "material.h"
1718
#include "sphere.h"
@@ -118,7 +119,7 @@ int main() {
118119
ray r = cam.get_ray(u, v);
119120
pixel_color += ray_color(r, world, max_depth);
120121
}
121-
pixel_color.write_color(std::cout, samples_per_pixel);
122+
write_color(std::cout, pixel_color, samples_per_pixel);
122123
}
123124
}
124125

src/TheNextWeek/main.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "box.h"
1515
#include "bvh.h"
1616
#include "camera.h"
17+
#include "color.h"
1718
#include "constant_medium.h"
1819
#include "hittable_list.h"
1920
#include "material.h"
@@ -447,7 +448,7 @@ int main() {
447448
ray r = cam.get_ray(u, v);
448449
pixel_color += ray_color(r, background, world, max_depth);
449450
}
450-
pixel_color.write_color(std::cout, samples_per_pixel);
451+
write_color(std::cout, pixel_color, samples_per_pixel);
451452
}
452453
}
453454

src/TheRestOfYourLife/main.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "aarect.h"
1515
#include "box.h"
1616
#include "camera.h"
17+
#include "color.h"
1718
#include "hittable_list.h"
1819
#include "material.h"
1920
#include "sphere.h"
@@ -127,7 +128,7 @@ int main() {
127128
ray r = cam.get_ray(u, v);
128129
pixel_color += ray_color(r, background, world, lights, max_depth);
129130
}
130-
pixel_color.write_color(std::cout, samples_per_pixel);
131+
write_color(std::cout, pixel_color, samples_per_pixel);
131132
}
132133
}
133134

src/common/color.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#ifndef COLOR_H
2+
#define COLOR_H
3+
//==============================================================================================
4+
// Originally written in 2020 by Peter Shirley <[email protected]>
5+
//
6+
// To the extent possible under law, the author(s) have dedicated all copyright and related and
7+
// neighboring rights to this software to the public domain worldwide. This software is
8+
// distributed without any warranty.
9+
//
10+
// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication
11+
// along with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
12+
//==============================================================================================
13+
14+
#include "vec3.h"
15+
16+
#include <iostream>
17+
18+
19+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
20+
auto r = pixel_color.x();
21+
auto g = pixel_color.y();
22+
auto b = pixel_color.z();
23+
24+
// Replace NaN components with zero. See explanation in Ray Tracing: The Rest of Your Life.
25+
if (r != r) r = 0.0;
26+
if (g != g) g = 0.0;
27+
if (b != b) b = 0.0;
28+
29+
// Divide the color by the number of samples and gamma-correct for gamma=2.0.
30+
auto scale = 1.0 / samples_per_pixel;
31+
r = sqrt(scale * r);
32+
g = sqrt(scale * g);
33+
b = sqrt(scale * b);
34+
35+
// Write the translated [0,255] value of each color component.
36+
out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
37+
<< static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
38+
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
39+
}
40+
41+
42+
#endif

0 commit comments

Comments
 (0)