Skip to content

Commit 3944d8d

Browse files
committed
Motivating the normal change in the text
Motivating the front_face variable First pass chapter 6 normals Rewrote struct hit_record to have vec3, then doubles, then bools Updated all sphere::hit in the books Updated sphere::hit in src Remove trailing whitespace Broke build. replaced ray_direction with r.direction() in src Replaced ray_direction with r.direction() in text Formatting error in c++ highlight Corrected previous commit for correct c++ highlight Rewrote beginning of Dielectric chapter trying to give a little bit more of an explanation Finished up first pass of dielectric chapter. DEATH WOULD BE NICE. Ported refract and dielectric changes to TheNextWeek and TheRestOf src renamed refract variables to match reflect Light touch ps in first 4 chapters Initial attempts at moving TheNextWeek over to new normal system Adding and motivating flip_face in the text Updating other hittable objects Forwarded normals changes to TheRestOfYourLife src Forward normal changes to the src boxes in the text
1 parent d76ad79 commit 3944d8d

25 files changed

+765
-286
lines changed

books/RayTracingInOneWeekend.html

Lines changed: 359 additions & 106 deletions
Large diffs are not rendered by default.

books/RayTracingTheNextWeek.html

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,18 @@
209209
rec.t = temp;
210210
rec.p = r.at(rec.t);
211211
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
212-
rec.normal = (rec.p - center(r.time())) / radius;
212+
vec3 outward_normal = (rec.p - center(r.time())) / radius;
213213
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
214+
if (dot(r.direction(), outward_normal) > 0.0) {
215+
// ray is inside the sphere
216+
rec.normal = -outward_normal;
217+
rec.front_face = false;
218+
}
219+
else {
220+
// ray is outside the sphere
221+
rec.normal = outward_normal;
222+
rec.front_face = true;
223+
}
214224
rec.mat_ptr = mat_ptr;
215225
return true;
216226
}
@@ -219,8 +229,18 @@
219229
rec.t = temp;
220230
rec.p = r.at(rec.t);
221231
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
222-
rec.normal = (rec.p - center(r.time())) / radius;
232+
vec3 outward_normal = (rec.p - center(r.time())) / radius;
223233
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
234+
if (dot(r.direction(), outward_normal) > 0.0) {
235+
// ray is inside the sphere
236+
rec.normal = -outward_normal;
237+
rec.front_face = false;
238+
}
239+
else {
240+
// ray is outside the sphere
241+
rec.normal = outward_normal;
242+
rec.front_face = true;
243+
}
224244
rec.mat_ptr = mat_ptr;
225245
return true;
226246
}
@@ -1691,9 +1711,17 @@
16911711
rec.u = (x-x0)/(x1-x0);
16921712
rec.v = (y-y0)/(y1-y0);
16931713
rec.t = t;
1714+
vec3 outward_normal = vec3(0, 0, 1);
1715+
if (dot(r.direction(), outward_normal) > 0.0) {
1716+
rec.normal = -outward_normal;
1717+
rec.front_face = false;
1718+
}
1719+
else {
1720+
rec.normal = outward_normal;
1721+
rec.front_face = true;
1722+
}
16941723
rec.mat_ptr = mp;
16951724
rec.p = r.at(t);
1696-
rec.normal = vec3(0, 0, 1);
16971725
return true;
16981726
}
16991727
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1795,9 +1823,17 @@
17951823
rec.u = (x-x0)/(x1-x0);
17961824
rec.v = (z-z0)/(z1-z0);
17971825
rec.t = t;
1826+
vec3 outward_normal = vec3(0, 1, 0);
1827+
if (dot(r.direction(), outward_normal) > 0.0) {
1828+
rec.normal = -outward_normal;
1829+
rec.front_face = false;
1830+
}
1831+
else {
1832+
rec.normal = outward_normal;
1833+
rec.front_face = true;
1834+
}
17981835
rec.mat_ptr = mp;
17991836
rec.p = r.at(t);
1800-
rec.normal = vec3(0, 1, 0);
18011837
return true;
18021838
}
18031839

@@ -1812,9 +1848,17 @@
18121848
rec.u = (y-y0)/(y1-y0);
18131849
rec.v = (z-z0)/(z1-z0);
18141850
rec.t = t;
1851+
vec3 outward_normal = vec3(1, 0, 0);
1852+
if (dot(r.direction(), outward_normal) > 0.0) {
1853+
rec.normal = -outward_normal;
1854+
rec.front_face = false;
1855+
}
1856+
else {
1857+
rec.normal = outward_normal;
1858+
rec.front_face = true;
1859+
}
18151860
rec.mat_ptr = mp;
18161861
rec.p = r.at(t);
1817-
rec.normal = vec3(1, 0, 0);
18181862
return true;
18191863
}
18201864
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1864,19 +1908,22 @@
18641908
<div class='together'>
18651909
We get:
18661910

