|
617 | 617 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
618 | 618 | if (discriminant < 0) {
|
619 | 619 | return -1.0;
|
620 |
| - } |
621 |
| - else { |
| 620 | + } else { |
622 | 621 | return (-b - sqrt(discriminant) ) / (2.0*a);
|
623 | 622 | }
|
624 | 623 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
683 | 682 |
|
684 | 683 | if (discriminant < 0) {
|
685 | 684 | return -1.0;
|
686 |
| - } |
687 |
| - else { |
| 685 | + } else { |
688 | 686 | return (-half_b - sqrt(discriminant) ) / a;
|
689 | 687 | }
|
690 | 688 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
792 | 790 | #define HITTABLE_LIST_H
|
793 | 791 |
|
794 | 792 | #include "hittable.h"
|
| 793 | + #include <vector> |
795 | 794 |
|
796 | 795 | class hittable_list: public hittable {
|
797 | 796 | public:
|
798 | 797 | hittable_list() {}
|
799 |
| - hittable_list(hittable **l, int n) {list = l; list_size = n; } |
| 798 | + hittable_list(hittable* object) { add(object); } |
| 799 | + |
| 800 | + void clear() { objects.clear(); } |
| 801 | + void add(hittable* object) { objects.push_back(object); } |
| 802 | + |
800 | 803 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
801 |
| - hittable **list; |
802 |
| - int list_size; |
| 804 | + |
| 805 | + public: |
| 806 | + std::vector<hittable*> objects; |
803 | 807 | };
|
804 | 808 |
|
805 | 809 | bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
806 | 810 | hit_record temp_rec;
|
807 | 811 | bool hit_anything = false;
|
808 |
| - double closest_so_far = t_max; |
809 |
| - for (int i = 0; i < list_size; i++) { |
810 |
| - if (list[i]->hit(r, t_min, closest_so_far, temp_rec)) { |
| 812 | + auto closest_so_far = t_max; |
| 813 | + |
| 814 | + for (auto object : objects) { |
| 815 | + if (object->hit(r, t_min, closest_so_far, temp_rec)) { |
811 | 816 | hit_anything = true;
|
812 | 817 | closest_so_far = temp_rec.t;
|
813 | 818 | rec = temp_rec;
|
814 | 819 | }
|
815 | 820 | }
|
| 821 | + |
816 | 822 | return hit_anything;
|
817 | 823 | }
|
818 | 824 |
|
|
821 | 827 | [Listing [hittable-list-initial]: <kbd>[hittable_list.h]</kbd> The hittable_list class]
|
822 | 828 | </div>
|
823 | 829 |
|
| 830 | +If you're unfamiliar with C++'s `std::vector`, this is a generic array-like collection of an |
| 831 | +arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector` automatically |
| 832 | +grows as more values are added: `objects.push_back(object)` adds a value to the end of the |
| 833 | +`std::vector` member variable `objects`. |
| 834 | + |
824 | 835 | <div class='together'></div>
|
825 | 836 | We need some math constants that we conveniently define in their own header file. For now we only
|
826 | 837 | need infinity, but we will also throw our own definition of pi in there, which we will need later.
|
|
876 | 887 | #include <iostream>
|
877 | 888 |
|
878 | 889 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
879 |
| - vec3 ray_color(const ray& r, hittable *world) { |
| 890 | + vec3 ray_color(const ray& r, hittable& world) { |
880 | 891 | hit_record rec;
|
881 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
882 |
| - return 0.5*vec3(rec.normal.x()+1, rec.normal.y()+1, rec.normal.z()+1); |
| 892 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 893 | + return 0.5 * (rec.normal + vec3(1,1,1)); |
883 | 894 | }
|
884 | 895 |
|
885 | 896 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
|
893 | 904 | int main() {
|
894 | 905 | int nx = 200;
|
895 | 906 | int ny = 100;
|
| 907 | + |
896 | 908 | std::cout << "P3\n" << nx << ' ' << ny << "\n255\n";
|
| 909 | + |
897 | 910 | vec3 lower_left_corner(-2.0, -1.0, -1.0);
|
898 | 911 | vec3 horizontal(4.0, 0.0, 0.0);
|
899 | 912 | vec3 vertical(0.0, 2.0, 0.0);
|
900 | 913 | vec3 origin(0.0, 0.0, 0.0);
|
901 | 914 |
|
902 | 915 |
|
903 | 916 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
904 |
| - hittable *list[2]; |
905 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5); |
906 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100); |
907 |
| - hittable *world = new hittable_list(list,2); |
| 917 | + hittable_list world; |
| 918 | + world.add(new sphere(vec3(0,0,-1), 0.5)); |
| 919 | + world.add(new sphere(vec3(0,-100.5,-1), 100)); |
908 | 920 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
909 | 921 |
|
910 | 922 | for (int j = ny-1; j >= 0; --j) {
|
|
1077 | 1089 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1078 | 1090 | int num_samples = 100;
|
1079 | 1091 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 1092 | + |
1080 | 1093 | std::cout << "P3\n" << nx << " " << ny << "\n255\n";
|
1081 | 1094 |
|
1082 |
| - hittable *list[2]; |
1083 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5); |
1084 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100); |
1085 |
| - hittable *world = new hittable_list(list,2); |
| 1095 | + hittable_list world; |
| 1096 | + world.add(new sphere(vec3(0,0,-1), 0.5)); |
| 1097 | + world.add(new sphere(vec3(0,-100.5,-1), 100)); |
1086 | 1098 |
|
1087 | 1099 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1088 | 1100 | camera cam;
|
|
1196 | 1208 | Then update the `ray_color()` function to use the new random direction generator:
|
1197 | 1209 |
|
1198 | 1210 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1199 |
| - vec3 ray_color(const ray& r, hittable *world) { |
| 1211 | + vec3 ray_color(const ray& r, hittable& world) { |
1200 | 1212 | hit_record rec;
|
1201 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1213 | + if (world.hit(r, 0.0, infinity, rec)) { |
1202 | 1214 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1203 | 1215 | vec3 target = rec.p + rec.normal + random_in_unit_sphere();
|
1204 | 1216 | return 0.5 * ray_color(ray(rec.p, target - rec.p), world);
|
|
1220 | 1232 | depth, returning no light contribution at the maximum depth:
|
1221 | 1233 |
|
1222 | 1234 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1223 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1235 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1224 | 1236 | hit_record rec;
|
1225 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1237 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1238 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1226 | 1239 | if (depth <= 0)
|
1227 | 1240 | return vec3(0,0,0);
|
1228 | 1241 | vec3 target = rec.p + rec.normal + random_in_unit_sphere();
|
|
1242 | 1255 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1243 | 1256 | int max_depth = 50;
|
1244 | 1257 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
| 1258 | + |
1245 | 1259 | ...
|
1246 | 1260 | for (int j = ny-1; j >= 0; --j) {
|
1247 | 1261 | std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
|
|
1316 | 1330 | point approximation the sphere intersector gives us. So we need to ignore hits very near zero:
|
1317 | 1331 |
|
1318 | 1332 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1319 |
| - if (world->hit(r, 0.001, infinity, rec)) { |
| 1333 | + if (world.hit(r, 0.001, infinity, rec)) { |
1320 | 1334 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1321 | 1335 | [Listing [reflect-tolerance]: <kbd>[main.cc]</kbd> Calculating reflected ray origins with tolerance]
|
1322 | 1336 |
|
|
1357 | 1371 | function.
|
1358 | 1372 |
|
1359 | 1373 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1360 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1374 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1361 | 1375 | hit_record rec;
|
1362 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1376 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1377 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1363 | 1378 | if (depth <= 0)
|
1364 | 1379 | return vec3(0,0,0);
|
1365 | 1380 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
|
1432 | 1447 | Plugging the new formula into the `ray_color()` function:
|
1433 | 1448 |
|
1434 | 1449 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1435 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1450 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1436 | 1451 | hit_record rec;
|
1437 |
| - if (world->hit(r, 0.0, infinity, rec)) { |
| 1452 | + if (world.hit(r, 0.0, infinity, rec)) { |
| 1453 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1438 | 1454 | if (depth <= 0)
|
1439 | 1455 | return vec3(0,0,0);
|
1440 | 1456 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
|
1660 | 1676 | We need to modify the color function to use this:
|
1661 | 1677 |
|
1662 | 1678 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1663 |
| - vec3 ray_color(const ray& r, hittable *world, int depth) { |
| 1679 | + vec3 ray_color(const ray& r, hittable& world, int depth) { |
1664 | 1680 | hit_record rec;
|
1665 | 1681 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1666 |
| - if (world->hit(r, 0.001, infinity, rec)) { |
| 1682 | + if (world.hit(r, 0.001, infinity, rec)) { |
| 1683 | + // If we've exceeded the ray bounce limit, no more light is gathered. |
1667 | 1684 | if (depth <= 0)
|
1668 | 1685 | return vec3(0,0,0);
|
1669 | 1686 | ray scattered;
|
|
1696 | 1713 |
|
1697 | 1714 |
|
1698 | 1715 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1699 |
| - hittable *list[4]; |
1700 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.7, 0.3, 0.3))); |
1701 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); |
1702 |
| - list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2))); |
1703 |
| - list[3] = new sphere(vec3(-1,0,-1), 0.5, new metal(vec3(0.8, 0.8, 0.8))); |
1704 |
| - hittable *world = new hittable_list(list,4); |
| 1716 | + hittable_list world; |
| 1717 | + world.add(new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.7, 0.3, 0.3)))); |
| 1718 | + world.add(new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0)))); |
| 1719 | + world.add(new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2)))); |
| 1720 | + world.add(new sphere(vec3(-1,0,-1), 0.5, new metal(vec3(0.8, 0.8, 0.8)))); |
1705 | 1721 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1706 | 1722 |
|
1707 | 1723 | camera cam;
|
|
2068 | 2084 |
|
2069 | 2085 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2070 | 2086 | auto R = cos(pi/4);
|
2071 |
| - list[0] = new sphere(vec3(-R,0,-1), R, new lambertian(vec3(0, 0, 1))); |
2072 |
| - list[1] = new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0))); |
2073 |
| - hittable *world = new hittable_list(list,2); |
| 2087 | + hittable_list world; |
| 2088 | + world.add(new sphere(vec3(-R,0,-1), R, new lambertian(vec3(0, 0, 1)))); |
| 2089 | + world.add(new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0)))); |
2074 | 2090 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2075 | 2091 | [Listing [scene-wide-angle]: <kbd>[main.cc]</kbd> Scene with wide-angle camera]
|
2076 | 2092 |
|
|
2307 | 2323 | First let’s make the image on the cover of this book -- lots of random spheres:
|
2308 | 2324 |
|
2309 | 2325 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2310 |
| - hittable *random_scene() { |
2311 |
| - int n = 500; |
2312 |
| - hittable **list = new hittable*[n+1]; |
2313 |
| - list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5))); |
| 2326 | + hittable_list random_scene() { |
| 2327 | + hittable_list objects; |
| 2328 | + |
| 2329 | + objects.add(new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)))); |
| 2330 | + |
2314 | 2331 | int i = 1;
|
2315 | 2332 | for (int a = -11; a < 11; a++) {
|
2316 | 2333 | for (int b = -11; b < 11; b++) {
|
2317 | 2334 | auto choose_mat = random_double();
|
2318 | 2335 | vec3 center(a + 0.9*random_double(), 0.2, b + 0.9*random_double());
|
2319 |
| - if ((center-vec3(4,0.2,0)).length() > 0.9) { |
| 2336 | + if ((center - vec3(4, .2, 0)).length() > 0.9) { |
2320 | 2337 | if (choose_mat < 0.8) {
|
2321 | 2338 | // diffuse
|
2322 | 2339 | auto albedo = vec3::random() * vec3::random();
|
2323 |
| - list[i++] = new sphere(center, 0.2, new lambertian(albedo)); |
| 2340 | + objects.add(new sphere(center, 0.2, new lambertian(albedo))); |
2324 | 2341 | } else if (choose_mat < 0.95) {
|
2325 | 2342 | // metal
|
2326 | 2343 | auto albedo = vec3::random(.5, 1);
|
2327 | 2344 | auto fuzz = random_double(0, .5);
|
2328 |
| - list[i++] = new sphere(center, 0.2, new metal(albedo, fuzz)); |
| 2345 | + objects.add(new sphere(center, 0.2, new metal(albedo, fuzz))); |
2329 | 2346 | } else {
|
2330 | 2347 | // glass
|
2331 |
| - list[i++] = new sphere(center, 0.2, new dielectric(1.5)); |
| 2348 | + objects.add(new sphere(center, 0.2, new dielectric(1.5))); |
2332 | 2349 | }
|
2333 | 2350 | }
|
2334 | 2351 | }
|
2335 | 2352 | }
|
2336 | 2353 |
|
2337 |
| - list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5)); |
2338 |
| - list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1))); |
2339 |
| - list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0)); |
| 2354 | + objects.add(new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5))); |
| 2355 | + objects.add(new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)))); |
| 2356 | + objects.add(new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0))); |
2340 | 2357 |
|
2341 |
| - return new hittable_list(list,i); |
| 2358 | + return objects; |
| 2359 | + } |
| 2360 | + |
| 2361 | + int main() { |
| 2362 | + ... |
| 2363 | + auto world = random_scene(); |
| 2364 | + ... |
2342 | 2365 | }
|
2343 | 2366 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2344 | 2367 | [Listing [scene-final]: <kbd>[main.cc]</kbd> Final scene]
|
|
0 commit comments