|
915 | 915 | #define HITTABLE_LIST_H
|
916 | 916 |
|
917 | 917 | #include "hittable.h"
|
| 918 | + #include <memory> |
918 | 919 | #include <vector>
|
919 | 920 |
|
| 921 | + using std::shared_ptr; |
| 922 | + using std::make_shared; |
| 923 | + |
920 | 924 | class hittable_list: public hittable {
|
921 | 925 | public:
|
922 | 926 | hittable_list() {}
|
923 |
| - hittable_list(hittable* object) { add(object); } |
| 927 | + hittable_list(shared_ptr<hittable> object) { add(object); } |
924 | 928 |
|
925 |
| - void clear() { objects.clear(); } |
926 |
| - void add(hittable* object) { objects.push_back(object); } |
| 929 | + void clear() { objects.clear(); } |
| 930 | + void add(shared_ptr<hittable> object) { objects.push_back(object); } |
927 | 931 |
|
928 | 932 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
929 | 933 |
|
930 | 934 | public:
|
931 |
| - std::vector<hittable*> objects; |
| 935 | + std::vector<shared_ptr<hittable>> objects; |
932 | 936 | };
|
933 | 937 |
|
934 | 938 | bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
|
952 | 956 | [Listing [hittable-list-initial]: <kbd>[hittable_list.h]</kbd> The hittable_list class]
|
953 | 957 | </div>
|
954 | 958 |
|
955 |
| -If you're unfamiliar with C++'s `std::vector`, this is a generic array-like collection of an |
956 |
| -arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector` automatically |
957 |
| -grows as more values are added: `objects.push_back(object)` adds a value to the end of the |
958 |
| -`std::vector` member variable `objects`. |
| 959 | +## Some New C++ Features |
| 960 | + |
| 961 | +The `hittable_list` class code uses two C++ features that may trip you up if you're not normally a |
| 962 | +C++ programmer: `vector` and `shared_ptr`. |
| 963 | + |
| 964 | +`shared_ptr<type>` is a pointer to some allocated type, with reference-counting semantics. |
| 965 | +Every time you assign its value to another shared pointer (usually with a simple assignment), the |
| 966 | +reference count is incremented. As shared pointers go out of scope (like at the end of a block or |
| 967 | +function), the reference count is decremented. Once the count goes to zero, the object is deleted. |
| 968 | + |
| 969 | +<div class='together'> |
| 970 | +Typically, a shared pointer is first initialized with a newly-allocated object, something like this: |
| 971 | + |
| 972 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 973 | + shared_ptr<thing> thing_ptr = make_shared<thing>(1, true); |
| 974 | + auto thing2_ptr = make_shared<thing2>(2, false); |
| 975 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 976 | + [Listing [shared-ptr]: An example allocation using `shared_ptr`] |
| 977 | + |
| 978 | +`make_shared<thing>(1, true)` allocates a new instance of type `thing`, using the constructor |
| 979 | +arguments `(1, true)`. It returns a `shared_ptr<thing>`. This can be simplified as in the second |
| 980 | +line with the `auto` type declaration, because the type is sufficiently defined by the return type |
| 981 | +of `make_shared<thing2>`. |
| 982 | +</div> |
| 983 | + |
| 984 | +We'll use shared pointers in our code, because it allows multiple objects to use a common object |
| 985 | +(for example, a bunch of spheres that all use the same material), and because it makes memory |
| 986 | +management automatic and easier to reason about. |
| 987 | + |
| 988 | +`std::shared_ptr` is included with the `<memory>` header. |
| 989 | + |
| 990 | +The second C++ feature you may be unfamiliar with is `std::vector`. This is a generic array-like |
| 991 | +collection of an arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector` |
| 992 | +automatically grows as more values are added: `objects.push_back(object)` adds a value to the end of |
| 993 | +the `std::vector` member variable `objects`. |
| 994 | + |
| 995 | +`std::vector` is included with the `<vector>` header. |
| 996 | + |
| 997 | +Finally, the `using` statements in listing [hittable-list-initial] tell the compiler that we'll be |
| 998 | +getting `shared_ptr` and `make_shared` from the `std` library, so we don't need to prefex these with |
| 999 | +`std::` every time we reference them. |
| 1000 | + |
| 1001 | +## Common Constants and Utility Functions |
959 | 1002 |
|
960 | 1003 | <div class='together'></div>
|
961 | 1004 | We need some math constants that we conveniently define in their own header file. For now we only
|
|
968 | 1011 | #ifndef RTWEEKEND_H
|
969 | 1012 | #define RTWEEKEND_H
|
970 | 1013 |
|
971 |
| - #include <limits> |
972 | 1014 | #include <cmath>
|
| 1015 | + #include <cstdlib> |
| 1016 | + #include <limits> |
| 1017 | + #include <memory> |
| 1018 | + |
| 1019 | + |
| 1020 | + // Usings |
| 1021 | + |
| 1022 | + using std::shared_ptr; |
| 1023 | + using std::make_shared; |
973 | 1024 |
|
974 | 1025 | // Constants
|
975 | 1026 |
|
|
1040 | 1091 |
|
1041 | 1092 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1042 | 1093 | hittable_list world;
|
1043 |
| - world.add(new sphere(vec3(0,0,-1), 0.5)); |
1044 |
| - world.add(new sphere(vec3(0,-100.5,-1), 100)); |
| 1094 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5)); |
| 1095 | + world.add(make_shared<sphere>(vec3(0,-100.5,-1), 100)); |
1045 | 1096 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1046 | 1097 |
|
1047 | 1098 | for (int j = ny-1; j >= 0; --j) {
|
|
1218 | 1269 | std::cout << "P3\n" << nx << " " << ny << "\n255\n";
|
1219 | 1270 |
|
1220 | 1271 | hittable_list world;
|
1221 |
| - world.add(new sphere(vec3(0,0,-1), 0.5)); |
1222 |
| - world.add(new sphere(vec3(0,-100.5,-1), 100)); |
| 1272 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5)); |
| 1273 | + world.add(make_shared<sphere>(vec3(0,-100.5,-1), 100)); |
1223 | 1274 |
|
1224 | 1275 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1225 | 1276 | camera cam;
|
|
1650 | 1701 | vec3 p;
|
1651 | 1702 | vec3 normal;
|
1652 | 1703 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1653 |
| - material *mat_ptr; |
| 1704 | + shared_ptr<material> mat_ptr; |
1654 | 1705 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1655 | 1706 | double t;
|
1656 | 1707 | bool front_face;
|
|
1687 | 1738 | class sphere: public hittable {
|
1688 | 1739 | public:
|
1689 | 1740 | sphere() {}
|
1690 |
| - sphere(vec3 cen, double r, material *m) : center(cen), radius(r), mat_ptr(m) {}; |
| 1741 | + |
| 1742 | + sphere(vec3 cen, double r, shared_ptr<material> m) |
| 1743 | + : center(cen), radius(r), mat_ptr(m) {}; |
| 1744 | + |
1691 | 1745 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
| 1746 | + |
| 1747 | + public: |
1692 | 1748 | vec3 center;
|
1693 | 1749 | double radius;
|
1694 | 1750 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1695 |
| - material *mat_ptr; |
| 1751 | + shared_ptr<material> mat_ptr; |
1696 | 1752 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1697 | 1753 | };
|
1698 | 1754 | bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
|
1752 | 1808 | return true;
|
1753 | 1809 | }
|
1754 | 1810 |
|
| 1811 | + public: |
1755 | 1812 | vec3 albedo;
|
1756 | 1813 | };
|
1757 | 1814 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
1799 | 1856 | attenuation = albedo;
|
1800 | 1857 | return (dot(scattered.direction(), rec.normal) > 0);
|
1801 | 1858 | }
|
| 1859 | + |
| 1860 | + public: |
1802 | 1861 | vec3 albedo;
|
1803 | 1862 | };
|
1804 | 1863 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
1847 | 1906 |
|
1848 | 1907 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1849 | 1908 | hittable_list world;
|
1850 |
| - world.add(new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.7, 0.3, 0.3)))); |
1851 |
| - world.add(new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0)))); |
1852 |
| - world.add(new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2)))); |
1853 |
| - world.add(new sphere(vec3(-1,0,-1), 0.5, new metal(vec3(0.8, 0.8, 0.8)))); |
| 1909 | + |
| 1910 | + world.add(make_shared<sphere>( |
| 1911 | + vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.7, 0.3, 0.3)))); |
| 1912 | + |
| 1913 | + world.add(make_shared<sphere>( |
| 1914 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0)))); |
| 1915 | + |
| 1916 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2)))); |
| 1917 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.8, 0.8)))); |
1854 | 1918 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1855 | 1919 |
|
1856 | 1920 | camera cam;
|
|
1912 | 1976 | attenuation = albedo;
|
1913 | 1977 | return (dot(scattered.direction(), rec.normal) > 0);
|
1914 | 1978 | }
|
| 1979 | + |
| 1980 | + public: |
1915 | 1981 | vec3 albedo;
|
1916 | 1982 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1917 | 1983 | double fuzz;
|
|
2134 | 2200 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2135 | 2201 | }
|
2136 | 2202 |
|
| 2203 | + public: |
2137 | 2204 | double ref_idx;
|
2138 | 2205 | };
|
2139 | 2206 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2144 | 2211 | Attenuation is always 1 -- the glass surface absorbs nothing. If we try that out with these parameters:
|
2145 | 2212 |
|
2146 | 2213 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2147 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.1, 0.2, 0.5))); |
2148 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); |
2149 |
| - list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2), 0.0)); |
2150 |
| - list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5)); |
| 2214 | + world.add(make_shared<sphere>( |
| 2215 | + vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.1, 0.2, 0.5))); |
| 2216 | + |
| 2217 | + world.add(make_shared<sphere>( |
| 2218 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0))); |
| 2219 | + |
| 2220 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2), 0.0)); |
| 2221 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<dielectric>(1.5)); |
2151 | 2222 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2152 | 2223 | [Listing [scene-dielectric]: <kbd>[main.cc]</kbd> Scene with dielectric sphere]
|
2153 | 2224 |
|
|
2206 | 2277 | return true;
|
2207 | 2278 | }
|
2208 | 2279 |
|
| 2280 | + public: |
2209 | 2281 | double ref_idx;
|
2210 | 2282 | };
|
2211 | 2283 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2218 | 2290 | to make a hollow glass sphere:
|
2219 | 2291 |
|
2220 | 2292 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2221 |
| - list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.1, 0.2, 0.5))); |
2222 |
| - list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); |
2223 |
| - list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2), 0.3)); |
2224 |
| - list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5)); |
2225 |
| - list[4] = new sphere(vec3(-1,0,-1), -0.45, new dielectric(1.5)); |
| 2293 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.1, 0.2, 0.5))); |
| 2294 | + world.add(make_shared<sphere>( |
| 2295 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0))); |
| 2296 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2), 0.3)); |
| 2297 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<dielectric>(1.5)); |
| 2298 | + world.add(make_shared<sphere>(vec3(-1,0,-1), -0.45, make_shared<dielectric>(1.5)); |
2226 | 2299 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2227 | 2300 | [Listing [scene-hollow-glass]: <kbd>[main.cc]</kbd> Scene with hollow glass sphere]
|
2228 | 2301 | </div>
|
|
2295 | 2368 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2296 | 2369 | auto R = cos(pi/4);
|
2297 | 2370 | hittable_list world;
|
2298 |
| - world.add(new sphere(vec3(-R,0,-1), R, new lambertian(vec3(0, 0, 1)))); |
2299 |
| - world.add(new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0)))); |
| 2371 | + world.add(make_shared<sphere>(vec3(-R,0,-1), R, make_shared<lambertian>(vec3(0, 0, 1)))); |
| 2372 | + world.add(make_shared<sphere(>vec3( R,0,-1), R, make_shared<lambertian>(vec3(1, 0, 0)))); |
2300 | 2373 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2301 | 2374 | [Listing [scene-wide-angle]: <kbd>[main.cc]</kbd> Scene with wide-angle camera]
|
2302 | 2375 |
|
|
2536 | 2609 | hittable_list random_scene() {
|
2537 | 2610 | hittable_list objects;
|
2538 | 2611 |
|
2539 |
| - objects.add(new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)))); |
| 2612 | + objects.add(make_shared<sphere>( |
| 2613 | + vec3(0,-1000,0), 1000, make_shared<lambertian>(vec3(0.5, 0.5, 0.5)))); |
2540 | 2614 |
|
2541 | 2615 | int i = 1;
|
2542 | 2616 | for (int a = -11; a < 11; a++) {
|
|
2547 | 2621 | if (choose_mat < 0.8) {
|
2548 | 2622 | // diffuse
|
2549 | 2623 | auto albedo = vec3::random() * vec3::random();
|
2550 |
| - objects.add(new sphere(center, 0.2, new lambertian(albedo))); |
| 2624 | + objects.add( |
| 2625 | + make_shared<sphere>(center, 0.2, make_shared<lambertian>(albedo))); |
2551 | 2626 | } else if (choose_mat < 0.95) {
|
2552 | 2627 | // metal
|
2553 | 2628 | auto albedo = vec3::random(.5, 1);
|
2554 | 2629 | auto fuzz = random_double(0, .5);
|
2555 |
| - objects.add(new sphere(center, 0.2, new metal(albedo, fuzz))); |
| 2630 | + objects.add( |
| 2631 | + make_shared<sphere>(center, 0.2, make_shared<metal>(albedo, fuzz))); |
2556 | 2632 | } else {
|
2557 | 2633 | // glass
|
2558 |
| - objects.add(new sphere(center, 0.2, new dielectric(1.5))); |
| 2634 | + objects.add(make_shared<sphere>(center, 0.2, make_shared<dielectric>(1.5))); |
2559 | 2635 | }
|
2560 | 2636 | }
|
2561 | 2637 | }
|
2562 | 2638 | }
|
2563 | 2639 |
|
2564 |
| - objects.add(new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5))); |
2565 |
| - objects.add(new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)))); |
2566 |
| - objects.add(new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0))); |
| 2640 | + objects.add(make_shared<sphere>(vec3(0, 1, 0), 1.0, make_shared<dielectric>(1.5))); |
| 2641 | + |
| 2642 | + objects.add( |
| 2643 | + make_shared<sphere>(vec3(-4, 1, 0), 1.0, make_shared<lambertian>(vec3(0.4, 0.2, 0.1)))); |
| 2644 | + |
| 2645 | + objects.add( |
| 2646 | + make_shared<sphere>(vec3(4, 1, 0), 1.0, make_shared<metal>(vec3(0.7, 0.6, 0.5), 0.0))); |
2567 | 2647 |
|
2568 | 2648 | return objects;
|
2569 | 2649 | }
|
|
0 commit comments