|
2428 | 2428 | class constant_medium : public hittable {
|
2429 | 2429 | public:
|
2430 | 2430 | 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) |
2432 | 2432 | {
|
2433 | 2433 | phase_function = make_shared<isotropic>(a);
|
2434 | 2434 | }
|
|
2441 | 2441 |
|
2442 | 2442 | public:
|
2443 | 2443 | shared_ptr<hittable> boundary;
|
2444 |
| - double density; |
2445 | 2444 | shared_ptr<material> phase_function;
|
| 2445 | + double neg_inv_density; |
2446 | 2446 | };
|
2447 | 2447 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2448 | 2448 | [Listing [const-med-class]: <kbd>[constant_medium.h]</kbd> Constant medium class]
|
|
2478 | 2478 | bool constant_medium::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
2479 | 2479 | // Print occasional samples when debugging. To enable, set enableDebug true.
|
2480 | 2480 | const bool enableDebug = false;
|
2481 |
| - bool debugging = enableDebug && random_double() < 0.00001; |
| 2481 | + const bool debugging = enableDebug && random_double() < 0.00001; |
2482 | 2482 |
|
2483 | 2483 | hit_record rec1, rec2;
|
2484 | 2484 |
|
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; |
2487 | 2487 |
|
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; |
2489 | 2490 |
|
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'; |
2492 | 2492 |
|
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; |
2497 | 2495 |
|
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; |
2500 | 2498 |
|
2501 |
| - if (hit_distance < distance_inside_boundary) { |
| 2499 | + if (rec1.t < 0) |
| 2500 | + rec1.t = 0; |
2502 | 2501 |
|
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()); |
2505 | 2505 |
|
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; |
2511 | 2508 |
|
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'; |
2518 | 2516 | }
|
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; |
2520 | 2523 | }
|
2521 | 2524 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2522 | 2525 | [Listing [const-med-hit]: <kbd>[constant_medium.h]</kbd> Constant medium hit method]
|
|
2526 | 2529 | works for ray origins inside the volume. In clouds, things bounce around a lot so that is a common
|
2527 | 2530 | case.
|
2528 | 2531 |
|
| 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 | + |
2529 | 2538 | <div class='together'>
|
2530 | 2539 | If we replace the two blocks with smoke and fog (dark and light particles) and make the light bigger
|
2531 | 2540 | (and dimmer so it doesn’t blow out the scene) for faster convergence:
|
|
0 commit comments