|
618 | 618 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
619 | 619 | if (discriminant < 0) {
|
620 | 620 | return -1.0;
|
621 |
| - } |
622 |
| - else { |
| 621 | + } else { |
623 | 622 | return (-b - sqrt(discriminant) ) / (2.0*a);
|
624 | 623 | }
|
625 | 624 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
684 | 683 |
|
685 | 684 | if (discriminant < 0) {
|
686 | 685 | return -1.0;
|
687 |
| - } |
688 |
| - else { |
| 686 | + } else { |
689 | 687 | return (-half_b - sqrt(discriminant) ) / a;
|
690 | 688 | }
|
691 | 689 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
938 | 936 | #define HITTABLE_LIST_H
|
939 | 937 |
|
940 | 938 | #include "hittable.h"
|
| 939 | + #include <vector> |
941 | 940 |
|
942 | 941 | class hittable_list: public hittable {
|
943 | 942 | public:
|
944 | 943 | hittable_list() {}
|
945 |
| - hittable_list(hittable **l, int n) {list = l; list_size = n; } |
| 944 | + hittable_list(hittable* object) { add(object); } |
| 945 | + |
| 946 | + void clear() { objects.clear(); } |
| 947 | + void add(hittable* object) { objects.push_back(object); } |
| 948 | + |
946 | 949 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
947 |
| - hittable **list; |
948 |
| - int list_size; |
| 950 | + |
| 951 | + public: |
| 952 | + std::vector<hittable*> objects; |
949 | 953 | };
|
950 | 954 |
|
951 | 955 | bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
952 | 956 | hit_record temp_rec;
|
953 | 957 | bool hit_anything = false;
|
954 |
| - double closest_so_far = t_max; |
955 |
| - for (int i = 0; i < list_size; i++) { |
956 |
| - if (list[i]->hit(r, t_min, closest_so_far, temp_rec)) { |
| 958 | + auto closest_so_far = t_max; |
| 959 | + |
| 960 | + for (auto object : objects) { |
| 961 | + if (object->hit(r, t_min, closest_so_far, temp_rec)) { |
957 | 962 | hit_anything = true;
|
958 | 963 | closest_so_far = temp_rec.t;
|
959 | 964 | rec = temp_rec;
|
960 | 965 | }
|
961 | 966 | }
|
| 967 | + |
962 | 968 | return hit_anything;
|
963 | 969 | }
|
964 | 970 |
|
|
967 | 973 | [Listing [hittable-list-initial]: <kbd>[hittable_list.h]</kbd> The hittable_list class]
|
968 | 974 | </div>
|
969 | 975 |
|
| 976 | +If you're unfamiliar with C++'s `std::vector`, this is a generic array-like collection of an |
| 977 | +arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector` automatically |
| 978 | +grows as more values are added: `objects.push_back(object)` adds a value to the end of the |
| 979 | +`std::vector` member variable `objects`. |
| 980 | + |
970 | 981 | <div class='together'></div>
|
971 | 982 | We need some math constants that we conveniently define in their own header file. For now we only
|
972 | 983 | need infinity, but we will also throw our own definition of pi in there, which we will need later.
|
|
1022 | 1033 | #include <iostream>
|
1023 | 1034 |
|
1024 | 1035 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1025 |
| - vec3 ray_color(const ray& r, hittable *world) { |
| 1036 | + vec3 ray_color(const ray& r, hittable& world) { |
1026 | 1037 | hit_record rec;
|
1027 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
1028 |
| - return 0.5*vec3(rec.normal.x()+1, rec.normal.y()+1, rec.normal.z()+1); |
| 1038 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1039 | + return 0.5 * (rec.normal + vec3(1,1,1)); |
1029 | 1040 | }
|
1030 | 1041 |
|
1031 | 1042 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
1039 | 1050 | int main() {
|
1040 | 1051 | int nx = 200;
|
1041 | 1052 | int ny = 100;
|
| 1053 | + |
1042 | 1054 | std::cout << "P3\n" << nx << ' ' << ny << "\n255\n";
|
| 1055 | + |
1043 | 1056 | vec3 lower_left_corner(-2.0, -1.0, -1.0);
|
1044 | 1057 | vec3 horizontal(4.0, 0.0, 0.0);
|
1045 | 1058 | vec3 vertical(0.0, 2.0, 0.0);
|
1046 | 1059 | vec3 origin(0.0, 0.0, 0.0);
|
1047 | 1060 |
|
1048 | 1061 |
|
1049 | 1062 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1050 |
| - hittable *list[2]; |
1051 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5); |
1052 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100); |
1053 |
| - hittable *world = new hittable_list(list,2); |
| 1063 | + hittable_list world; |
| 1064 | + world.add(new sphere(vec3(0,0,-1), 0.5)); |
| 1065 | + world.add(new sphere(vec3(0,-100.5,-1), 100)); |
1054 | 1066 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1055 | 1067 |
|
1056 | 1068 | for (int j = ny-1; j >= 0; --j) {
|
|
1223 | 1235 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1224 | 1236 | int num_samples = 100;
|
1225 | 1237 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 1238 | + |
1226 | 1239 | std::cout << "P3\n" << nx << " " << ny << "\n255\n";
|
1227 | 1240 |
|
1228 |
| - hittable *list[2]; |
1229 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5); |
1230 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100); |
1231 |
| - hittable *world = new hittable_list(list,2); |
| 1241 | + hittable_list world; |
| 1242 | + world.add(new sphere(vec3(0,0,-1), 0.5)); |
| 1243 | + world.add(new sphere(vec3(0,-100.5,-1), 100)); |
1232 | 1244 |
|
1233 | 1245 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1234 | 1246 | camera cam;
|
|
1342 | 1354 | Then update the `ray_color()` function to use the new random direction generator:
|
1343 | 1355 |
|
1344 | 1356 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1345 |
| - vec3 ray_color(const ray& r, hittable *world) { |
| 1357 | + vec3 ray_color(const ray& r, hittable& world) { |
1346 | 1358 | hit_record rec;
|
1347 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1359 | + if (world.hit(r, 0.0, infinity, rec)) { |
1348 | 1360 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1349 | 1361 | vec3 target = rec.p + rec.normal + random_in_unit_sphere();
|
1350 | 1362 | return 0.5 * ray_color(ray(rec.p, target - rec.p), world);
|
|
1366 | 1378 | depth, returning no light contribution at the maximum depth:
|
1367 | 1379 |
|
1368 | 1380 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1369 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1381 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1370 | 1382 | hit_record rec;
|
1371 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1383 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1384 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1372 | 1385 | if (depth <= 0)
|
1373 | 1386 | return vec3(0,0,0);
|
1374 | 1387 | vec3 target = rec.p + rec.normal + random_in_unit_sphere();
|
|
1388 | 1401 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1389 | 1402 | int max_depth = 50;
|
1390 | 1403 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 1404 | + |
1391 | 1405 | ...
|
1392 | 1406 | for (int j = ny-1; j >= 0; --j) {
|
1393 | 1407 | std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
|
|
1462 | 1476 | point approximation the sphere intersector gives us. So we need to ignore hits very near zero:
|
1463 | 1477 |
|
1464 | 1478 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1465 |
| - if (world->hit(r, 0.001, infinity, rec)) { |
| 1479 | + if (world.hit(r, 0.001, infinity, rec)) { |
1466 | 1480 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1467 | 1481 | [Listing [reflect-tolerance]: <kbd>[main.cc]</kbd> Calculating reflected ray origins with tolerance]
|
1468 | 1482 |
|
|
1503 | 1517 | function.
|
1504 | 1518 |
|
1505 | 1519 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1506 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1520 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1507 | 1521 | hit_record rec;
|
1508 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1522 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1523 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1509 | 1524 | if (depth <= 0)
|
1510 | 1525 | return vec3(0,0,0);
|
1511 | 1526 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
|
1578 | 1593 | Plugging the new formula into the `ray_color()` function:
|
1579 | 1594 |
|
1580 | 1595 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1581 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1596 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1582 | 1597 | hit_record rec;
|
1583 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1598 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1599 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1584 | 1600 | if (depth <= 0)
|
1585 | 1601 | return vec3(0,0,0);
|
1586 | 1602 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
|
1826 | 1842 | We need to modify the color function to use this:
|
1827 | 1843 |
|
1828 | 1844 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1829 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1845 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1830 | 1846 | hit_record rec;
|
1831 |
| - if (world->hit(r, 0.001, infinity, rec)) { |
| 1847 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
| 1848 | + if (world.hit(r, 0.001, infinity, rec)) { |
| 1849 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1832 | 1850 | if (depth <= 0)
|
1833 | 1851 | return vec3(0,0,0);
|
1834 |
| - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight |
1835 | 1852 | ray scattered;
|
1836 | 1853 | vec3 attenuation;
|
1837 | 1854 | if (rec.mat_ptr->scatter(r, rec, attenuation, scattered))
|
|
1862 | 1879 |
|
1863 | 1880 |
|
1864 | 1881 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1865 |
| - hittable *list[4]; |
1866 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.7, 0.3, 0.3))); |
1867 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); |
1868 |
| - list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2))); |
1869 |
| - list[3] = new sphere(vec3(-1,0,-1), 0.5, new metal(vec3(0.8, 0.8, 0.8))); |
1870 |
| - hittable *world = new hittable_list(list,4); |
| 1882 | + hittable_list world; |
| 1883 | + world.add(new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.7, 0.3, 0.3)))); |
| 1884 | + world.add(new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0)))); |
| 1885 | + world.add(new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2)))); |
| 1886 | + world.add(new sphere(vec3(-1,0,-1), 0.5, new metal(vec3(0.8, 0.8, 0.8)))); |
1871 | 1887 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1872 | 1888 |
|
1873 | 1889 | camera cam;
|
|
2321 | 2337 |
|
2322 | 2338 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2323 | 2339 | auto R = cos(pi/4);
|
2324 |
| - list[0] = new sphere(vec3(-R,0,-1), R, new lambertian(vec3(0, 0, 1))); |
2325 |
| - list[1] = new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0))); |
2326 |
| - hittable *world = new hittable_list(list,2); |
| 2340 | + hittable_list world; |
| 2341 | + world.add(new sphere(vec3(-R,0,-1), R, new lambertian(vec3(0, 0, 1)))); |
| 2342 | + world.add(new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0)))); |
2327 | 2343 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2328 | 2344 | [Listing [scene-wide-angle]: <kbd>[main.cc]</kbd> Scene with wide-angle camera]
|
2329 | 2345 |
|
|
2560 | 2576 | First let’s make the image on the cover of this book -- lots of random spheres:
|
2561 | 2577 |
|
2562 | 2578 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2563 |
| - hittable *random_scene() { |
2564 |
| - int n = 500; |
2565 |
| - hittable **list = new hittable*[n+1]; |
2566 |
| - list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5))); |
| 2579 | + hittable_list random_scene() { |
| 2580 | + hittable_list objects; |
| 2581 | + |
| 2582 | + objects.add(new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)))); |
| 2583 | + |
2567 | 2584 | int i = 1;
|
2568 | 2585 | for (int a = -11; a < 11; a++) {
|
2569 | 2586 | for (int b = -11; b < 11; b++) {
|
2570 | 2587 | auto choose_mat = random_double();
|
2571 | 2588 | vec3 center(a + 0.9*random_double(), 0.2, b + 0.9*random_double());
|
2572 |
| - if ((center-vec3(4,0.2,0)).length() > 0.9) { |
| 2589 | + if ((center - vec3(4, 0.2, 0)).length() > 0.9) { |
2573 | 2590 | if (choose_mat < 0.8) {
|
2574 | 2591 | // diffuse
|
2575 | 2592 | auto albedo = vec3::random() * vec3::random();
|
2576 |
| - list[i++] = new sphere(center, 0.2, new lambertian(albedo)); |
| 2593 | + objects.add(new sphere(center, 0.2, new lambertian(albedo))); |
2577 | 2594 | } else if (choose_mat < 0.95) {
|
2578 | 2595 | // metal
|
2579 | 2596 | auto albedo = vec3::random(.5, 1);
|
2580 | 2597 | auto fuzz = random_double(0, .5);
|
2581 |
| - list[i++] = new sphere(center, 0.2, new metal(albedo, fuzz)); |
| 2598 | + objects.add(new sphere(center, 0.2, new metal(albedo, fuzz))); |
2582 | 2599 | } else {
|
2583 | 2600 | // glass
|
2584 |
| - list[i++] = new sphere(center, 0.2, new dielectric(1.5)); |
| 2601 | + objects.add(new sphere(center, 0.2, new dielectric(1.5))); |
2585 | 2602 | }
|
2586 | 2603 | }
|
2587 | 2604 | }
|
2588 | 2605 | }
|
2589 | 2606 |
|
2590 |
| - list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5)); |
2591 |
| - list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1))); |
2592 |
| - list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0)); |
| 2607 | + objects.add(new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5))); |
| 2608 | + objects.add(new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)))); |
| 2609 | + objects.add(new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0))); |
2593 | 2610 |
|
2594 |
| - return new hittable_list(list,i); |
| 2611 | + return objects; |
| 2612 | + } |
| 2613 | + |
| 2614 | + int main() { |
| 2615 | + ... |
| 2616 | + auto world = random_scene(); |
| 2617 | + ... |
2595 | 2618 | }
|
2596 | 2619 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2597 | 2620 | [Listing [scene-final]: <kbd>[main.cc]</kbd> Final scene]
|
|
0 commit comments