Skip to content

Commit d67a7fa

Browse files
authored
Merge pull request #745 from RayTracing/refactor-dielectric
Another small refactor for dielectric scatter()
2 parents 689163d + 8416196 commit d67a7fa

File tree

6 files changed

+69
-88
lines changed

6 files changed

+69
-88
lines changed

books/RayTracingInOneWeekend.html

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,6 +2405,7 @@
24052405

24062406
vec3 unit_direction = unit_vector(r_in.direction());
24072407
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
2408+
24082409
scattered = ray(rec.p, refracted);
24092410
return true;
24102411
}
@@ -2520,17 +2521,15 @@
25202521
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
25212522

25222523
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
2524+
vec3 direction;
25232525

2524-
// If the ray cannot refract, then return the reflected path.
25252526
if (cannot_refract) {
2526-
vec3 reflected = reflect(unit_direction, rec.normal);
2527-
scattered = ray(rec.p, reflected);
2528-
return true;
2529-
}
2530-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2527+
direction = reflect(unit_direction, rec.normal);
2528+
else
2529+
direction = refract(unit_direction, rec.normal, refraction_ratio);
25312530

2532-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
2533-
scattered = ray(rec.p, refracted);
2531+
scattered = ray(rec.p, direction);
2532+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
25342533
return true;
25352534
}
25362535

@@ -2566,20 +2565,9 @@
25662565
<div class='together'>
25672566
Now real glass has reflectivity that varies with angle -- look at a window at a steep angle and it
25682567
becomes a mirror. There is a big ugly equation for that, but almost everybody uses a cheap and
2569-
surprisingly accurate polynomial approximation by Christophe Schlick:
2570-
2571-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2572-
double schlick(double cosine, double ref_idx) {
2573-
auto r0 = (1-ref_idx) / (1+ref_idx);
2574-
r0 = r0*r0;
2575-
return r0 + (1-r0)*pow((1 - cosine),5);
2576-
}
2577-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2578-
[Listing [schlick]: <kbd>[material.h]</kbd> Schlick approximation]
2579-
</div>
2568+
surprisingly accurate polynomial approximation by Christophe Schlick. This yields our full glass
2569+
material:
25802570

2581-
<div class='together'>
2582-
This yields our full glass material:
25832571
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
25842572
class dielectric : public material {
25852573
public:
@@ -2596,24 +2584,31 @@
25962584
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
25972585

25982586
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
2587+
vec3 direction;
25992588

26002589
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2601-
// If the ray cannot refract, or if it probabilistically reflects because of its
2602-
// grazing angle, then return the reflected path.
2603-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
2590+
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
26042591
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2605-
vec3 reflected = reflect(unit_direction, rec.normal);
2606-
scattered = ray(rec.p, reflected);
2607-
return true;
2608-
}
2592+
direction = reflect(unit_direction, rec.normal);
2593+
else
2594+
direction = refract(unit_direction, rec.normal, refraction_ratio);
26092595

2610-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
2611-
scattered = ray(rec.p, refracted);
2596+
scattered = ray(rec.p, direction);
26122597
return true;
26132598
}
26142599

26152600
public:
26162601
double ir; // Index of Refraction
2602+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2603+
2604+
private:
2605+
static double reflectance(double cosine, double ref_idx) {
2606+
// Use Schlick's approximation for reflectance.
2607+
auto r0 = (1-ref_idx) / (1+ref_idx);
2608+
r0 = r0*r0;
2609+
return r0 + (1-r0)*pow((1 - cosine),5);
2610+
}
2611+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
26172612
};
26182613
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26192614
[Listing [glass]: <kbd>[material.h]</kbd> Full glass material]

books/RayTracingTheNextWeek.html

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,9 @@
308308
class dielectric : public material {
309309
...
310310
virtual bool scatter(
311-
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered
312-
) const override {
313-
314311
...
315-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
316-
vec3 reflected = reflect(unit_direction, rec.normal);
317-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
318-
scattered = ray(rec.p, reflected, r_in.time());
319-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
320-
return true;
321-
}
322-
323-
vec3 refracted = refract(unit_direction, rec.normal, etai_over_etat);
324312
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
325-
scattered = ray(rec.p, refracted, r_in.time());
313+
scattered = ray(rec.p, direction, r_in.time());
326314
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
327315
return true;
328316
}

