Skip to content

Commit f7432bf

Browse files
authored
Merge pull request #337 from RayTracing/constant_medium
constant_medium: refactor + additional text
2 parents a8c3b04 + 293cdd4 commit f7432bf

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
@@ -2428,7 +2428,7 @@
24282428
class constant_medium : public hittable {
24292429
public:
24302430
constant_medium(shared_ptr<hittable> b, double d, shared_ptr<texture> a)
2431-
: boundary(b), density(d)
2431+
: boundary(b), neg_inv_density(-1/d)
24322432
{
24332433
phase_function = make_shared<isotropic>(a);
24342434
}
@@ -2441,8 +2441,8 @@
24412441

24422442
public:
24432443
shared_ptr<hittable> boundary;
2444-
double density;
24452444
shared_ptr<material> phase_function;
2445+
double neg_inv_density;
24462446
};
24472447
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24482448
[Listing [const-med-class]: <kbd>[constant_medium.h]</kbd> Constant medium class]
@@ -2478,45 +2478,48 @@
24782478
bool constant_medium::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
24792479
// Print occasional samples when debugging. To enable, set enableDebug true.
24802480
const bool enableDebug = false;
2481-
bool debugging = enableDebug && random_double() < 0.00001;
2481+
const bool debugging = enableDebug && random_double() < 0.00001;
24822482

24832483
hit_record rec1, rec2;
24842484

2485-
if (boundary->hit(r, -infinity, infinity, rec1)) {
2486-
if (boundary->hit(r, rec1.t+0.0001, infinity, rec2)) {
2485+
if (!boundary->hit(r, -infinity, infinity, rec1))
2486+
return false;
24872487

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

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

2493-
if (rec1.t >= rec2.t)
2494-
return false;
2495-
if (rec1.t < 0)
2496-
rec1.t = 0;
2493+
if (rec1.t < t_min) rec1.t = t_min;
2494+
if (rec2.t > t_max) rec2.t = t_max;
24972495

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

2501-
if (hit_distance < distance_inside_boundary) {
2499+
if (rec1.t < 0)
2500+
rec1.t = 0;
25022501

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

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

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

2532+
In addition, the above code assumes that once a ray exits the constant medium boundary, it will
2533+
continue forever outside the boundary. Put another way, it assumes that the boundary shape is
2534+
convex. So this particular implementation will work for boundaries like boxes or spheres, but will
2535+
not work with toruses or shapes that contain voids. It's possible to write an implementation that
2536+
handles arbitrary shapes, but we'll leave that as an exercise for the reader.
2537+
25292538
<div class='together'>
25302539
If we replace the two blocks with smoke and fog (dark and light particles) and make the light bigger
25312540
(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)