Skip to content

Commit 0afae2e

Browse files
authored
Merge pull request #312 from RayTracing/tdb/normals_and_dielectrics_rebase
Motivating the normal change in the text
2 parents cf3b2bd + f3df879 commit 0afae2e

25 files changed

+521
-287
lines changed

books/RayTracingInOneWeekend.html

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

books/RayTracingTheNextWeek.html

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@
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+
rec.set_face_normal(r, outward_normal);
214215
rec.mat_ptr = mat_ptr;
215216
return true;
216217
}
@@ -219,8 +220,9 @@
219220
rec.t = temp;
220221
rec.p = r.at(rec.t);
221222
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
222-
rec.normal = (rec.p - center(r.time())) / radius;
223+
vec3 outward_normal = (rec.p - center(r.time())) / radius;
223224
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
225+
rec.set_face_normal(r, outward_normal);
224226
rec.mat_ptr = mat_ptr;
225227
return true;
226228
}
@@ -1728,9 +1730,10 @@
17281730
rec.u = (x-x0)/(x1-x0);
17291731
rec.v = (y-y0)/(y1-y0);
17301732
rec.t = t;
1733+
vec3 outward_normal = vec3(0, 0, 1);
1734+
rec.set_face_normal(r, outward_normal);
17311735
rec.mat_ptr = mp;
17321736
rec.p = r.at(t);
1733-
rec.normal = vec3(0, 0, 1);
17341737
return true;
17351738
}
17361739
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1834,9 +1837,10 @@
18341837
rec.u = (x-x0)/(x1-x0);
18351838
rec.v = (z-z0)/(z1-z0);
18361839
rec.t = t;
1840+
vec3 outward_normal = vec3(0, 1, 0);
1841+
rec.set_face_normal(r, outward_normal);
18371842
rec.mat_ptr = mp;
18381843
rec.p = r.at(t);
1839-
rec.normal = vec3(0, 1, 0);
18401844
return true;
18411845
}
18421846

@@ -1851,9 +1855,10 @@
18511855
rec.u = (y-y0)/(y1-y0);
18521856
rec.v = (z-z0)/(z1-z0);
18531857
rec.t = t;
1858+
vec3 outward_normal = vec3(1, 0, 0);
1859+
rec.set_face_normal(r, outward_normal);
18541860
rec.mat_ptr = mp;
18551861
rec.p = r.at(t);
1856-
rec.normal = vec3(1, 0, 0);
18571862
return true;
18581863
}
18591864
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1903,23 +1908,26 @@
19031908
<div class='together'>
19041909
We get:
19051910

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

19081913
</div>
19091914

19101915
<div class='together'>
1911-
This is very noisy because the light is small. But why are the other walls missing? They are facing
1912-
the wrong way. We need outward facing normals. Let’s make a hittable that does nothing but hold
1913-
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 faces are always in the
1920+
$(1, 0, 0)$, $(0, 1, 0)$, or $(0, 0, 1)$ directions. We need a way to switch the faces of an
1921+
object. Let’s make a hittable that does nothing but hold another hittable, and flips the face:
19141922

19151923
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
1916-
class flip_normals : public hittable {
1924+
class flip_face : public hittable {
19171925
public:
1918-
flip_normals(hittable *p) : ptr(p) {}
1926+
flip_face(hittable *p) : ptr(p) {}
19191927

19201928
virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
19211929
if (ptr->hit(r, t_min, t_max, rec)) {
1922-
rec.normal = -rec.normal;
1930+
rec.front_face = !rec.front_face;
19231931
return true;
19241932
}
19251933
else
@@ -1933,7 +1941,7 @@
19331941
hittable *ptr;
19341942
};
19351943
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1936-
[Listing [flip-normals]: <kbd>[hittable.h]</kbd> Flip-normals function]
1944+
[Listing [flip-face]: <kbd>[hittable.h]</kbd> Flip-Face function]
19371945
</div>
19381946

19391947
<div class='together'>
@@ -1949,16 +1957,16 @@
19491957
material *light = new diffuse_light(new constant_texture(vec3(15, 15, 15)));
19501958

19511959
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1952-
objects.add(new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)));
1960+
objects.add(new flip_face(new yz_rect(0, 555, 0, 555, 555, green)));
19531961
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19541962
objects.add(new yz_rect(0, 555, 0, 555, 0, red));
19551963
objects.add(new xz_rect(213, 343, 227, 332, 554, light));
19561964
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1957-
objects.add(new flip_normals(new xz_rect(0, 555, 0, 555, 555, white)));
1965+
objects.add(new flip_face(new xz_rect(0, 555, 0, 555, 555, white)));
19581966
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19591967
objects.add(new xz_rect(0, 555, 0, 555, 0, white));
19601968
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
1961-
objects.add(new flip_normals(new xy_rect(0, 555, 0, 555, 555, white)));
1969+
objects.add(new flip_face(new xy_rect(0, 555, 0, 555, 555, white)));
19621970
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
19631971