1867-
![Empty Cornell box](../images/img.cornell-first.jpg)
1911+
![Empty Cornell box](../images/img.cornell-empty.jpg)
18681912

18691913
</div>
18701914

18711915
<div class='together'>
1872-
This is very noisy because the light is small. But why are the other walls missing? They are facing
1873-
the wrong way. We need outward facing normals. Let’s make a hittable that does nothing but hold
1874-
another hittable, but reverses the normals:
1916+
This is very noisy because the light is small. But we have a problem: Some of the walls are facing
1917+
the wrong way. We haven't specified that a diffuse material should behave differently on different
1918+
faces of the object, but what if the Cornell box had a different pattern on the inside and outside
1919+
walls? The rectangle objects are described such that their front face is always in the $(1, 0, 0)$,
1920+
$(0, 1, 0)$, or $(0, 0, 1)$ directions. We need a way to switch the faces of an object. Let’s make
1921+
a hittable that does nothing but hold another hittable, but flips the face:
18751922

18761923
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1877-
class flip_normals : public hittable {
1924+
class flip_face : public hittable {
18781925
public:
1879-
flip_normals(hittable *p) : ptr(p) {}
1926+
flip_face(hittable *p) : ptr(p) {}
18801927

18811928
virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
18821929
if (ptr->hit(r, t_min, t_max, rec)) {
@@ -1894,7 +1941,7 @@
18941941
hittable *ptr;
18951942
};
18961943
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1897-
[Listing [flip-normals]: <kbd>[hittable.h]</kbd> Flip-normals function]
1944+
[Listing [flip-face]: <kbd>[hittable.h]</kbd> Flip-Face function]
18981945
</div>
18991946

19001947
<div class='together'>
@@ -1910,16 +1957,16 @@
19101957
material *light = new diffuse_light(new constant_texture(vec3(15, 15, 15)));
19111958

19121959
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1913-
list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green));
1960+
list[i++] = new flip_face(new yz_rect(0, 555, 0, 555, 555, green));
19141961
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19151962
list[i++] = new yz_rect(0, 555, 0, 555, 0, red);
19161963
list[i++] = new xz_rect(213, 343, 227, 332, 554, light);
19171964
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1918-
list[i++] = new flip_normals(new xz_rect(0, 555, 0, 555, 555, white));
1965+
list[i++] = new flip_face(new xz_rect(0, 555, 0, 555, 555, white));
19191966
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19201967
list[i++] = new xz_rect(0, 555, 0, 555, 0, white);
19211968
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1922-
list[i++] = new flip_normals(new xy_rect(0, 555, 0, 555, 555, white));
1969+
list[i++] = new flip_face(new xy_rect(0, 555, 0, 555, 555, white));
19231970
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19241971

19251972
return new hittable_list(list,i);
@@ -1965,11 +2012,11 @@
19652012
pmax = p1;
19662013
hittable **list = new hittable*[6];
19672014
list[0] = new xy_rect(p0.x(), p1.x(), p0.y(), p1.y(), p1.z(), ptr);
1968-
list[1] = new flip_normals(new xy_rect(p0.x(), p1.x(), p0.y(), p1.y(), p0.z(), ptr));
2015+
list[1] = new flip_face(new xy_rect(p0.x(), p1.x(), p0.y(), p1.y(), p0.z(), ptr));
19692016
list[2] = new xz_rect(p0.x(), p1.x(), p0.z(), p1.z(), p1.y(), ptr);
1970-
list[3] = new flip_normals(new xz_rect(p0.x(), p1.x(), p0.z(), p1.z(), p0.y(), ptr));
2017+
list[3] = new flip_face(new xz_rect(p0.x(), p1.x(), p0.z(), p1.z(), p0.y(), ptr));
19712018
list[4] = new yz_rect(p0.y(), p1.y(), p0.z(), p1.z(), p1.x(), ptr);
1972-
list[5] = new flip_normals(new yz_rect(p0.y(), p1.y(), p0.z(), p1.z(), p0.x(), ptr));
2019+
list[5] = new flip_face(new yz_rect(p0.y(), p1.y(), p0.z(), p1.z(), p0.x(), ptr));
19732020
list_ptr = new hittable_list(list,6);
19742021
}
19752022

