Skip to content

Commit 5f76429

Browse files
authored
Merge pull request #510 from RayTracing/write-color
Move vec3::write_color to standalone helper
2 parents de29d24 + 094f74b commit 5f76429

File tree

7 files changed

+123
-51
lines changed

7 files changed

+123
-51
lines changed

CHANGELOG.md

+4-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Change Log -- Ray Tracing in One Weekend
22
====================================================================================================
33

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

77
### Common
@@ -10,6 +10,7 @@ Change Log -- Ray Tracing in One Weekend
1010
- New: Add explanation for padding `aarect` in the zero dimension (#488)
1111
- Change: Minor change to use new `point3` and `color` type aliases for `vec3` (#422)
1212
- Change: Renamed `constant_texture` to `solid_color`, add RGB constructor (#452)
13+
- Change: Moved `vec3::write_color()` method to utility function in `color.h` header (#502)
1314
- Change: Math notation to bold uppercase points, bold lowercase no-barb vectors (#412)
1415
- Change: Switch from `ffmin`/`ffmax` to standard `fmin`/`fmax` (#444, #491)
1516

@@ -21,6 +22,8 @@ Change Log -- Ray Tracing in One Weekend
2122
- Fix: Improve image size and aspect ratio calculation to make size changes easier
2223
- Fix: Added `t` parameter back into `hit_record` at correct place
2324
- Fix: image basic vectors off by one
25+
- Fix: Correct typo in "What's next?" list to rejoin split paragraph on "Lights." Adjust numbering
26+
in rest of list.
2427
- Change: First image size changed to 256x256
2528
- Change: Default image sizes changed from 200x100 to 384x216
2629
- Change: Define image aspect ratio up front, then image height from that and the image width
@@ -29,14 +32,6 @@ Change Log -- Ray Tracing in One Weekend
2932
- Change: Large rewrite of the `image_texture` class. Now handles image loading too. (#434)
3033

3134

32-
---------------------------------------------------------------------------------------------------
33-
# v3.0.3 (in progress)
34-
35-
### _In One Weekend_
36-
- Fix: Correct typo in "What's next?" list to rejoin split paragraph on "Lights." Adjust numbering
37-
in rest of list.
38-
39-
4035
----------------------------------------------------------------------------------------------------
4136
# v3.0.2 (2020-04-11)
4237

books/RayTracingInOneWeekend.html

+54-26
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,6 @@
274274
return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
275275
}
276276

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

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

357377
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
378+
#include "color.h"
358379
#include "vec3.h"
359380

360381
#include <iostream>
@@ -370,7 +391,7 @@
370391
for (int i = 0; i < image_width; ++i) {
371392
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
372393
color pixel_color(double(i)/(image_width-1), double(j)/(image_height-1), 0.25);
373-
pixel_color.write_color(std::cout);
394+
write_color(std::cout, pixel_color);
374395
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
375396
}
376397
}
@@ -491,7 +512,7 @@
491512
ray r(origin, lower_left_corner + u*horizontal + v*vertical);
492513
color pixel_color = ray_color(r);
493514
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
494-
pixel_color.write_color(std::cout);
515+
write_color(std::cout, pixel_color);
495516
}
496517
}
497518

@@ -1204,7 +1225,7 @@
12041225
color pixel_color = ray_color(r, world);
12051226
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
12061227

1207-
pixel_color.write_color(std::cout);
1228+
write_color(std::cout, pixel_color);
12081229
}
12091230
}
12101231

@@ -1328,7 +1349,7 @@
13281349
[Listing [camera-initial]: <kbd>[camera.h]</kbd> The camera class]
13291350
</div>
13301351

1331-
To handle the multi-sampled color computation, we update the `vec3::write_color()` function. Rather
1352+
To handle the multi-sampled color computation, we'll update the `write_color()` function. Rather
13321353
than adding in a fractional contribution each time we accumulate more light to the color, just add
13331354
the full color each iteration, and then perform a single divide at the end (by the number of
13341355
samples) when writing out the color. In addition, we'll add a handy utility function to the
@@ -1344,20 +1365,24 @@
13441365
[Listing [clamp]: <kbd>[rtweekend.h]</kbd> The clamp() utility function]
13451366

13461367
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1347-
void write_color(std::ostream &out, int samples_per_pixel) {
1368+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
1369+
auto r = pixel_color.x();
1370+
auto g = pixel_color.y();
1371+
auto b = pixel_color.z();
1372+
13481373
// Divide the color total by the number of samples.
13491374
auto scale = 1.0 / samples_per_pixel;
1350-
auto r = scale * e[0];
1351-
auto g = scale * e[1];
1352-
auto b = scale * e[2];
1375+
r *= scale;
1376+
g *= scale;
1377+
b *= scale;
13531378

13541379
// Write the translated [0,255] value of each color component.
13551380
out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
13561381
<< static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
13571382
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
13581383
}
13591384
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1360-
[Listing [write-color-clamped]: <kbd>[vec3.h]</kbd> The write_color() function]
1385+
[Listing [write-color-clamped]: <kbd>[color.h]</kbd> The multi-sample write_color() function]
13611386

13621387
<div class='together'>
13631388
Main is also changed:
@@ -1391,7 +1416,7 @@
13911416
ray r = cam.get_ray(u, v);
13921417
pixel_color += ray_color(r, world);
13931418
}
1394-
pixel_color.write_color(std::cout, samples_per_pixel);
1419+
write_color(std::cout, pixel_color, samples_per_pixel);
13951420
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
13961421
}
13971422
}
@@ -1568,7 +1593,7 @@
15681593
pixel_color += ray_color(r, world, max_depth);
15691594
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
15701595
}
1571-
pixel_color.write_color(std::cout, samples_per_pixel);
1596+
write_color(std::cout, pixel_color, samples_per_pixel);
15721597
}
15731598
}
15741599

