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