Skip to content

Commit 9f0234b

Browse files
authored
Implement bubbles with IOR, not negative radii
We were using negative radii on spheres to invert the sense of front vs back faces of spheres, and using this to get an inverted index of refraction (IOR) for bubbles. This method was used to model a hollow glass sphere. Over the past couple of years we've encountered a number of bugs induced by negative radii spheres (see the list in the description for issue 1420). Instead, this change interprets the dielectric parameter not as an IOR relative to surrounding air, but instead as the ratio of the IOR of the object material over the IOR of the surrounding medium. Interpreting the parameter this way lets you model a sphere of air enclosed in glass -- just what we need to model a hollow glass sphere purely with the proper IORs, and without resorting to inverted geometry with negative radii spheres. We also end up using this method to properly demonstrate total internal/external reflection in another section. Resolves #1420
1 parent efcb15b commit 9f0234b

File tree

9 files changed

+118
-93
lines changed

9 files changed

+118
-93
lines changed

books/RayTracingInOneWeekend.html

Lines changed: 75 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@
11141114

11151115
class sphere : public hittable {
11161116
public:
1117-
sphere(const point3& center, double radius) : center(center), radius(radius) {}
1117+
sphere(const point3& center, double radius) : center(center), radius(fmax(0,radius)) {}
11181118

11191119
bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override {
11201120
vec3 oc = center - r.origin();
@@ -2795,7 +2795,7 @@
27952795
public:
27962796
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
27972797
sphere(const point3& center, double radius, shared_ptr<material> mat)
2798-
: center(center), radius(radius), mat(mat) {}
2798+
: center(center), radius(fmax(0,radius)), mat(mat) {}
27992799
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
28002800

28012801
bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
@@ -3157,6 +3157,25 @@
31573157
splits into a reflected ray and a refracted (transmitted) ray. We’ll handle that by randomly
31583158
choosing between reflection and refraction, only generating one scattered ray per interaction.
31593159

3160+
As a quick review of terms, a _reflected_ ray hits a surface and then "bounces" off in a new
3161+
direction.
3162+
3163+
A _refracted_ ray bends as it transitions from a material's surroundings into the material itself
3164+
(as with glass or water). This is why a pencil looks bent when partially inserted in water.
3165+
3166+
The amount that a refracted ray bends is determined by the material's _refractive index_. Generally,
3167+
this is a single value that describes how much light bends when entering a material from a vacuum.
3168+
Glass has a refractive index of something like 1.5&ndash;1.7, and air has a small refractive index
3169+
of 1.000293.
3170+
3171+
When a transparent material is embedded in a different transparent material, you can describe the
3172+
refraction with a relative refraction index: the refractive index of the object's material divided
3173+
by the refractive index of the surrounding material. For example, if you want to render a glass ball
3174+
under water, then the glass ball would have an effective refractive index of 1.125. This is given by
3175+
the refractive index of glass (1.5) divided by the refractive index of water (1.333).
3176+
3177+
You can find the refractive index of most common materials with a quick internet search.
3178+
31603179

31613180
Refraction
31623181
-----------
@@ -3257,23 +3276,24 @@
32573276
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ Highlight
32583277
class dielectric : public material {
32593278
public:
3260-
dielectric(double ref_index) : ref_index(ref_index) {}
3279+
dielectric(double refraction_index) : refraction_index(refraction_index) {}
32613280

32623281
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
32633282
const override {
32643283
attenuation = color(1.0, 1.0, 1.0);
3265-
double refraction_ratio = rec.front_face ? (1.0/ref_index) : ref_index;
3284+
double ri = rec.front_face ? (1.0/refraction_index) : refraction_index;
32663285

32673286
vec3 unit_direction = unit_vector(r_in.direction());
3268-
vec3 refracted = refract(unit_direction, rec.normal, refraction_ratio);
3287+
vec3 refracted = refract(unit_direction, rec.normal, ri);
32693288

32703289
scattered = ray(rec.p, refracted);
32713290
return true;
32723291
}
32733292

32743293
private:
3275-
double ref_index; // Refractive index in vacuum or air, or the ratio of the material's
3276-
// refractive index over the refractive index of the enclosing media
3294+
// Refractive index in vacuum or air, or the ratio of the material's refractive index over
3295+
// the refractive index of the enclosing media
3296+
double refraction_index;
32773297
};
32783298
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32793299
[Listing [dielectric-always-refract]: <kbd>[material.h]</kbd>
@@ -3327,7 +3347,7 @@
33273347
solution does not exist, the glass cannot refract, and therefore must reflect the ray:
33283348

33293349
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
3330-
if (refraction_ratio * sin_theta > 1.0) {
3350+
if (ri * sin_theta > 1.0) {
33313351
// Must Reflect
33323352
...
33333353
} else {
@@ -3355,7 +3375,7 @@
33553375
double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0);
33563376
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
33573377

3358-
if (refraction_ratio * sin_theta > 1.0) {
3378+
if (ri * sin_theta > 1.0) {
33593379
// Must Reflect
33603380
...
33613381
} else {
@@ -3371,34 +3391,35 @@
33713391
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
33723392
class dielectric : public material {
33733393
public:
3374-
dielectric(double ref_index) : ref_index(ref_index) {}
3394+
dielectric(double refraction_index) : refraction_index(refraction_index) {}
33753395

33763396
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
33773397
const override {
33783398
attenuation = color(1.0, 1.0, 1.0);
3379-
double refraction_ratio = rec.front_face ? (1.0/ref_index) : ref_index;
3399+
double ri = rec.front_face ? (1.0/refraction_index) : refraction_index;
33803400

33813401
vec3 unit_direction = unit_vector(r_in.direction());
33823402
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
33833403
double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0);
33843404
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
33853405

3386-
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
3406+
bool cannot_refract = ri * sin_theta > 1.0;
33873407
vec3 direction;
33883408

33893409
if (cannot_refract)
33903410
direction = reflect(unit_direction, rec.normal);
33913411
else
3392-
direction = refract(unit_direction, rec.normal, refraction_ratio);
3412+
direction = refract(unit_direction, rec.normal, ri);
33933413

33943414
scattered = ray(rec.p, direction);
33953415
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
33963416
return true;
33973417
}
33983418

33993419
private:
3400-
double ref_index; // Refractive index in vacuum or air, or the ratio of the material's
3401-
// refractive index over the refractive index of the enclosing media
3420+
// Refractive index in vacuum or air, or the ratio of the material's refractive index over
3421+
// the refractive index of the enclosing media
3422+
double refraction_index;
34023423
};
34033424
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34043425
[Listing [dielectric-with-refraction]: <kbd>[material.h]</kbd>
@@ -3440,40 +3461,41 @@
34403461
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
34413462
class dielectric : public material {
34423463
public:
3443-
dielectric(double ref_index) : ref_index(ref_index) {}
3464+
dielectric(double refraction_index) : refraction_index(refraction_index) {}
34443465

34453466
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
34463467
const override {
34473468
attenuation = color(1.0, 1.0, 1.0);
3448-
double refraction_ratio = rec.front_face ? (1.0/ref_index) : ref_index;
3469+
double ri = rec.front_face ? (1.0/refraction_index) : refraction_index;
34493470

34503471
vec3 unit_direction = unit_vector(r_in.direction());
34513472
double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0);
34523473
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
34533474

3454-
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
3475+
bool cannot_refract = ri * sin_theta > 1.0;
34553476
vec3 direction;
34563477

34573478
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
3458-
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
3479+
if (cannot_refract || reflectance(cos_theta, ri) > random_double())
34593480
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
34603481
direction = reflect(unit_direction, rec.normal);
34613482
else
3462-
direction = refract(unit_direction, rec.normal, refraction_ratio);
3483+
direction = refract(unit_direction, rec.normal, ri);
34633484

34643485
scattered = ray(rec.p, direction);
34653486
return true;
34663487
}
34673488

34683489
private:
3469-
double ref_index; // Refractive index in vacuum or air, or the ratio of the material's
3470-
// refractive index over the refractive index of the enclosing media
3490+
// Refractive index in vacuum or air, or the ratio of the material's refractive index over
3491+
// the refractive index of the enclosing media
3492+
double refraction_index;
34713493

34723494

34733495
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
3474-
static double reflectance(double cosine, double ref_idx) {
3496+
static double reflectance(double cosine, double refraction_index) {
34753497
// Use Schlick's approximation for reflectance.
3476-
auto r0 = (1-ref_idx) / (1+ref_idx);
3498+
auto r0 = (1-refraction_index) / (1+refraction_index);
34773499
r0 = r0*r0;
34783500
return r0 + (1-r0)*pow((1 - cosine),5);
34793501
}
@@ -3485,50 +3507,49 @@
34853507

34863508
Modeling a Hollow Glass Sphere
34873509
-------------------------------
3488-
An interesting and easy trick with dielectric spheres is to note that if you use a negative radius,
3489-
the geometry is unaffected, but the surface normal points inward.
3490-
3491-
However, properly handling negative radii can be tricky. Recall the line from `sphere::hit()` in
3492-
listing [sphere-material] that calculates the outward normal:
3493-
3494-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
3495-
vec3 outward_normal = (rec.p - center) / radius;
3496-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3497-
[Listing [proper-invert-sphere-normal]: Proper normal handling for spheres with negative radii]
3498-
3499-
In your own implementation, you might have been tempted to instead do something like this:
3510+
Let's model a hollow glass sphere. This is a sphere of some thickness with another sphere of air
3511+
inside it. If you think about the path of a ray going through such an object, it will hit the outer
3512+
sphere, refract, hit the inner sphere (assuming we do hit it), refract a second time, and travel
3513+
through the air inside. Then it will continue on, hit the inside surface of the inner sphere,
3514+
refract back, then hit the inside surface of the outer sphere, and finally refract and exit back
3515+
into the scene atmosphere.
35003516

3501-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
3502-
vec3 outward_normal = (rec.p - center).unit_vector();
3503-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3504-
[Listing [improper-invert-sphere-normal]:
3505-
Problematic normal calculation for spheres with negative radii
3506-
]
3517+
The outer sphere is just modeled with a standard glass sphere, with a refractive index of around
3518+
1.50 (modeling a refraction from the outside air into glass). The inner sphere is a bit different
3519+
because _its_ refractive index should be relative to the material of the surrounding outer sphere,
3520+
thus modeling a transition from glass into the inner air.
35073521

3508-
If you do that, spheres with negative radii won't work properly. Since a sphere with a negative
3509-
radius is a _bubble_, its interior is the infinite space outside the sphere. Its exterior is the
3510-
finite bubble inside the sphere, so the outward normal needs to point toward the sphere center.
3511-
Dividing by the (negative) radius flips the normal as we want. If you implmented your code like the
3512-
second example above, you'll want to fix that now.
3522+
This is actually simple to specify, as the `refraction_index` parameter to the dielectric material
3523+
can be interpreted as the _ratio_ of the refractive index of the object divided by the refractive
3524+
index of the enclosing medium. In this case, the inner sphere would have an refractive index of air
3525+
(the inner sphere material) over the index of refraction of glass (the enclosing medium), or
3526+
$1.00/1.50 = 0.67$.
35133527

3514-
Let's use this hollow sphere hack to model the interior of a sphere with a given thickness. To do
3515-
this, add a second _inverted_ glass sphere inside the original glass sphere:
3528+
Here's the code:
35163529

35173530
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
35183531
...
3532+
auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
3533+
auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5));
3534+
auto material_left = make_shared<dielectric>(1.50);
3535+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
3536+
auto material_bubble = make_shared<dielectric>(0.67);
3537+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
3538+
auto material_right = make_shared<metal>(color(0.8, 0.6, 0.2), 0.0);
3539+
35193540
world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
35203541
world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
35213542
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
35223543
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
3523-
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left));
3544+
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.4, material_bubble));
35243545
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
35253546
world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
35263547
...
35273548
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35283549
[Listing [scene-hollow-glass]: <kbd>[main.cc]</kbd> Scene with hollow glass sphere]
35293550

35303551
<div class='together'>
3531-
This gives:
3552+
And here's the result:
35323553

35333554
![<span class='num'>Image 18:</span> A hollow glass sphere
35343555
](../images/img-1.18-glass-hollow.png class='pixel')
@@ -3780,13 +3801,14 @@
37803801
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
37813802
auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
37823803
auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5));
3783-
auto material_left = make_shared<dielectric>(1.5);
3804+
auto material_left = make_shared<dielectric>(1.50);
3805+
auto material_bubble = make_shared<dielectric>(0.67);
37843806
auto material_right = make_shared<metal>(color(0.8, 0.6, 0.2), 0.0);
37853807