19641972
return objects;
@@ -2004,11 +2012,11 @@
20042012
pmax = p1;
20052013
hittable **list = new hittable*[6];
20062014
list[0] = new xy_rect(p0.x(), p1.x(), p0.y(), p1.y(), p1.z(), ptr);
2007-
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));
20082016
list[2] = new xz_rect(p0.x(), p1.x(), p0.z(), p1.z(), p1.y(), ptr);
2009-
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));
20102018
list[4] = new yz_rect(p0.y(), p1.y(), p0.z(), p1.z(), p1.x(), ptr);
2011-
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));
20122020
list_ptr = new hittable_list(list,6);
20132021
}
20142022

@@ -2071,6 +2079,7 @@
20712079
ray moved_r(r.origin() - offset, r.direction(), r.time());
20722080
if (ptr->hit(moved_r, t_min, t_max, rec)) {
20732081
rec.p += offset;
2082+
rec.set_face_normal(moved_r, rec.normal);
20742083
return true;
20752084
}
20762085
else
@@ -2210,7 +2219,7 @@
22102219
normal[0] = cos_theta*rec.normal[0] + sin_theta*rec.normal[2];
22112220
normal[2] = -sin_theta*rec.normal[0] + cos_theta*rec.normal[2];
22122221
rec.p = p;
2213-
rec.normal = normal;
2222+
rec.set_face_normal(rotated_r, normal);
22142223
return true;
22152224
}
22162225
else
@@ -2363,6 +2372,7 @@
23632372
}
23642373

23652374
rec.normal = vec3(1,0,0); // arbitrary
2375+
rec.front_face = true; // also arbitrary
23662376
rec.mat_ptr = phase_function;
23672377
return true;
23682378
}
@@ -2391,12 +2401,12 @@
23912401
auto green = new lambertian(new constant_texture(vec3(0.12, 0.45, 0.15)));
23922402
auto light = new diffuse_light(new constant_texture(vec3(7, 7, 7)));
23932403

2394-
objects.add(new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)));
2404+
objects.add(new flip_face(new yz_rect(0, 555, 0, 555, 555, green)));
23952405
objects.add(new yz_rect(0, 555, 0, 555, 0, red));
23962406
objects.add(new xz_rect(113, 443, 127, 432, 554, light));
2397-
objects.add(new flip_normals(new xz_rect(0, 555, 0, 555, 555, white)));
2407+
objects.add(new flip_face(new xz_rect(0, 555, 0, 555, 555, white)));
23982408
objects.add(new xz_rect(0, 555, 0, 555, 0, white));
2399-
objects.add(new flip_normals(new xy_rect(0, 555, 0, 555, 555, white)));
2409+
objects.add(new flip_face(new xy_rect(0, 555, 0, 555, 555, white)));
24002410

24012411
hittable* box1 = new box(vec3(0,0,0), vec3(165,330,165), white);
24022412
box1 = new rotate_y(box1, 15);

books/RayTracingTheRestOfYourLife.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -736,12 +736,12 @@
736736
auto *green = new lambertian(new constant_texture(vec3(0.12, 0.45, 0.15)));
737737
auto *light = new diffuse_light(new constant_texture(vec3(15, 15, 15)));
738738

739-
world.add(new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)));
739+
world.add(new flip_face(new yz_rect(0, 555, 0, 555, 555, green)));
740740
world.add(new yz_rect(0, 555, 0, 555, 0, red));
741741
world.add(new xz_rect(213, 343, 227, 332, 554, light));
742-
world.add(new flip_normals(new xz_rect(0, 555, 0, 555, 555, white)));
742+
world.add(new flip_face(new xz_rect(0, 555, 0, 555, 555, white)));
743743
world.add(new xz_rect(0, 555, 0, 555, 0, white));
744-
world.add(new flip_normals(new xy_rect(0, 555, 0, 555, 555, white)));
744+
world.add(new flip_face(new xy_rect(0, 555, 0, 555, 555, white)));
745745

