|
1114 | 1114 |
|
1115 | 1115 | class sphere : public hittable {
|
1116 | 1116 | 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)) {} |
1118 | 1118 |
|
1119 | 1119 | bool hit(const ray& r, double ray_tmin, double ray_tmax, hit_record& rec) const override {
|
1120 | 1120 | vec3 oc = center - r.origin();
|
|
2795 | 2795 | public:
|
2796 | 2796 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
2797 | 2797 | 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) {} |
2799 | 2799 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2800 | 2800 |
|
2801 | 2801 | bool hit(const ray& r, interval ray_t, hit_record& rec) const override {
|
|
3477 | 3477 |
|
3478 | 3478 | Modeling a Hollow Glass Sphere
|
3479 | 3479 | -------------------------------
|
3480 |
| -An interesting and easy trick with dielectric spheres is to note that if you use a negative radius, |
3481 |
| -the geometry is unaffected, but the surface normal points inward. |
| 3480 | +Let's model a hollow glass sphere. This is a sphere of some thickness with another sphere of air |
| 3481 | +inside it. If you think about the path of a ray going through such an object, it will hit the outer |
| 3482 | +sphere, refract, hit the inner sphere (assuming we do hit it), refract a second time, and travel |
| 3483 | +through the air inside. Then it will continue on, hit the inside surface of the inner sphere, |
| 3484 | +refract back, then hit the inside surface of the outer sphere, and finally refract and exit back |
| 3485 | +into the scene atmosphere. |
3482 | 3486 |
|
3483 |
| -However, properly handling negative radii can be tricky. Recall the line from `sphere::hit()` in |
3484 |
| -listing [sphere-material] that calculates the outward normal: |
| 3487 | +The outer sphere is just modeled with a standard glass sphere, with an index of refraction of around |
| 3488 | +1.50. The inner sphere is a bit different, because _its_ index of refraction will now be relative to |
| 3489 | +the "glass atmosphere" of the outer sphere. This is actually simple to specify, as our |
| 3490 | +index-of-refraction parameter to the dielectric material can be interpreted as the ratio of the |
| 3491 | +index of refraction of the object over the index of refraction of the enclosing medium. |
3485 | 3492 |
|
3486 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
3487 |
| - vec3 outward_normal = (rec.p - center) / radius; |
3488 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
3489 |
| - [Listing [proper-invert-sphere-normal]: Proper normal handling for spheres with negative radii] |
3490 |
| - |
3491 |
| -In your own implementation, you might have been tempted to instead do something like this: |
3492 |
| - |
3493 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
3494 |
| - vec3 outward_normal = (rec.p - center).unit_vector(); |
3495 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
3496 |
| - [Listing [improper-invert-sphere-normal]: |
3497 |
| - Problematic normal calculation for spheres with negative radii |
3498 |
| - ] |
3499 |
| - |
3500 |
| -If you do that, spheres with negative radii won't work properly. Since a sphere with a negative |
3501 |
| -radius is a _bubble_, its interior is the infinite space outside the sphere. Its exterior is the |
3502 |
| -finite bubble inside the sphere, so the outward normal needs to point toward the sphere center. |
3503 |
| -Dividing by the (negative) radius flips the normal as we want. If you implmented your code like the |
3504 |
| -second example above, you'll want to fix that now. |
| 3493 | +In this case, the inner sphere would have an index of refraction of air (the inner sphere material) |
| 3494 | +over the index of refraction of glass (the enclosing medium), or $1.00/1.50 = 0.67$. |
3505 | 3495 |
|
3506 |
| -Let's use this hollow sphere hack to model the interior of a sphere with a given thickness. To do |
3507 |
| -this, add a second _inverted_ glass sphere inside the original glass sphere: |
| 3496 | +Here's the code: |
3508 | 3497 |
|
3509 | 3498 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3510 | 3499 | ...
|
| 3500 | + auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0)); |
| 3501 | + auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5)); |
| 3502 | + auto material_left = make_shared<dielectric>(1.50); |
| 3503 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 3504 | + auto material_bubble = make_shared<dielectric>(0.67); |
| 3505 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 3506 | + auto material_right = make_shared<metal>(color(0.8, 0.6, 0.2), 0.0); |
| 3507 | + |
3511 | 3508 | world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
|
3512 | 3509 | world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
|
3513 | 3510 | world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
|
3514 | 3511 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
3515 |
| - world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left)); |
| 3512 | + world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.4, material_bubble)); |
3516 | 3513 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3517 | 3514 | world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
|
3518 | 3515 | ...
|
3519 | 3516 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3520 | 3517 | [Listing [scene-hollow-glass]: <kbd>[main.cc]</kbd> Scene with hollow glass sphere]
|
3521 | 3518 |
|
3522 | 3519 | <div class='together'>
|
3523 |
| -This gives: |
| 3520 | +And here's the result: |
3524 | 3521 |
|
3525 | 3522 | 
|
|
3772 | 3769 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
3773 | 3770 | auto material_ground = make_shared<lambertian>(color(0.8, 0.8, 0.0));
|
3774 | 3771 | auto material_center = make_shared<lambertian>(color(0.1, 0.2, 0.5));
|
3775 |
| - auto material_left = make_shared<dielectric>(1.5); |
| 3772 | + auto material_left = make_shared<dielectric>(1.50); |
| 3773 | + auto material_bubble = make_shared<dielectric>(0.67); |
3776 | 3774 | auto material_right = make_shared<metal>(color(0.8, 0.6, 0.2), 0.0);
|
3777 | 3775 |
|
3778 | 3776 | world.add(make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground));
|
3779 | 3777 | world.add(make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center));
|
3780 | 3778 | world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left));
|
3781 |
| - world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left)); |
| 3779 | + world.add(make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.4, material_bubble)); |
3782 | 3780 | world.add(make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right));
|
3783 | 3781 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
3784 | 3782 |
|
|
0 commit comments