|
920 | 920 | class hittable_list: public hittable {
|
921 | 921 | public:
|
922 | 922 | hittable_list() {}
|
923 |
| - hittable_list(hittable* object) { add(object); } |
| 923 | + hittable_list(shared_ptr<hittable> object) { add(object); } |
924 | 924 |
|
925 |
| - void clear() { objects.clear(); } |
926 |
| - void add(hittable* object) { objects.push_back(object); } |
| 925 | + void clear() { objects.clear(); } |
| 926 | + void add(shared_ptr<hittable> object) { objects.push_back(object); } |
927 | 927 |
|
928 | 928 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
929 | 929 |
|
930 | 930 | public:
|
931 |
| - std::vector<hittable*> objects; |
| 931 | + std::vector<shared_ptr<hittable>> objects; |
932 | 932 | };
|
933 | 933 |
|
934 | 934 | bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
|
952 | 952 | [Listing [hittable-list-initial]: <kbd>[hittable_list.h]</kbd> The hittable_list class]
|
953 | 953 | </div>
|
954 | 954 |
|
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`. |
| 955 | +## Some New C++ Features |
| 956 | + |
| 957 | +This code uses two C++ features that may trip you up if you're not normally a C++ programmer: |
| 958 | +`vector` and `shared_ptr`. |
| 959 | + |
| 960 | +`shared_ptr<type>` is a pointer to some allocated type, with reference-counting semantics. |
| 961 | +Every time you assign its value to another shared pointer (usually with a simple assignment), the |
| 962 | +reference count is incremented. As shared pointers go out of scope (like at the end of a block or |
| 963 | +function), the reference count is decremented. Once the count goes to zero, the object is deleted. |
| 964 | + |
| 965 | +<div class='together'> |
| 966 | +Typically, a shared pointer is first initialized with a newly-allocated object, something like this: |
| 967 | + |
| 968 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ |
| 969 | + shared_ptr<thing> thing_ptr = make_shared<thing>(1, true); |
| 970 | + auto thing2_ptr = make_shared<thing2>(2, false); |
| 971 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 972 | + [Listing [shared-ptr]: An example allocation using `shared_ptr`] |
| 973 | + |
| 974 | +`make_shared<thing>(1, true)` allocates a new instance of type `thing`, using the constructor |
| 975 | +arguments `(1, true)`. It returns a `shared_ptr<thing>`. This can be simplified as in the second |
| 976 | +line with the `auto` type declaration, because the type is sufficiently defined by the return type |
| 977 | +of `make_shared<thing2>`. |
| 978 | + |
| 979 | +We'll use shared pointers in our code, because it allows multiple objects to use a common object |
| 980 | +(for example, a bunch of spheres that all use the same material), and because it makes memory |
| 981 | +management automatic and easier to reason about. |
| 982 | +</div> |
| 983 | + |
| 984 | +The second C++ feature you may be unfamiliar with is `std::vector`. This is a generic array-like |
| 985 | +collection of an arbitrary type. Above, we use a collection of pointers to `hittable`. `std::vector` |
| 986 | +automatically grows as more values are added: `objects.push_back(object)` adds a value to the end of |
| 987 | +the `std::vector` member variable `objects`. |
| 988 | + |
| 989 | +## Common Constants and Utility Functions |
959 | 990 |
|
960 | 991 | <div class='together'></div>
|
961 | 992 | We need some math constants that we conveniently define in their own header file. For now we only
|
|
1040 | 1071 |
|
1041 | 1072 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1042 | 1073 | 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)); |
| 1074 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5)); |
| 1075 | + world.add(make_shared<sphere>(vec3(0,-100.5,-1), 100)); |
1045 | 1076 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1046 | 1077 |
|
1047 | 1078 | for (int j = ny-1; j >= 0; --j) {
|
|
1218 | 1249 | std::cout << "P3\n" << nx << " " << ny << "\n255\n";
|
1219 | 1250 |
|
1220 | 1251 | 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)); |
| 1252 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5)); |
| 1253 | + world.add(make_shared<sphere>(vec3(0,-100.5,-1), 100)); |
1223 | 1254 |
|
1224 | 1255 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1225 | 1256 | camera cam;
|
|
1650 | 1681 | vec3 p;
|
1651 | 1682 | vec3 normal;
|
1652 | 1683 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1653 |
| - material *mat_ptr; |
| 1684 | + shared_ptr<material> mat_ptr; |
1654 | 1685 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1655 | 1686 | double t;
|
1656 | 1687 | bool front_face;
|
|
1687 | 1718 | class sphere: public hittable {
|
1688 | 1719 | public:
|
1689 | 1720 | sphere() {}
|
1690 |
| - sphere(vec3 cen, double r, material *m) : center(cen), radius(r), mat_ptr(m) {}; |
| 1721 | + |
| 1722 | + sphere(vec3 cen, double r, shared_ptr<material> m) |
| 1723 | + : center(cen), radius(r), mat_ptr(m) {}; |
| 1724 | + |
1691 | 1725 | virtual bool hit(const ray& r, double tmin, double tmax, hit_record& rec) const;
|
| 1726 | + |
| 1727 | + public: |
1692 | 1728 | vec3 center;
|
1693 | 1729 | double radius;
|
1694 | 1730 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1695 |
| - material *mat_ptr; |
| 1731 | + shared_ptr<material> mat_ptr; |
1696 | 1732 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1697 | 1733 | };
|
1698 | 1734 | bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
|
|
1752 | 1788 | return true;
|
1753 | 1789 | }
|
1754 | 1790 |
|
| 1791 | + public: |
1755 | 1792 | vec3 albedo;
|
1756 | 1793 | };
|
1757 | 1794 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
1799 | 1836 | attenuation = albedo;
|
1800 | 1837 | return (dot(scattered.direction(), rec.normal) > 0);
|
1801 | 1838 | }
|
| 1839 | + |
| 1840 | + public: |
1802 | 1841 | vec3 albedo;
|
1803 | 1842 | };
|
1804 | 1843 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
1847 | 1886 |
|
1848 | 1887 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1849 | 1888 | 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)))); |
| 1889 | + |
| 1890 | + world.add(make_shared<sphere>( |
| 1891 | + vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.7, 0.3, 0.3)))); |
| 1892 | + |
| 1893 | + world.add(make_shared<sphere>( |
| 1894 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0)))); |
| 1895 | + |
| 1896 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2)))); |
| 1897 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.8, 0.8)))); |
1854 | 1898 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
1855 | 1899 |
|
1856 | 1900 | camera cam;
|
|
1912 | 1956 | attenuation = albedo;
|
1913 | 1957 | return (dot(scattered.direction(), rec.normal) > 0);
|
1914 | 1958 | }
|
| 1959 | + |
| 1960 | + public: |
1915 | 1961 | vec3 albedo;
|
1916 | 1962 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight
|
1917 | 1963 | double fuzz;
|
|
2134 | 2180 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2135 | 2181 | }
|
2136 | 2182 |
|
| 2183 | + public: |
2137 | 2184 | double ref_idx;
|
2138 | 2185 | };
|
2139 | 2186 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2144 | 2191 | Attenuation is always 1 -- the glass surface absorbs nothing. If we try that out with these parameters:
|
2145 | 2192 |
|
2146 | 2193 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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)); |
| 2194 | + world.add(make_shared<sphere>( |
| 2195 | + vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.1, 0.2, 0.5))); |
| 2196 | + |
| 2197 | + world.add(make_shared<sphere>( |
| 2198 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0))); |
| 2199 | + |
| 2200 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2), 0.0)); |
| 2201 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<dielectric>(1.5)); |
2151 | 2202 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2152 | 2203 | [Listing [scene-dielectric]: <kbd>[main.cc]</kbd> Scene with dielectric sphere]
|
2153 | 2204 |
|
|
2206 | 2257 | return true;
|
2207 | 2258 | }
|
2208 | 2259 |
|
| 2260 | + public: |
2209 | 2261 | double ref_idx;
|
2210 | 2262 | };
|
2211 | 2263 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
2218 | 2270 | to make a hollow glass sphere:
|
2219 | 2271 |
|
2220 | 2272 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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)); |
| 2273 | + world.add(make_shared<sphere>(vec3(0,0,-1), 0.5, make_shared<lambertian>(vec3(0.1, 0.2, 0.5))); |
| 2274 | + world.add(make_shared<sphere>( |
| 2275 | + vec3(0,-100.5,-1), 100, make_shared<lambertian>(vec3(0.8, 0.8, 0.0))); |
| 2276 | + world.add(make_shared<sphere>(vec3(1,0,-1), 0.5, make_shared<metal>(vec3(0.8, 0.6, 0.2), 0.3)); |
| 2277 | + world.add(make_shared<sphere>(vec3(-1,0,-1), 0.5, make_shared<dielectric>(1.5)); |
| 2278 | + world.add(make_shared<sphere>(vec3(-1,0,-1), -0.45, make_shared<dielectric>(1.5)); |
2226 | 2279 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2227 | 2280 | [Listing [scene-hollow-glass]: <kbd>[main.cc]</kbd> Scene with hollow glass sphere]
|
2228 | 2281 | </div>
|
|
2295 | 2348 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++
|
2296 | 2349 | auto R = cos(pi/4);
|
2297 | 2350 | 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)))); |
| 2351 | + world.add(make_shared<sphere>(vec3(-R,0,-1), R, make_shared<lambertian>(vec3(0, 0, 1)))); |
| 2352 | + world.add(make_shared<sphere(>vec3( R,0,-1), R, make_shared<lambertian>(vec3(1, 0, 0)))); |
2300 | 2353 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2301 | 2354 | [Listing [scene-wide-angle]: <kbd>[main.cc]</kbd> Scene with wide-angle camera]
|
2302 | 2355 |
|
|
2536 | 2589 | hittable_list random_scene() {
|
2537 | 2590 | hittable_list objects;
|
2538 | 2591 |
|
2539 |
| - objects.add(new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)))); |
| 2592 | + objects.add(make_shared<sphere>( |
| 2593 | + vec3(0,-1000,0), 1000, make_shared<lambertian>(vec3(0.5, 0.5, 0.5)))); |
2540 | 2594 |
|
2541 | 2595 | int i = 1;
|
2542 | 2596 | for (int a = -11; a < 11; a++) {
|
|
2547 | 2601 | if (choose_mat < 0.8) {
|
2548 | 2602 | // diffuse
|
2549 | 2603 | auto albedo = vec3::random() * vec3::random();
|
2550 |
| - objects.add(new sphere(center, 0.2, new lambertian(albedo))); |
| 2604 | + objects.add( |
| 2605 | + make_shared<sphere>(center, 0.2, make_shared<lambertian>(albedo))); |
2551 | 2606 | } else if (choose_mat < 0.95) {
|
2552 | 2607 | // metal
|
2553 | 2608 | auto albedo = vec3::random(.5, 1);
|
2554 | 2609 | auto fuzz = random_double(0, .5);
|
2555 |
| - objects.add(new sphere(center, 0.2, new metal(albedo, fuzz))); |
| 2610 | + objects.add( |
| 2611 | + make_shared<sphere>(center, 0.2, make_shared<metal>(albedo, fuzz))); |
2556 | 2612 | } else {
|
2557 | 2613 | // glass
|
2558 |
| - objects.add(new sphere(center, 0.2, new dielectric(1.5))); |
| 2614 | + objects.add(make_shared<sphere>(center, 0.2, make_shared<dielectric>(1.5))); |
2559 | 2615 | }
|
2560 | 2616 | }
|
2561 | 2617 | }
|
2562 | 2618 | }
|
2563 | 2619 |
|
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))); |
| 2620 | + objects.add(make_shared<sphere>(vec3(0, 1, 0), 1.0, make_shared<dielectric>(1.5))); |
| 2621 | + |
| 2622 | + objects.add( |
| 2623 | + make_shared<sphere>(vec3(-4, 1, 0), 1.0, make_shared<lambertian>(vec3(0.4, 0.2, 0.1)))); |
| 2624 | + |
| 2625 | + objects.add( |
| 2626 | + make_shared<sphere>(vec3(4, 1, 0), 1.0, make_shared<metal>(vec3(0.7, 0.6, 0.5), 0.0))); |
2567 | 2627 |
|
2568 | 2628 | return objects;
|
2569 | 2629 | }
|
|
0 commit comments