@@ -2032,6 +2079,13 @@
20322079
ray moved_r(r.origin() - offset, r.direction(), r.time());
20332080
if (ptr->hit(moved_r, t_min, t_max, rec)) {
20342081
rec.p += offset;
2082+
if (dot(moved_r.direction(), rec.normal) > 0.0) {
2083+
rec.normal = -rec.normal;
2084+
rec.front_face = false;
2085+
}
2086+
else {
2087+
rec.front_face = true;
2088+
}
20352089
return true;
20362090
}
20372091
else
@@ -2171,7 +2225,14 @@
21712225
normal[0] = cos_theta*rec.normal[0] + sin_theta*rec.normal[2];
21722226
normal[2] = -sin_theta*rec.normal[0] + cos_theta*rec.normal[2];
21732227
rec.p = p;
2174-
rec.normal = normal;
2228+
if (dot(rotated_r.direction(), normal) > 0.0) {
2229+
rec.normal = -normal;
2230+
rec.front_face = false;
2231+
}
2232+
else {
2233+
rec.normal = normal;
2234+
rec.front_face = true;
2235+
}
21752236
return true;
21762237
}
21772238
else
@@ -2323,6 +2384,7 @@
23232384
}
23242385

23252386
rec.normal = vec3(1,0,0); // arbitrary
2387+
rec.front_face = true; // also arbitrary
23262388
rec.mat_ptr = phase_function;
23272389
return true;
23282390
}
@@ -2351,12 +2413,12 @@
23512413
material *green = new lambertian(new constant_texture(vec3(0.12, 0.45, 0.15)));
23522414
material *light = new diffuse_light(new constant_texture(vec3(7, 7, 7)));
23532415

2354-
list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green));
2416+
list[i++] = new flip_face(new yz_rect(0, 555, 0, 555, 555, green));
23552417
list[i++] = new yz_rect(0, 555, 0, 555, 0, red);
23562418
list[i++] = new xz_rect(113, 443, 127, 432, 554, light);
2357-
list[i++] = new flip_normals(new xz_rect(0, 555, 0, 555, 555, white));
2419+
list[i++] = new flip_face(new xz_rect(0, 555, 0, 555, 555, white));
23582420
list[i++] = new xz_rect(0, 555, 0, 555, 0, white);
2359-
list[i++] = new flip_normals(new xy_rect(0, 555, 0, 555, 555, white));
2421+
list[i++] = new flip_face(new xy_rect(0, 555, 0, 555, 555, white));
23602422

