diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html
index 44a6ce77..ac7d8768 100644
--- a/books/RayTracingTheRestOfYourLife.html
+++ b/books/RayTracingTheRestOfYourLife.html
@@ -317,10 +317,12 @@
cam.render(world);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [estpi-3]: [main.cc] Stratifying the samples inside pixels]
+ [Listing [estpi-3]: [main.cc] Cornell box, revisited]
Run this program to generate an un-stratified render and save for comparison.
+Now make the following changes to implement a stratified sampling procedure:
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
class camera {
public:
@@ -476,20 +478,13 @@
Our work above is equally valid as a means to solve for $\pi$ as it is a means to solve for the area
-of a circle. So we could make the following substitution in the first version of our program:
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
- int main() {
- ...
-
+of a circle. So we could make the following substitution in one of the first versions of our pi
+program:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ delete
std::cout << "Estimate of Pi = " << (4.0 * inside_circle) / N << '\n';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
std::cout << "Estimated area of unit circle = " << (4.0 * inside_circle) / N << '\n';
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Listing [estunitcircle]: [pi.cc] Estimating area of unit circle]
@@ -1186,6 +1181,7 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
int N = 1000000;
auto sum = 0.0;
+
for (int i = 0; i < N; i++) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
auto x = f(random_double());
@@ -1748,10 +1744,10 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
double scattering_pdf = rec.mat->scattering_pdf(r, rec, scattered);
- double pdf = scattering_pdf;
+ double pdf_value = scattering_pdf;
color color_from_scatter =
- (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf;
+ (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf_value;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
return color_from_emission + color_from_scatter;
@@ -1765,7 +1761,7 @@
You should get exactly the same picture. Which _should make sense_, as the scattered part of
-`ray_color` is getting multiplied by `scattering_pdf / pdf`, and as `pdf` is equal to
+`ray_color` is getting multiplied by `scattering_pdf / pdf_value`, and as `pdf_value` is equal to
`scattering_pdf` is just the same as multiplying by one.
@@ -1804,11 +1800,11 @@
double scattering_pdf = rec.mat->scattering_pdf(r, rec, scattered);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- double pdf = 1 / (2*pi);
+ double pdf_value = 1 / (2*pi);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
color color_from_scatter =
- (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf;
+ (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf_value;
return color_from_emission + color_from_scatter;
}
@@ -1830,7 +1826,7 @@
double scattering_pdf = rec.mat->scattering_pdf(r, rec, scattered);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- double pdf = scattering_pdf;
+ double pdf_value = scattering_pdf;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
...
@@ -2312,8 +2308,10 @@
class hit_record;
class material {
+ public:
...
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
virtual bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, double& pdf
@@ -2351,59 +2349,88 @@
};
class metal : public material {
- public:
- ...
+ public:
+ ...
+
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, double& pdf
) const override {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
+ ...
}
- };
+ };
class dielectric : public material {
- public:
- ...
+ public:
+ ...
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, double& pdf
) const override {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
+ ...
}
- };
+ };
class diffuse_light : public material {
- public:
- ...
+ ...
+ };
+
+ class isotropic : public material {
+ public:
+ ...
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, double& pdf
) const override {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
+ ...
}
- };
+ };
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ [Listing [scatter-onb]:
Which produces:
@@ -2427,8 +2454,8 @@
bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, double& pdf
) const override {
- attenuation = tex->value(rec.u, rec.v, rec.p);
scattered = ray(rec.p, random_unit_vector(), r_in.time());
+ attenuation = tex->value(rec.u, rec.v, rec.p);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
pdf = 1 / (4 * pi);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
@@ -2511,6 +2538,8 @@
class camera {
...
private:
+ ...
+
color ray_color(const ray& r, int depth, const hittable& world) const {
// If we've exceeded the ray bounce limit, no more light is gathered.
if (depth <= 0)
@@ -2524,15 +2553,10 @@
ray scattered;
color attenuation;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- double pdf;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ double pdf_value; // TODO: What are we supposed to do with the returned PDF?
color color_from_emission = rec.mat->emitted(rec.u, rec.v, rec.p);
-
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
- if (!rec.mat->scatter(r, rec, attenuation, scattered, pdf))
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ if (!rec.mat->scatter(r, rec, attenuation, scattered, pdf_value))
return color_from_emission;
@@ -2550,14 +2574,14 @@
if (light_cosine < 0.000001)
return color_from_emission;
- pdf = distance_squared / (light_cosine * light_area);
+ pdf_value = distance_squared / (light_cosine * light_area);
scattered = ray(rec.p, to_light, r.time());
double scattering_pdf = rec.mat->scattering_pdf(r, rec, scattered);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
color color_from_scatter =
- (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf;
+ (attenuation * scattering_pdf * ray_color(scattered, depth-1, world)) / pdf_value;
return color_from_emission + color_from_scatter;
}
@@ -2565,7 +2589,23 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Listing [ray-color-lights]:
[camera.h] Ray color with light sampling]
-
+We'll test this scene with just ten samples per pixel:
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ int main() {
+ ...
+ cam.aspect_ratio = 1.0;
+ cam.image_width = 600;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
+ cam.samples_per_pixel = 10;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ cam.max_depth = 50;
+ cam.background = color(0,0,0);
+ ...
+ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ [Listing [ray-color-lights-10spp]: [main.cc] Ray color with light sampling at 10spp]
+
With 10 samples per pixel this yields:
![Image 7: Cornell box, sampling only the light, 10 samples per pixel
@@ -2574,8 +2614,6 @@
This is about what we would expect from something that samples only the light sources, so this
appears to work.
-
-
Switching to Unidirectional Light
----------------------------------
@@ -2609,7 +2647,7 @@
const override {
if (!rec.front_face)
return color(0,0,0);
- return emit->value(u, v, p);
+ return tex->value(u, v, p);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
@@ -2699,7 +2737,7 @@
#endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [class-pdf]:
[pdf.h] The abstract pdf class]
+ [Listing [class-pdf]:
[pdf.h] The abstract PDF class]
@@ -2721,7 +2759,7 @@
}
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [class-uni-pdf]:
+And set the render back to 1000 samples per pixel:
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ int main() {
+ ...
+ cam.aspect_ratio = 1.0;
+ cam.image_width = 600;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
+ cam.samples_per_pixel = 1000;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ cam.max_depth = 50;
+ cam.background = color(0,0,0);
+ ...
+ }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ [Listing [cosine-density-1000spp]: [main.cc] Reset sampling back to 1000spp]
@@ -2824,9 +2878,16 @@
Now we can try sampling directions toward a `hittable`, like the light.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
- ...
+ #include "rtweekend.h"
+
+
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
#include "hittable_list.h"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
+ #include "onb.h"
+
...
+
class hittable_pdf : public pdf {
public:
hittable_pdf(const hittable& objects, const point3& origin)
@@ -2859,7 +2920,11 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
class hittable {
public:
- ...
+ virtual ~hittable() = default;
+
+ virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0;
+
+ virtual aabb bounding_box() const = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
@@ -2868,7 +2933,7 @@
}
virtual vec3 random(const point3& origin) const {
- return vec3(1, 0, 0);
+ return vec3(1,0,0);
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
};
@@ -2896,6 +2961,7 @@
set_bounding_box();
}
+
...
@@ -2930,7 +2996,7 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- [Listing [quad-pdf]: