|
111 | 111 | later when we internally use high dynamic range, but before output we will tone map to the zero
|
112 | 112 | to one range, so this code won’t change.
|
113 | 113 |
|
114 |
| - 4. Red goes from black to fully on from left to right, and green goes from black at the bottom to |
115 |
| - fully on at the top. Red and green together make yellow so we should expect the upper right |
116 |
| - corner to be yellow. |
| 114 | + 4. Red goes from fully off (black) to fully on (bright red) from left to right, and green goes |
| 115 | + from black at the bottom to fully on at the top. Red and green together make yellow so we |
| 116 | + should expect the upper right corner to be yellow. |
117 | 117 |
|
118 | 118 |
|
119 | 119 | Creating an Image File
|
|
231 | 231 | Here’s the top part of my `vec3` class:
|
232 | 232 |
|
233 | 233 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 234 | + #ifndef VEC3_H |
| 235 | + #define VEC3_H |
| 236 | + |
234 | 237 | #include <iostream>
|
235 | 238 |
|
236 | 239 | class vec3 {
|
|
286 | 289 | // Type aliases for vec3
|
287 | 290 | using point3 = vec3; // 3D point
|
288 | 291 | using color = vec3; // RGB color
|
| 292 | + |
| 293 | + #endif |
289 | 294 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
290 |
| - [Listing [vec3-class]: <kbd>[vec3.h]</kbd> `vec3` class] |
| 295 | + [Listing [vec3-class]: <kbd>[vec3.h]</kbd> vec3 class] |
291 | 296 | </div>
|
292 | 297 |
|
293 | 298 | We use `double` here, but some ray tracers use `float`. Either one is fine -- follow your own
|
|
374 | 379 | std::cerr << "\nDone.\n";
|
375 | 380 | }
|
376 | 381 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
377 |
| - [Listing [ppm-2]: <kbd>[main.cc]</kbd> Final code for the first PPM image |
| 382 | + [Listing [ppm-2]: <kbd>[main.cc]</kbd> Final code for the first PPM image] |
378 | 383 | </div>
|
379 | 384 |
|
380 | 385 |
|
|
765 | 770 | An Abstraction for Hittable Objects
|
766 | 771 | ------------------------------------
|
767 | 772 | Now, how about several spheres? While it is tempting to have an array of spheres, a very clean
|
768 |
| -solution is the make an “abstract class” for anything a ray might hit and make both a sphere and a |
| 773 | +solution is to make an “abstract class” for anything a ray might hit and make both a sphere and a |
769 | 774 | list of spheres just something you can hit. What that class should be called is something of a
|
770 | 775 | quandary -- calling it an “object” would be good if not for “object oriented” programming. “Surface”
|
771 | 776 | is often used, with the weakness being maybe we will want volumes. “hittable” emphasizes the member
|
|
884 | 889 | If we decide to have the normals always point out, then we will need to determine which side the
|
885 | 890 | ray is on when we color it. We can figure this out by comparing the ray with the normal. If the ray
|
886 | 891 | and the normal face in the same direction, the ray is inside the object, if the ray and the normal
|
887 |
| -face in the opposide direction, then the ray is outside the object. This can be determined by |
| 892 | +face in the opposite direction, then the ray is outside the object. This can be determined by |
888 | 893 | taking the dot product of the two vectors, where if their dot is positive, the ray is inside the
|
889 | 894 | sphere.
|
890 | 895 |
|
|
993 | 998 | return false;
|
994 | 999 | }
|
995 | 1000 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
996 |
| - [Listing [sphere-final]: <kbd>[sphere.h]</kbd> The `sphere` class with normal determination] |
| 1001 | + [Listing [sphere-final]: <kbd>[sphere.h]</kbd> The sphere class with normal determination] |
997 | 1002 |
|
998 | 1003 | </div>
|
999 | 1004 |
|
1000 | 1005 |
|
1001 | 1006 | A List of Hittable Objects
|
1002 | 1007 | ---------------------------
|
1003 | 1008 | <div class='together'>
|
1004 |
| -We add a list of objects: |
| 1009 | +We have a generic object called a `hittable` that the ray can intersect with. We now add a class |
| 1010 | +that stores a list of `hittable`s: |
1005 | 1011 |
|
1006 | 1012 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1007 | 1013 | #ifndef HITTABLE_LIST_H
|
|
1069 | 1075 | shared_ptr<vec3> vec3_ptr = make_shared<vec3>(1.414214, 2.718281, 1.618034);
|
1070 | 1076 | shared_ptr<sphere> sphere_ptr = make_shared<sphere>(point3(0,0,0), 1.0);
|
1071 | 1077 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1072 |
| - [Listing [shared-ptr]: An example allocation using `shared_ptr`] |
| 1078 | + [Listing [shared-ptr]: An example allocation using shared_ptr] |
1073 | 1079 |
|
1074 | 1080 | `make_shared<thing>(thing_constructor_params ...)` allocates a new instance of type `thing`, using
|
1075 | 1081 | the constructor parameters. It returns a `shared_ptr<thing>`.
|
|
1082 | 1088 | auto vec3_ptr = make_shared<vec3>(1.414214, 2.718281, 1.618034);
|
1083 | 1089 | auto sphere_ptr = make_shared<sphere>(point3(0,0,0), 1.0);
|
1084 | 1090 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1085 |
| - [Listing [shared-ptr-auto]: An example allocation using `shared_ptr` with `auto` type] |
| 1091 | + [Listing [shared-ptr-auto]: An example allocation using shared_ptr with auto type] |
1086 | 1092 |
|
1087 | 1093 | </div>
|
1088 | 1094 |
|
|
1217 | 1223 | std::cerr << "\nDone.\n";
|
1218 | 1224 | }
|
1219 | 1225 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1220 |
| - [Listing [main-with-rtweekend-h]: <kbd>[main.cc]</kbd> desc] |
| 1226 | + [Listing [main-with-rtweekend-h]: <kbd>[main.cc]</kbd> The new main with hittables] |
1221 | 1227 | </div>
|
1222 | 1228 |
|
1223 | 1229 | <div class='together'>
|
|
1248 | 1254 | Some Random Number Utilities
|
1249 | 1255 | -----------------------------
|
1250 | 1256 | One thing we need is a random number generator that returns real random numbers. We need a function
|
1251 |
| -that returns a canonical random number which by convention returns random real in the range |
| 1257 | +that returns a canonical random number which by convention returns a random real in the range |
1252 | 1258 | $0 ≤ r < 1$. The “less than” before the 1 is important as we will sometimes take advantage of that.
|
1253 | 1259 |
|
1254 | 1260 | <div class='together'>
|
|
1290 | 1296 | return rand_generator();
|
1291 | 1297 | }
|
1292 | 1298 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1293 |
| - [Listing [random-double-alt]: <kbd>[file]</kbd> random_double(), alternate implemenation] |
| 1299 | + [Listing [random-double-alt]: <kbd>[rtweekend.h]</kbd> random_double(), alternate implemenation] |
1294 | 1300 | </div>
|
1295 | 1301 |
|
1296 | 1302 |
|
|
1430 | 1436 | ====================================================================================================
|
1431 | 1437 |
|
1432 | 1438 | Now that we have objects and multiple rays per pixel, we can make some realistic looking materials.
|
1433 |
| -We’ll start with diffuse (matte) materials. One question is whether we can mix and match shapes and |
1434 |
| -materials (so we assign a sphere a material) or if it’s put together so the geometry and material |
1435 |
| -are tightly bound (that could be useful for procedural objects where the geometry and material are |
1436 |
| -linked). We’ll go with separate -- which is usual in most renderers -- but do be aware of the |
1437 |
| -limitation. |
| 1439 | +We’ll start with diffuse (matte) materials. One question is whether we mix and match geometry and |
| 1440 | +materials (so we can assign a material to multiple spheres, or vice versa) or if geometry and |
| 1441 | +material are tightly bound (that could be useful for procedural objects where the geometry and |
| 1442 | +material are linked). We’ll go with separate -- which is usual in most renderers -- but do be aware |
| 1443 | +of the limitation. |
1438 | 1444 |
|
1439 | 1445 | A Simple Diffuse Material
|
1440 | 1446 | --------------------------
|
|
1488 | 1494 | return vec3(random_double(min,max), random_double(min,max), random_double(min,max));
|
1489 | 1495 | }
|
1490 | 1496 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1491 |
| - [Listing [vec-rand-util]: <kbd>[vec3.h]</kbd> `vec3` random utility functions] |
| 1497 | + [Listing [vec-rand-util]: <kbd>[vec3.h]</kbd> vec3 random utility functions] |
1492 | 1498 |
|
1493 | 1499 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1494 | 1500 | vec3 random_in_unit_sphere() {
|
|
1535 | 1541 |
|
1536 | 1542 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1537 | 1543 | color ray_color(const ray& r, const hittable& world, int depth) {
|
| 1544 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
1538 | 1545 | hit_record rec;
|
1539 | 1546 |
|
| 1547 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
1540 | 1548 | // If we've exceeded the ray bounce limit, no more light is gathered.
|
1541 | 1549 | if (depth <= 0)
|
1542 | 1550 | return color(0,0,0);
|
| 1551 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 1552 | + |
1543 | 1553 |
|
1544 | 1554 | if (world.hit(r, 0, infinity, rec)) {
|
1545 | 1555 | point3 target = rec.p + rec.normal + random_in_unit_sphere();
|
| 1556 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
1546 | 1557 | return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1);
|
1547 | 1558 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1548 | 1559 | }
|
|
1664 | 1675 | <div class='together'>
|
1665 | 1676 | The rejection method presented here produces random points in the unit ball offset along the surface
|
1666 | 1677 | normal. This corresponds to picking directions on the hemisphere with high probability close to the
|
1667 |
| -normal, and a lower probability of scattering rays at grazing angles. The distribution present |
1668 |
| -scales by the $\cos^3 (\phi)$ where $\phi$ is the angle from the normal. This is useful since light |
1669 |
| -arriving at shallow angles spreads over a larger area, and thus has a lower contribution to the |
1670 |
| -final color. |
| 1678 | +normal, and a lower probability of scattering rays at grazing angles. This distribution scales by |
| 1679 | +the $\cos^3 (\phi)$ where $\phi$ is the angle from the normal. This is useful since light arriving |
| 1680 | +at shallow angles spreads over a larger area, and thus has a lower contribution to the final color. |
1671 | 1681 |
|
1672 | 1682 | However, we are interested in a Lambertian distribution, which has a distribution of $\cos (\phi)$.
|
1673 | 1683 | True Lambertian has the probability higher for ray scattering close to the normal, but the
|
|
1837 | 1847 | This suggests the abstract class:
|
1838 | 1848 |
|
1839 | 1849 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 1850 | + #ifndef MATERIAL_H |
| 1851 | + #define MATERIAL_H |
| 1852 | + |
1840 | 1853 | class material {
|
1841 | 1854 | public:
|
1842 | 1855 | virtual bool scatter(
|
1843 | 1856 | const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered
|
1844 | 1857 | ) const = 0;
|
1845 | 1858 | };
|
| 1859 | + |
| 1860 | + #endif |
1846 | 1861 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1847 | 1862 | [Listing [material-initial]: <kbd>[material.h]</kbd> The material class]
|
1848 | 1863 | </div>
|
|
2453 | 2468 | ----------------------
|
2454 | 2469 | <div class='together'>
|
2455 | 2470 | Now real glass has reflectivity that varies with angle -- look at a window at a steep angle and it
|
2456 |
| -becomes a mirror. There is a big ugly equation for that, but almost everybody uses a simple and |
2457 |
| -surprisingly simple polynomial approximation by Christophe Schlick: |
| 2471 | +becomes a mirror. There is a big ugly equation for that, but almost everybody uses a cheap and |
| 2472 | +surprisingly accurate polynomial approximation by Christophe Schlick: |
2458 | 2473 |
|
2459 | 2474 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2460 | 2475 | double schlick(double cosine, double ref_idx) {
|
|
2634 | 2649 |
|
2635 | 2650 | We can actually use any up vector we want, and simply project it onto this plane to get an up vector
|
2636 | 2651 | for the camera. I use the common convention of naming a “view up” (_vup_) vector. A couple of cross
|
2637 |
| -products, and we now have a complete orthonormal basis (u,v,w) to describe our camera’s orientation. |
| 2652 | +products, and we now have a complete orthonormal basis $(u,v,w)$ to describe our camera’s |
| 2653 | +orientation. |
2638 | 2654 |
|
2639 | 2655 | ![Figure [cam-up]: Camera view up direction](../images/fig.cam-up.jpg)
|
2640 | 2656 |
|
2641 | 2657 | Remember that `vup`, `v`, and `w` are all in the same plane. Note that, like before when our fixed
|
2642 | 2658 | camera faced -Z, our arbitrary view camera faces -w. And keep in mind that we can -- but we don’t
|
2643 |
| -have to -- use world up (0,1,0) to specify vup. This is convenient and will naturally keep your |
| 2659 | +have to -- use world up $(0,1,0)$ to specify vup. This is convenient and will naturally keep your |
2644 | 2660 | camera horizontally level until you decide to experiment with crazy camera angles.
|
2645 | 2661 |
|
2646 | 2662 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
2703 | 2719 |
|
2704 | 2720 | </div>
|
2705 | 2721 |
|
2706 |
| -And we can change field of view to get: |
| 2722 | +And we can change field of view: |
| 2723 | + |
| 2724 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 2725 | + camera cam(point3(-2,2,1), point3(0,0,-1), vup, 20, aspect_ratio); |
| 2726 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 2727 | + [Listing [change-field-view]: <kbd>[main.cc]</kbd> Change field of view] |
| 2728 | + |
| 2729 | +to get: |
2707 | 2730 |
|
2708 | 2731 | <div class="render">
|
2709 | 2732 |
|
|
0 commit comments