23612423
hittable *b1 = new translate(
23622424
new rotate_y(new box(vec3(0, 0, 0), vec3(165, 165, 165), white), -18),

books/RayTracingTheRestOfYourLife.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -736,12 +736,12 @@
736736

737737
hittable **list = new hittable*[8];
738738
int i = 0;
739-
list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green));
739+
list[i++] = new flip_face(new yz_rect(0, 555, 0, 555, 555, green));
740740
list[i++] = new yz_rect(0, 555, 0, 555, 0, red);
741741
list[i++] = new xz_rect(213, 343, 227, 332, 554, light);
742-
list[i++] = new flip_normals(new xz_rect(0, 555, 0, 555, 555, white));
742+
list[i++] = new flip_face(new xz_rect(0, 555, 0, 555, 555, white));
743743
list[i++] = new xz_rect(0, 555, 0, 555, 0, white);
744-
list[i++] = new flip_normals(new xy_rect(0, 555, 0, 555, 555, white));
744+
list[i++] = new flip_face(new xy_rect(0, 555, 0, 555, 555, white));
745745
list[i++] = new translate(new rotate_y(
746746
new box(vec3(0, 0, 0), vec3(165, 165, 165), white), -18), vec3(130,0,65));
747747
list[i++] = new translate(new rotate_y(
@@ -1338,7 +1338,7 @@
13381338
virtual vec3 emitted(const ray& r_in, const hit_record& rec, double u, double v,
13391339
const vec3& p) const {
13401340

1341-
if (dot(rec.normal, r_in.direction()) < 0.0)
1341+
if (rec.front_face)
13421342
return emit->value(u, v, p);
13431343
else
13441344
return vec3(0,0,0);
@@ -1917,12 +1917,12 @@
19171917
material *white = new lambertian( new constant_texture(vec3(0.73, 0.73, 0.73)) );
19181918
material *green = new lambertian( new constant_texture(vec3(0.12, 0.45, 0.15)) );
19191919
material *light = new diffuse_light( new constant_texture(vec3(15, 15, 15)) );
1920-
list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green));
1920+
list[i++] = new flip_face(new yz_rect(0, 555, 0, 555, 555, green));
19211921
list[i++] = new yz_rect(0, 555, 0, 555, 0, red);
1922-
list[i++] = new flip_normals(new xz_rect(213, 343, 227, 332, 554, light));
1923-
list[i++] = new flip_normals(new xz_rect(0, 555, 0, 555, 555, white));
1922+
list[i++] = new flip_face(new xz_rect(213, 343, 227, 332, 554, light));
1923+
list[i++] = new flip_face(new xz_rect(0, 555, 0, 555, 555, white));
19241924
list[i++] = new xz_rect(0, 555, 0, 555, 0, white);
1925-
list[i++] = new flip_normals(new xy_rect(0, 555, 0, 555, 555, white));
1925+
list[i++] = new flip_face(new xy_rect(0, 555, 0, 555, 555, white));
19261926
list[i++] = new translate(
19271927
new rotate_y(new box(vec3(0, 0, 0), vec3(165, 165, 165), white), -18),
19281928
vec3(130,0,65));

images/img.glass-always-refract.png

18.8 KB
Loading

images/img.glass-hollow.png

13.9 KB
Loading
20.1 KB
Loading

src/InOneWeekend/hittable.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
class material;
1818

1919
struct hit_record {
20-
double t;
2120
vec3 p;
2221
vec3 normal;
2322
material *mat_ptr;
23+
double t;
24+
bool front_face;
2425
};
2526

2627
class hittable {

src/InOneWeekend/material.h

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,34 @@ class dielectric : public material {
3838

3939
virtual bool scatter(
4040
const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered
41-
) const {
42-
vec3 outward_normal;
43-
vec3 reflected = reflect(r_in.direction(), rec.normal);
44-
double ni_over_nt;
41+
) const {
4542
attenuation = vec3(1.0, 1.0, 1.0);
46-
vec3 refracted;
47-
double reflect_prob;
48-
double cosine;
49-
50-
if (dot(r_in.direction(), rec.normal) > 0) {
51-
outward_normal = -rec.normal;
52-
ni_over_nt = ref_idx;
53-
cosine = dot(r_in.direction(), rec.normal) / r_in.direction().length();
54-
cosine = sqrt(1 - ref_idx*ref_idx*(1-cosine*cosine));
43+
double etai_over_etat;
44+
if (rec.front_face) {
45+
etai_over_etat = 1.0 / ref_idx;
5546
} else {
56-
outward_normal = rec.normal;
57-
ni_over_nt = 1.0 / ref_idx;
58-
cosine = -dot(r_in.direction(), rec.normal) / r_in.direction().length();
47+
etai_over_etat = ref_idx;
5948
}
6049

61-
if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted)) {
62-
reflect_prob = schlick(cosine, ref_idx);
63-
} else {
64-
reflect_prob = 1.0;
50+
vec3 unit_direction = unit_vector(r_in.direction());
51+
double cos_theta = ffmin(dot(-unit_direction, rec.normal), 1.0);
52+
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
53+
if (etai_over_etat * sin_theta > 1.0 ) {
54+
vec3 reflected = reflect(unit_direction, rec.normal);
55+
scattered = ray(rec.p, reflected);
56+
return true;
6557
}
66-
67-
if (random_double() < reflect_prob) {
68-
scattered = ray(rec.p, reflected);
69-
} else {
70-
scattered = ray(rec.p, refracted);
58+
59+
double reflect_prob = schlick(cos_theta, etai_over_etat);
60+
if (random_double() < reflect_prob)
61+
{
62+
vec3 reflected = reflect(unit_direction, rec.normal);
63+
scattered = ray(rec.p, reflected);
64+
return true;
7165
}
72-
66+
67+
vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat);
68+
scattered = ray(rec.p, refracted);
7369
return true;
7470
}
7571

src/InOneWeekend/sphere.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,35 @@ bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) cons
3939
if (temp < t_max && temp > t_min) {
4040
rec.t = temp;
4141
rec.p = r.at(rec.t);
42-
rec.normal = (rec.p - center) / radius;
42+
vec3 outward_normal = (rec.p - center) / radius;
43+
if (dot(r.direction(), outward_normal) > 0.0) {
44+
// ray is inside the sphere
45+
rec.normal = -outward_normal;
46+
rec.front_face = false;
47+
}
48+
else {
49+
// ray is outside the sphere
50+
rec.normal = outward_normal;
51+
rec.front_face = true;
52+
}
4353
rec.mat_ptr = mat_ptr;
4454
return true;
4555
}
4656
temp = (-half_b + root) / a;
4757
if (temp < t_max && temp > t_min) {
4858
rec.t = temp;
4959
rec.p = r.at(rec.t);
50-
rec.normal = (rec.p - center) / radius;
60+
vec3 outward_normal = (rec.p - center) / radius;
61+
if (dot(r.direction(), outward_normal) > 0.0) {
62+
// ray is inside the sphere
63+
rec.normal = -outward_normal;
64+
rec.front_face = false;
65+
}
66+
else {
67+
// ray is outside the sphere
68+
rec.normal = outward_normal;
69+
rec.front_face = true;
70+
}
5171
rec.mat_ptr = mat_ptr;
5272
return true;
5373
}

0 commit comments

Comments
 (0)