books/RayTracingTheRestOfYourLife.html

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,19 +2161,9 @@
21612161
srec.attenuation = color(1.0, 1.0, 1.0);
21622162
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
21632163
double refraction_ratio = rec.front_face ? (1.0/ir) : ir;
2164-
21652164
...
2166-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
2167-
vec3 reflected = reflect(unit_direction, rec.normal);
2168-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2169-
srec.specular_ray = ray(rec.p, reflected, r_in.time());
2170-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
2171-
return true;
2172-
}
2173-
2174-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
21752165
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
2176-
srec.specular_ray = ray(rec.p, refracted, r_in.time());
2166+
srec.specular_ray = ray(rec.p, direction, r_in.time());
21772167
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
21782168
return true;
21792169
}

src/InOneWeekend/material.h

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@
1717
struct hit_record;
1818

1919

20-
double schlick(double cosine, double ref_idx) {
21-
auto r0 = (1-ref_idx) / (1+ref_idx);
22-
r0 = r0*r0;
23-
return r0 + (1-r0)*pow((1 - cosine),5);
24-
}
25-
26-
2720
class material {
2821
public:
2922
virtual bool scatter(
@@ -84,22 +77,27 @@ class dielectric : public material {
8477
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
8578

8679
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
80+
vec3 direction;
8781

88-
// If the ray cannot refract, or if it probabilistically reflects because of its
89-
// grazing angle, then return the reflected path.
90-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
91-
vec3 reflected = reflect(unit_direction, rec.normal);
92-
scattered = ray(rec.p, reflected);
93-
return true;
94-
}
82+
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
83+
direction = reflect(unit_direction, rec.normal);
84+
else
85+
direction = refract(unit_direction, rec.normal, refraction_ratio);
9586

96-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
97-
scattered = ray(rec.p, refracted);
87+
scattered = ray(rec.p, direction);
9888
return true;
9989
}
10090

10191
public:
10292
double ir; // Index of Refraction
93+
94+
private:
95+
static double reflectance(double cosine, double ref_idx) {
96+
// Use Schlick's approximation for reflectance.
97+
auto r0 = (1-ref_idx) / (1+ref_idx);
98+
r0 = r0*r0;
99+
return r0 + (1-r0)*pow((1 - cosine),5);
100+
}
103101
};
104102

105103

src/TheNextWeek/material.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,27 @@ class dielectric : public material {
8989
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
9090

9191
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
92+
vec3 direction;
9293

93-
// If the ray cannot refract, or if it probabilistically reflects because of its
94-
// grazing angle, then return the reflected path.
95-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
96-
vec3 reflected = reflect(unit_direction, rec.normal);
97-
scattered = ray(rec.p, reflected, r_in.time());
98-
return true;
99-
}
94+
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
95+
direction = reflect(unit_direction, rec.normal);
96+
else
97+
direction = refract(unit_direction, rec.normal, refraction_ratio);
10098

101-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
102-
scattered = ray(rec.p, refracted, r_in.time());
99+
scattered = ray(rec.p, direction, r_in.time());
103100
return true;
104101
}
105102

106103
public:
107104
double ir; // Index of Refraction
105+
106+
private:
107+
static double reflectance(double cosine, double ref_idx) {
108+
// Use Schlick's approximation for reflectance.
109+
auto r0 = (1-ref_idx) / (1+ref_idx);
110+
r0 = r0*r0;
111+
return r0 + (1-r0)*pow((1 - cosine),5);
112+
}
108113
};
109114

110115

src/TheRestOfYourLife/material.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,22 +119,27 @@ class dielectric : public material {
119119
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
120120

121121
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
122+
vec3 direction;
122123

123-
// If the ray cannot refract, or if it probabilistically reflects because of its
124-
// grazing angle, then return the reflected path.
125-
if (cannot_refract || random_double() < schlick(cos_theta, refraction_ratio)) {
126-
vec3 reflected = reflect(unit_direction, rec.normal);
127-
srec.specular_ray = ray(rec.p, reflected, r_in.time());
128-
return true;
129-
}
124+
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
125+
direction = reflect(unit_direction, rec.normal);
126+
else
127+
direction = refract(unit_direction, rec.normal, refraction_ratio);
130128

131-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
132-
srec.specular_ray = ray(rec.p, refracted, r_in.time());
129+
srec.specular_ray = ray(rec.p, direction, r_in.time());
133130
return true;
134131
}
135132

136133
public:
137134
double ir; // Index of Refraction
135+
136+
private:
137+
static double reflectance(double cosine, double ref_idx) {
138+
// Use Schlick's approximation for reflectance.
139+
auto r0 = (1-ref_idx) / (1+ref_idx);
140+
r0 = r0*r0;
141+
return r0 + (1-r0)*pow((1 - cosine),5);
142+
}
138143
};
139144

140145

0 commit comments

Comments
 (0)