@@ -1599,14 +1624,17 @@
15991624
square-root:
16001625

16011626
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1602-
void write_color(std::ostream &out, int samples_per_pixel) {
1627+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
1628+
auto r = pixel_color.x();
1629+
auto g = pixel_color.y();
1630+
auto b = pixel_color.z();
1631+
16031632
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1604-
// Divide the color total by the number of samples and gamma-correct
1605-
// for a gamma value of 2.0.
1633+
// Divide the color total by the number of samples and gamma-correct for gamma=2.0.
16061634
auto scale = 1.0 / samples_per_pixel;
1607-
auto r = sqrt(scale * e[0]);
1608-
auto g = sqrt(scale * e[1]);
1609-
auto b = sqrt(scale * e[2]);
1635+
r = sqrt(scale * r);
1636+
g = sqrt(scale * g);
1637+
b = sqrt(scale * b);
16101638
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
16111639

16121640
// Write the translated [0,255] value of each color component.
@@ -1615,7 +1643,7 @@
16151643
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
16161644
}
16171645
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1618-
[Listing [write-color-gamma]: <kbd>[vec3.h]</kbd> write_color(), with gamma correction]
1646+
[Listing [write-color-gamma]: <kbd>[color.h]</kbd> write_color(), with gamma correction]
16191647

16201648
</div>
16211649

@@ -2092,7 +2120,7 @@
20922120
ray r = cam.get_ray(u, v);
20932121
pixel_color += ray_color(r, world, max_depth);
20942122
}
2095-
pixel_color.write_color(std::cout, samples_per_pixel);
2123+
write_color(std::cout, pixel_color, samples_per_pixel);
20962124
}
20972125
}
20982126

books/RayTracingTheRestOfYourLife.html

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

23732373
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2374-
void write_color(std::ostream &out, int samples_per_pixel) {
2374+
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
2375+
auto r = pixel_color.x();
2376+
auto g = pixel_color.y();
2377+
auto b = pixel_color.z();
2378+
23752379
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2376-
// Replace NaN component values with zero.
2377-
if (e[0] != e[0]) e[0] = 0.0;
2378-
if (e[1] != e[1]) e[1] = 0.0;
2379-
if (e[2] != e[2]) e[2] = 0.0;
2380+
// Replace NaN components with zero. See explanation in Ray Tracing: The Rest of Your Life.
2381+
if (r != r) r = 0.0;
2382+
if (g != g) g = 0.0;
2383+
if (b != b) b = 0.0;
2384+
23802385
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
23812386

2382-
// Divide the color total by the number of samples and gamma-correct
2383-
// for a gamma value of 2.0.
2387+
// Divide the color by the number of samples and gamma-correct for gamma=2.0.
23842388
auto scale = 1.0 / samples_per_pixel;
2385-
auto r = sqrt(scale * e[0]);
2386-
auto g = sqrt(scale * e[1]);
2387-
auto b = sqrt(scale * e[2]);
2389+
r = sqrt(scale * r);
2390+
g = sqrt(scale * g);
2391+
b = sqrt(scale * b);
23882392

23892393
// Write the translated [0,255] value of each color component.
23902394
out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
23912395
<< static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
23922396
<< static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
23932397
}
23942398
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2395-
[Listing [write-color-nan]: <kbd>[vec3.h]</kbd> NaN-tolerant write_color function]
2399+
[Listing [write-color-nan]: <kbd>[color.h]</kbd> NaN-tolerant write_color function]
23962400
</div>
23972401

23982402
<div class='together'>

src/InOneWeekend/main.cc

+2-1
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

+2-1
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

+2-1
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

+42
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)