746746
hittable* box1 = new box(vec3(0,0,0), vec3(165,330,165), white);
747747
box1 = new rotate_y(box1, 15);
@@ -1363,7 +1363,7 @@
13631363
virtual vec3 emitted(const ray& r_in, const hit_record& rec, double u, double v,
13641364
const vec3& p) const {
13651365

1366-
if (dot(rec.normal, r_in.direction()) < 0.0)
1366+
if (rec.front_face)
13671367
return emit->value(u, v, p);
13681368
else
13691369
return vec3(0,0,0);
@@ -1972,12 +1972,12 @@
19721972
auto *green = new lambertian(new constant_texture(vec3(0.12, 0.45, 0.15)));
19731973
auto *light = new diffuse_light(new constant_texture(vec3(15, 15, 15)));
19741974

1975-
world.add(new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)));
1975+
world.add(new flip_face(new yz_rect(0, 555, 0, 555, 555, green)));
19761976
world.add(new yz_rect(0, 555, 0, 555, 0, red));
19771977
world.add(new xz_rect(213, 343, 227, 332, 554, light));
1978-
world.add(new flip_normals(new xz_rect(0, 555, 0, 555, 555, white)));
1978+
world.add(new flip_face(new xz_rect(0, 555, 0, 555, 555, white)));
19791979
world.add(new xz_rect(0, 555, 0, 555, 0, white));
1980-
world.add(new flip_normals(new xy_rect(0, 555, 0, 555, 555, white)));
1980+
world.add(new flip_face(new xy_rect(0, 555, 0, 555, 555, white)));
19811981

19821982
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
19831983
material *aluminum = new metal(vec3(0.8, 0.85, 0.88), 0.0);

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: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@
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;
25+
26+
inline void set_face_normal(const ray& r, const vec3& outward_normal) {
27+
front_face = dot(r.direction(), outward_normal) < 0;
28+
normal = front_face ? outward_normal :-outward_normal;
29+
}
2430
};
2531

2632
class hittable {

src/InOneWeekend/material.h

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,29 @@ 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));
55-
} 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();
43+
double etai_over_etat = (rec.front_face) ? (1.0 / ref_idx) : (ref_idx);
44+
45+
vec3 unit_direction = unit_vector(r_in.direction());
46+
double cos_theta = ffmin(dot(-unit_direction, rec.normal), 1.0);
47+
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
48+
if (etai_over_etat * sin_theta > 1.0 ) {
49+
vec3 reflected = reflect(unit_direction, rec.normal);
50+
scattered = ray(rec.p, reflected);
51+
return true;
5952
}
60-
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;
53+
54+
double reflect_prob = schlick(cos_theta, etai_over_etat);
55+
if (random_double() < reflect_prob)
56+
{
57+
vec3 reflected = reflect(unit_direction, rec.normal);
58+
scattered = ray(rec.p, reflected);
59+
return true;
6560
}
66-
67-
if (random_double() < reflect_prob) {
68-
scattered = ray(rec.p, reflected);
69-
} else {
70-
scattered = ray(rec.p, refracted);
71-
}
72-
61+
62+
vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat);
63+
scattered = ray(rec.p, refracted);
7364
return true;
7465
}
7566

src/InOneWeekend/sphere.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ 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+
rec.set_face_normal(r, outward_normal);
4344
rec.mat_ptr = mat_ptr;
4445
return true;
4546
}
4647
temp = (-half_b + root) / a;
4748
if (temp < t_max && temp > t_min) {
4849
rec.t = temp;
4950
rec.p = r.at(rec.t);
50-
rec.normal = (rec.p - center) / radius;
51+
vec3 outward_normal = (rec.p - center) / radius;
52+
rec.set_face_normal(r, outward_normal);
5153
rec.mat_ptr = mat_ptr;
5254
return true;
5355
}

src/TheNextWeek/aarect.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,10 @@ bool xy_rect::hit(const ray& r, double t0, double t1, hit_record& rec) const {
8080
rec.u = (x-x0)/(x1-x0);
8181
rec.v = (y-y0)/(y1-y0);
8282
rec.t = t;
83+
vec3 outward_normal = vec3(0, 0, 1);
84+
rec.set_face_normal(r, outward_normal);
8385
rec.mat_ptr = mp;
8486
rec.p = r.at(t);
85-
rec.normal = vec3(0, 0, 1);
8687
return true;
8788
}
8889

@@ -97,9 +98,10 @@ bool xz_rect::hit(const ray& r, double t0, double t1, hit_record& rec) const {
9798
rec.u = (x-x0)/(x1-x0);
9899
rec.v = (z-z0)/(z1-z0);
99100
rec.t = t;
101+
vec3 outward_normal = vec3(0, 1, 0);
102+
rec.set_face_normal(r, outward_normal);
100103
rec.mat_ptr = mp;
101104
rec.p = r.at(t);
102-
rec.normal = vec3(0, 1, 0);
103105
return true;
104106
}
105107

@@ -114,9 +116,10 @@ bool yz_rect::hit(const ray& r, double t0, double t1, hit_record& rec) const {
114116
rec.u = (y-y0)/(y1-y0);
115117
rec.v = (z-z0)/(z1-z0);
116118
rec.t = t;
119+
vec3 outward_normal = vec3(1, 0, 0);
120+
rec.set_face_normal(r, outward_normal);
117121
rec.mat_ptr = mp;
118122
rec.p = r.at(t);
119-
rec.normal = vec3(1, 0, 0);
120123
return true;
121124
}
122125

0 commit comments

Comments
 (0)