Skip to content

Commit 293cdd4

Browse files
committed
constant_medium: refactor + additional text
- Opportunistic refactoring of constant_medium.h, updated in book also. - Set up main.cc to allow for custom samples_per_pixel and ray depth per scene. - Add explanatory text that the constant_medium boundary shape must be convex. Resolves #186
1 parent e142f3b commit 293cdd4

File tree

3 files changed

+72
-60
lines changed

3 files changed

+72
-60
lines changed

books/RayTracingTheNextWeek.html

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,7 @@
24302430
class constant_medium : public hittable {
24312431
public:
24322432
constant_medium(shared_ptr<hittable> b, double d, shared_ptr<texture> a)
2433-
: boundary(b), density(d)
2433+
: boundary(b), neg_inv_density(-1/d)
24342434
{
24352435
phase_function = make_shared<isotropic>(a);
24362436
}
@@ -2443,8 +2443,8 @@
24432443

24442444
public:
24452445
shared_ptr<hittable> boundary;
2446-
double density;
24472446
shared_ptr<material> phase_function;
2447+
double neg_inv_density;
24482448
};
24492449
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24502450
[Listing [const-med-class]: <kbd>[constant_medium.h]</kbd> Constant medium class]
@@ -2480,45 +2480,48 @@
24802480
bool constant_medium::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
24812481
// Print occasional samples when debugging. To enable, set enableDebug true.
24822482
const bool enableDebug = false;
2483-
bool debugging = enableDebug && random_double() < 0.00001;
2483+
const bool debugging = enableDebug && random_double() < 0.00001;
24842484

24852485
hit_record rec1, rec2;
24862486

2487-
if (boundary->hit(r, -infinity, infinity, rec1)) {
2488-
if (boundary->hit(r, rec1.t+0.0001, infinity, rec2)) {
2487+
if (!boundary->hit(r, -infinity, infinity, rec1))
2488+
return false;
24892489

2490-
if (debugging) std::cerr << "\nt0 t1 " << rec1.t << " " << rec2.t << '\n';
2490+
if (!boundary->hit(r, rec1.t+0.0001, infinity, rec2))
2491+
return false;
24912492

2492-
if (rec1.t < t_min) rec1.t = t_min;
2493-
if (rec2.t > t_max) rec2.t = t_max;
2493+
if (debugging) std::cerr << "\nt0=" << rec1.t << ", t1=" << rec2.t << '\n';
24942494

2495-
if (rec1.t >= rec2.t)
2496-
return false;
2497-
if (rec1.t < 0)
2498-
rec1.t = 0;
2495+
if (rec1.t < t_min) rec1.t = t_min;
2496+
if (rec2.t > t_max) rec2.t = t_max;
24992497

2500-
auto distance_inside_boundary = (rec2.t - rec1.t) * r.direction().length();
2501-
auto hit_distance = -(1/density) * log(random_double());
2498+
if (rec1.t >= rec2.t)
2499+
return false;
25022500

2503-
if (hit_distance < distance_inside_boundary) {
2501+
if (rec1.t < 0)
2502+
rec1.t = 0;
25042503

2505-
rec.t = rec1.t + hit_distance / r.direction().length();
2506-
rec.p = r.at(rec.t);
2504+
const auto ray_length = r.direction().length();
2505+
const auto distance_inside_boundary = (rec2.t - rec1.t) * ray_length;
2506+
const auto hit_distance = neg_inv_density * log(random_double());
25072507

2508-
if (debugging) {
2509-
std::cerr << "hit_distance = " << hit_distance << '\n'
2510-
<< "rec.t = " << rec.t << '\n'
2511-
<< "rec.p = " << rec.p << '\n';
2512-
}
2508+
if (hit_distance > distance_inside_boundary)
2509+
return false;
25132510

2514-
rec.normal = vec3(1,0,0); // arbitrary
2515-
rec.front_face = true; // also arbitrary
2516-
rec.mat_ptr = phase_function;
2517-
return true;
2518-
}
2519-
}
2511+
rec.t = rec1.t + hit_distance / ray_length;
2512+
rec.p = r.at(rec.t);
2513+
2514+
if (debugging) {
2515+
std::cerr << "hit_distance = " << hit_distance << '\n'
2516+
<< "rec.t = " << rec.t << '\n'
2517+
<< "rec.p = " << rec.p << '\n';
25202518
}
2521-
return false;
2519+
2520+
rec.normal = vec3(1,0,0); // arbitrary
2521+
rec.front_face = true; // also arbitrary
2522+
rec.mat_ptr = phase_function;
2523+
2524+
return true;
25222525
}
25232526
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25242527
[Listing [const-med-hit]: <kbd>[constant_medium.h]</kbd> Constant medium hit method]
@@ -2528,6 +2531,12 @@
25282531
works for ray origins inside the volume. In clouds, things bounce around a lot so that is a common
25292532
case.
25302533