37863808
world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
37873809
world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
37883810
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
3789-
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left));
3811+
world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.4, material_bubble));
37903812
world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
37913813
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
37923814

books/RayTracingTheNextWeek.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,12 @@
179179
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
180180
// Stationary Sphere
181181
sphere(const point3& center, double radius, shared_ptr<material> mat)
182-
: center1(center), radius(radius), mat(mat), is_moving(false) {}
182+
: center1(center), radius(fmax(0,radius)), mat(mat), is_moving(false) {}
183183

184184
// Moving Sphere
185185
sphere(const point3& center1, const point3& center2, double radius,
186186
shared_ptr<material> mat)
187-
: center1(center1), radius(radius), mat(mat), is_moving(true)
187+
: center1(center1), radius(fmax(0,radius)), mat(mat), is_moving(true)
188188
{
189189
center_vec = center2 - center1;
190190
}
@@ -724,7 +724,7 @@
724724
// Stationary Sphere
725725
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
726726
sphere(const point3& center, double radius, shared_ptr<material> mat)
727-
: center1(center), radius(radius), mat(mat), is_moving(false)
727+
: center1(center), radius(fmax(0,radius)), mat(mat), is_moving(false)
728728
{
729729
auto rvec = vec3(radius, radius, radius);
730730
bbox = aabb(center1 - rvec, center1 + rvec);
@@ -760,7 +760,7 @@
760760
// Moving Sphere
761761
sphere(const point3& center1, const point3& center2, double radius,
762762
shared_ptr<material> mat)
763-
: center1(center1), radius(radius), mat(mat), is_moving(true)
763+
: center1(center1), radius(fmax(0,radius)), mat(mat), is_moving(true)
764764
{
765765
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
766766
auto rvec = vec3(radius, radius, radius);

books/RayTracingTheRestOfYourLife.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3316,7 +3316,7 @@
33163316

33173317
class dielectric : public material {
33183318
public:
3319-
dielectric(double ref_index) : ref_index(ref_index) {}
3319+
dielectric(double refraction_index) : refraction_index(refraction_index) {}
33203320

33213321

33223322
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
@@ -3325,19 +3325,19 @@
33253325
srec.pdf_ptr = nullptr;
33263326
srec.skip_pdf = true;
33273327
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
3328-
double refraction_ratio = rec.front_face ? (1.0/ref_index) : ref_index;
3328+
double ri = rec.front_face ? (1.0/refraction_index) : refraction_index;
33293329

33303330
vec3 unit_direction = unit_vector(r_in.direction());
33313331
double cos_theta = fmin(dot(-unit_direction, rec.normal), 1.0);
33323332
double sin_theta = sqrt(1.0 - cos_theta*cos_theta);
33333333

3334-
bool cannot_refract = refraction_ratio * sin_theta > 1.0;
3334+
bool cannot_refract = ri * sin_theta > 1.0;
33353335
vec3 direction;
33363336

3337-
if (cannot_refract || reflectance(cos_theta, refraction_ratio) > random_double())
3337+
if (cannot_refract || reflectance(cos_theta, ri) > random_double())
33383338
direction = reflect(unit_direction, rec.normal);
33393339
else
3340-
direction = refract(unit_direction, rec.normal, refraction_ratio);
3340+
direction = refract(unit_direction, rec.normal, ri);
33413341

33423342

33433343
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight

0 commit comments

Comments
 (0)