2534+
In addition, the above code assumes that once a ray exits the constant medium boundary, it will
2535+
continue forever outside the boundary. Put another way, it assumes that the boundary shape is
2536+
convex. So this particular implementation will work for boundaries like boxes or spheres, but will
2537+
not work with toruses or shapes that contain voids. It's possible to write an implementation that
2538+
handles arbitrary shapes, but we'll leave that as an exercise for the reader.
2539+
25312540
<div class='together'>
25322541
If we replace the two blocks with smoke and fog (dark and light particles) and make the light bigger
25332542
(and dimmer so it doesn’t blow out the scene) for faster convergence:

src/TheNextWeek/constant_medium.h

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
class constant_medium : public hittable {
2121
public:
2222
constant_medium(shared_ptr<hittable> b, double d, shared_ptr<texture> a)
23-
: boundary(b), density(d)
23+
: boundary(b), neg_inv_density(-1/d)
2424
{
2525
phase_function = make_shared<isotropic>(a);
2626
}
@@ -33,54 +33,56 @@ class constant_medium : public hittable {
3333

3434
public:
3535
shared_ptr<hittable> boundary;
36-
double density;
3736
shared_ptr<material> phase_function;
37+
double neg_inv_density;
3838
};
3939

4040

4141
bool constant_medium::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
4242
// Print occasional samples when debugging. To enable, set enableDebug true.
4343
const bool enableDebug = false;
44-
bool debugging = enableDebug && random_double() < 0.00001;
44+
const bool debugging = enableDebug && random_double() < 0.00001;
4545

4646
hit_record rec1, rec2;
4747

48-
if (boundary->hit(r, -infinity, infinity, rec1)) {
49-
if (boundary->hit(r, rec1.t+0.0001, infinity, rec2)) {
48+
if (!boundary->hit(r, -infinity, infinity, rec1))
49+
return false;
5050

51-
if (debugging) std::cerr << "\nt0 t1 " << rec1.t << " " << rec2.t << '\n';
51+
if (!boundary->hit(r, rec1.t+0.0001, infinity, rec2))
52+
return false;
5253

53-
if (rec1.t < t_min) rec1.t = t_min;
54-
if (rec2.t > t_max) rec2.t = t_max;
54+
if (debugging) std::cerr << "\nt0=" << rec1.t << ", t1=" << rec2.t << '\n';
5555

56-
if (rec1.t >= rec2.t)
57-
return false;
56+
if (rec1.t < t_min) rec1.t = t_min;
57+
if (rec2.t > t_max) rec2.t = t_max;
5858

59-
if (rec1.t < 0)
60-
rec1.t = 0;
59+
if (rec1.t >= rec2.t)
60+
return false;
6161

62-
auto distance_inside_boundary = (rec2.t - rec1.t) * r.direction().length();
63-
auto hit_distance = -(1/density) * log(random_double());
62+
if (rec1.t < 0)
63+
rec1.t = 0;
6464

65-
if (hit_distance < distance_inside_boundary) {
65+
const auto ray_length = r.direction().length();
66+
const auto distance_inside_boundary = (rec2.t - rec1.t) * ray_length;
67+
const auto hit_distance = neg_inv_density * log(random_double());
6668

67-
rec.t = rec1.t + hit_distance / r.direction().length();
68-
rec.p = r.at(rec.t);
69+
if (hit_distance > distance_inside_boundary)
70+
return false;
6971

70-
if (debugging) {
71-
std::cerr << "hit_distance = " << hit_distance << '\n'
72-
<< "rec.t = " << rec.t << '\n'
73-
<< "rec.p = " << rec.p << '\n';
74-
}
72+
rec.t = rec1.t + hit_distance / ray_length;
73+
rec.p = r.at(rec.t);
7574

76-
rec.normal = vec3(1,0,0); // arbitrary
77-
rec.front_face = true; // also arbitrary
78-
rec.mat_ptr = phase_function;
79-
return true;
80-
}
81-
}
75+
if (debugging) {
76+
std::cerr << "hit_distance = " << hit_distance << '\n'
77+
<< "rec.t = " << rec.t << '\n'
78+
<< "rec.p = " << rec.p << '\n';
8279
}
83-
return false;
80+
81+
rec.normal = vec3(1,0,0); // arbitrary
82+
rec.front_face = true; // also arbitrary
83+
rec.mat_ptr = phase_function;
84+
85+
return true;
8486
}
8587

8688
#endif

src/TheNextWeek/main.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,13 @@ hittable_list final_scene() {
348348
int main() {
349349
const int image_width = 600;
350350
const int image_height = 600;
351-
const int samples_per_pixel = 100;
352-
const int max_depth = 50;
353351
const auto aspect_ratio = double(image_width) / image_height;
354352

355353
hittable_list world;
356354

355+
int samples_per_pixel = 100;
356+
int max_depth = 50;
357+
357358
vec3 lookfrom;
358359
vec3 lookat;
359360
vec3 vup(0,1,0);

0 commit comments

Comments
 (0)