diff --git a/CMakeLists.txt b/CMakeLists.txt index 97377a8d..e4264c2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,9 +15,13 @@ project ( RTWeekend set ( CMAKE_CXX_STANDARD 11 ) # Source -set ( SOURCE_ONE_WEEKEND +set ( COMMON_ALL src/common/rtweekend.h src/common/vec3.h +) + +set ( SOURCE_ONE_WEEKEND + ${COMMON_ALL} src/InOneWeekend/camera.h src/InOneWeekend/hittable.h src/InOneWeekend/hittable_list.h @@ -28,9 +32,8 @@ set ( SOURCE_ONE_WEEKEND ) set ( SOURCE_NEXT_WEEK - src/common/rtweekend.h + ${COMMON_ALL} src/common/rtw_stb_image.h - src/common/vec3.h src/common/external/stb_image.h src/TheNextWeek/aabb.h src/TheNextWeek/aarect.h @@ -51,13 +54,13 @@ set ( SOURCE_NEXT_WEEK ) set ( SOURCE_REST_OF_YOUR_LIFE - src/common/rtweekend.h + ${COMMON_ALL} src/common/rtw_stb_image.h - src/common/vec3.h src/common/external/stb_image.h src/TheRestOfYourLife/aabb.h src/TheRestOfYourLife/aarect.h src/TheRestOfYourLife/box.h + src/TheRestOfYourLife/bucamera.h src/TheRestOfYourLife/bvh.h src/TheRestOfYourLife/camera.h src/TheRestOfYourLife/constant_medium.h @@ -75,12 +78,23 @@ set ( SOURCE_REST_OF_YOUR_LIFE src/TheRestOfYourLife/main.cc ) -set ( COMMON_DIR src ) - +# Executables add_executable(inOneWeekend ${SOURCE_ONE_WEEKEND}) add_executable(theNextWeek ${SOURCE_NEXT_WEEK}) add_executable(theRestOfYourLife ${SOURCE_REST_OF_YOUR_LIFE}) +add_executable(cos_cubed src/TheRestOfYourLife/cos_cubed.cc ${COMMON_ALL}) +add_executable(cos_density src/TheRestOfYourLife/cos_density.cc ${COMMON_ALL}) +add_executable(integrate_x_sq src/TheRestOfYourLife/integrate_x_sq.cc ${COMMON_ALL}) +add_executable(pi src/TheRestOfYourLife/pi.cc ${COMMON_ALL}) +add_executable(sphere_importance src/TheRestOfYourLife/sphere_importance.cc ${COMMON_ALL}) +add_executable(sphere_plot src/TheRestOfYourLife/sphere_plot.cc ${COMMON_ALL}) -target_include_directories(inOneWeekend PRIVATE ${COMMON_DIR}) -target_include_directories(theNextWeek PRIVATE ${COMMON_DIR}) -target_include_directories(theRestOfYourLife PRIVATE ${COMMON_DIR}) +target_include_directories(inOneWeekend PRIVATE src) +target_include_directories(theNextWeek PRIVATE src) +target_include_directories(theRestOfYourLife PRIVATE src) +target_include_directories(cos_cubed PRIVATE src) +target_include_directories(cos_density PRIVATE src) +target_include_directories(integrate_x_sq PRIVATE src) +target_include_directories(pi PRIVATE src) +target_include_directories(sphere_importance PRIVATE src) +target_include_directories(sphere_plot PRIVATE src) diff --git a/books/RayTracingInOneWeekend.html b/books/RayTracingInOneWeekend.html index fddde399..ff6f0b04 100644 --- a/books/RayTracingInOneWeekend.html +++ b/books/RayTracingInOneWeekend.html @@ -88,6 +88,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-initial]: [main.cc] Creating your first image] There are some things to note in that code: @@ -137,6 +138,7 @@ 14 253 51 15 253 51 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [first-img]: First image output] If it doesn’t, then you probably just have some newlines or something similar that is confusing the @@ -212,6 +214,7 @@ double e[3]; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [vec3-class]: [vec3.h] `vec3` class] We use `double` here, but some ray tracers use `float`. Either one is fine -- follow your own @@ -264,6 +267,7 @@ return v / v.length(); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [vec3-utility]: [vec3.h] vec3 utility functions]
Now we can change our main to use this: @@ -289,6 +293,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-gradient]: [main.cc] Creating a color gradient image]
@@ -315,13 +320,12 @@ #include "common/vec3.h" - class ray - { + class ray { public: ray() {} ray(const vec3& a, const vec3& b) { A = a; B = b; } - vec3 origin() const { return A; } - vec3 direction() const { return B; } + vec3 origin() const { return A; } + vec3 direction() const { return B; } vec3 point_at_parameter(double t) const { return A + t*B; } vec3 A; @@ -330,6 +334,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-initial]: [main.cc] The ray class] Now we are ready to turn the corner and make a ray tracer. At the core of a ray tracer is to send @@ -387,6 +392,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-blue-white-blend]: [main.cc] Rendering a blue-to-white gradient]
@@ -496,6 +502,7 @@ return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-red-sphere]: [main.cc] Rendering a red sphere]
@@ -569,6 +576,7 @@ return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [render-surface-normal]: [main.cc] Rendering surface normals on a sphere]
@@ -586,6 +594,7 @@ auto c = dot(oc, oc) - radius*radius; auto discriminant = b*b - 4*a*c; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-sphere-before]: [main.cc] Ray-sphere intersection code (before)] First, recall that a vector dotted with itself is equal to the squared length of that vector. @@ -616,6 +625,7 @@ return (-half_b - sqrt(discriminant) ) / a; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-sphere-after]: [main.cc] Ray-sphere intersection code (after)] Now, how about several spheres? While it is tempting to have an array of spheres, a very clean @@ -647,7 +657,7 @@ vec3 normal; }; - class hittable { + class hittable { public: virtual bool hit( const ray& r, double t_min, double t_max, hit_record& rec) const = 0; @@ -655,6 +665,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-initial]: [hittable.h] The hittable class]
@@ -667,10 +678,10 @@ #include "common/vec3.h" #include "hittable.h" - class sphere: public hittable { + class sphere: public hittable { public: sphere() {} - sphere(vec3 cen, double r) : center(cen), radius(r) {}; + sphere(vec3 cen, double r) : center(cen), radius(r) {}; virtual bool hit( const ray& r, double tmin, double tmax, hit_record& rec) const; vec3 center; @@ -707,6 +718,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sphere-initial]: [sphere.h] The sphere class]
@@ -747,6 +759,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-list-initial]: [hittable_list.h] The hittable_list class]
@@ -785,7 +798,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - + [Listing [rtweekend-initial]: [common/rtweekend.h] The rtweekend.h common header]
@@ -851,6 +864,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-with-rtweekend-h]: [main.cc] desc]
@@ -890,7 +904,7 @@ return rand() / (RAND_MAX + 1.0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - + [Listing [random-double]: [rtweekend.h] random_double() function]
@@ -910,6 +924,7 @@ return rand_generator(); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [random-double-alt]: [file] random_double(), alternate implemenation]
@@ -951,6 +966,7 @@ }; #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [camera-initial]: [camera.h] The camera class]
To handle the multi-sampled color computation, we update the `vec3::write_color()` function. Rather @@ -966,6 +982,7 @@ return x; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [clamp]: [rtweekend.h] The clamp() utility function] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ void write_color(std::ostream &out, int num_samples) { @@ -981,6 +998,7 @@ << static_cast(256.0 * clamp(b, 0.0, 0.999999)) << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [write-color-clamped]: [vec3.h] The write_color() function]
Main is also changed: @@ -1018,6 +1036,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-multi-sample]: [main.cc] Rendering with multi-sampled pixels]
@@ -1079,6 +1098,7 @@ return vec3(r * cos(a), r * sin(a), z); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [random-unit-vec]: [material.h] The random_unit_vector() function]
@@ -1100,6 +1120,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-random-unit]: [main.cc] ray_color() using a random ray direction]
@@ -1136,6 +1157,7 @@ << static_cast(256.0 * clamp(b, 0.0, 0.999999)) << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [write-color-gamma]: [vec3.h] write_color(), with gamma correction]
@@ -1154,6 +1176,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ if (world->hit(r, 0.001, infinity, rec)) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [reflect-tolerance]: [main.cc] Calculating reflected ray origins with tolerance] This gets rid of the shadow acne problem. Yes it is really called that. @@ -1176,13 +1199,14 @@ This suggests the abstract class: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class material { + class material { public: virtual bool scatter( const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const = 0; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [material-initial]: [material.h] The material class]
@@ -1198,13 +1222,17 @@ #include "common/rtweekend.h" #include "ray.h" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight class material; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ struct hit_record { double t; vec3 p; vec3 normal; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight material *mat_ptr; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; class hittable { @@ -1215,6 +1243,7 @@ #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hit-with-material]: [hittable.h] Hit record with added material pointer]
What we have set up here is that material will tell us how rays interact with the surface. @@ -1229,11 +1258,11 @@ within `hit_record`. See the highlighted lines below: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class sphere: public hittable { + class sphere: public hittable { public: sphere() {} sphere(vec3 cen, double r, material *m) - : center(cen), radius(r), mat_ptr(m) {}; + : center(cen), radius(r), mat_ptr(m) {}; virtual bool hit( const ray& r, double tmin, double tmax, hit_record& rec) const; vec3 center; @@ -1276,6 +1305,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sphere-material]: [sphere.h] Ray-sphere intersection with added material information]
@@ -1299,6 +1329,7 @@ vec3 albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lambertian-initial]: [material.h] The lambertian material class]
Note we could just as well only scatter with some probability $p$ and have attenuation be @@ -1323,6 +1354,7 @@ return v - 2*dot(v,n)*n; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [vec3-reflect]: [material.h] vec3 reflection function]
@@ -1342,6 +1374,7 @@ vec3 albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [metal-material]: [material.h] Metal material with reflectance function]
@@ -1369,6 +1402,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-scatter]: [main.cc] Ray color with scattered reflectance]
@@ -1407,6 +1441,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-with-metal]: [main.cc] Scene with metal spheres]
@@ -1464,6 +1499,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [metal-fuzz]: [main.cc] Metal spheres with fuzziness] In order to generate a random point inside a unit sphere (`random_in_unit_sphere()`), we used one of the easiest algorithms: a rejection method. First, pick a random point in the unit cube where x, y, @@ -1532,6 +1568,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [refract]: [material.h] Refraction function]
@@ -1572,6 +1609,7 @@ double ref_idx; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [dielectric]: [material.h] Dielectric material class]
Attenuation is always 1 -- the glass surface absorbs nothing. The `attenuation = vec3(1.0, 1.0, @@ -1588,6 +1626,7 @@ list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2), 0.0)); list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-dielectric]: [main.cc] Scene with dielectric sphere] We get: @@ -1613,6 +1652,7 @@ return r0 + (1-r0)*pow((1 - cosine),5); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [schlick]: [material.h] Schlick approximation]
@@ -1675,6 +1715,7 @@ double ref_idx; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [glass]: [material.h] Full glass material]
@@ -1689,6 +1730,7 @@ list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5)); list[4] = new sphere(vec3(-1,0,-1), -0.45, new dielectric(1.5)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-hollow-glass]: [main.cc] Scene with hollow glass sphere]
@@ -1721,14 +1763,9 @@ This implies $h = \tan(\frac{\theta}{2})$. Our camera now becomes: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #ifndef CAMERA_H - #define CAMERA_H - - #include "common/rtweekend.h" - #include "ray.h" - class camera { public: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight camera( double vfov, // vfov is top to bottom in degrees double aspect @@ -1741,6 +1778,7 @@ vertical = vec3(0.0, 2*half_height, 0.0); origin = vec3(0.0, 0.0, 0.0); } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ ray get_ray(double u, double v) { return ray(origin, @@ -1752,8 +1790,8 @@ vec3 horizontal; vec3 vertical; }; - #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [camera-fov]: [camera.h] Camera with adjustable field-of-view (fov)]
@@ -1765,6 +1803,7 @@ list[1] = new sphere(vec3( R,0,-1), R, new lambertian(vec3(1, 0, 0))); hittable *world = new hittable_list(list,2); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-wide-angle]: [main.cc] Scene with wide-angle camera] gives: @@ -1796,22 +1835,16 @@ camera horizontally level until you decide to experiment with crazy camera angles. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #ifndef CAMERA_H - #define CAMERA_H - - #include "common/rtweekend.h" - #include "ray.h" - class camera { public: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight camera( + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight vec3 lookfrom, vec3 lookat, vec3 vup, + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ double vfov, // vfov is top to bottom in degrees double aspect ) { vec3 u, v, w; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ auto theta = degrees_to_radians(vfov); auto half_height = tan(theta/2); auto half_width = aspect * half_height; @@ -1836,8 +1869,8 @@ vec3 horizontal; vec3 vertical; }; - #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [camera-orient]: [camera.h] Positionable and orientable camera]
This allows us to change the viewpoint: @@ -1845,6 +1878,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ camera cam(vec3(-2,2,1), vec3(0,0,-1), vec3(0,1,0), 90, double(nx)/ny); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-free-view]: [main.cc] Scene with alternate viewpoint] to get: @@ -1893,12 +1927,6 @@ point: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #ifndef CAMERA_H - #define CAMERA_H - - #include "common/rtweekend.h" - #include "ray.h" - vec3 random_in_unit_disk() { vec3 p; do { @@ -1909,10 +1937,10 @@ class camera { public: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight camera( vec3 lookfrom, vec3 lookat, vec3 vup, double vfov, // vfov is top to bottom in degrees + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight double aspect, double aperture, double focus_dist ) { lens_radius = aperture / 2; @@ -1953,8 +1981,8 @@ double lens_radius; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; - #endif ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [camera-dof]: [camera.h] Camera with adjustable depth-of-field (dof)]
@@ -1968,6 +1996,7 @@ camera cam(lookfrom, lookat, vec3(0,1,0), 20, double(nx)/ny, aperture, dist_to_focus); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-camera-dof]: [main.cc] Scene camera with depth-of-field] We get: @@ -2023,6 +2052,7 @@ return new hittable_list(list,i); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-final]: [main.cc] Final scene]
diff --git a/books/RayTracingTheNextWeek.html b/books/RayTracingTheNextWeek.html index 34115769..07655de0 100644 --- a/books/RayTracingTheNextWeek.html +++ b/books/RayTracingTheNextWeek.html @@ -62,8 +62,7 @@ For this we will first need to have a ray store the time it exists at: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class ray - { + class ray { public: ray() {} ray(const vec3& a, const vec3& b, double ti = 0.0) { @@ -82,6 +81,7 @@ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [time-ray]: [ray.h] Ray with time information]
Now we need to modify the camera to generate rays at a random time between `time1` and `time2`. @@ -143,6 +143,7 @@ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [time-camera]: [camera.h] Camera with time information] We also need a moving object. I’ll create a sphere class that has its center move linearly from `center0` at `time0` to `center1` at `time1`. Outside that time interval it continues on, so those @@ -170,6 +171,7 @@ return center0 + ((time - time0) / (time1 - time0))*(center1 - center0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [moving-sphere]: [moving_sphere.h] A moving sphere]
An alternative to making a new moving sphere class is to just make them all move and have the @@ -215,6 +217,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [moving-sphere-hit]: [moving-sphere.h] Moving sphere hit function]
@@ -239,6 +242,7 @@ vec3 albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lambertian-animate]: [material.h] Lambertian matrial for moving objects]
@@ -295,10 +299,12 @@ return new hittable_list(list,i); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-spheres-moving]: + [main.cc] Last book's final scene, but with moving spheres]
-And with these viewing parameters gives: +And with these viewing parameters: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ vec3 lookfrom(13,2,3); @@ -311,6 +317,9 @@ dist_to_focus, 0.0, 1.0 ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-spheres-moving-camera]: [main.cc] Viewing parameters] + +gives the following result: ![Image 2-1](../images/img-2-2-01.jpg) @@ -547,6 +556,7 @@ vec3 _max; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [aabb]: [aabb.h] Axis-aligned bounding box class]
@@ -571,6 +581,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [aabb-hit]: [aabb.h] Axis-aligned bounding box hit function]
@@ -588,6 +599,7 @@ virtual bool bounding_box(double t0, double t1, aabb& box) const = 0; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-bbox]: [hittable.h] Hittable class with bounding-box]
@@ -600,6 +612,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sphere-bbox]: [sphere.h] Sphere with bounding box]
@@ -616,6 +629,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [moving-sphere-bbox]: [moving_sphere.h] Moving sphere with bounding box]
@@ -641,6 +655,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hit-list-bbox]: [hittable_list.h] Hittable list with bounding box]
@@ -658,6 +673,7 @@ return aabb(small,big); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [surrounding-box]: [aabb.h] Surrounding bounding box]
@@ -687,6 +703,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [bvh]: [bvh.h] Bounding volume hierarchy]
Note that the children pointers are to generic hittables. They can be other `bvh_nodes`, or @@ -723,6 +740,7 @@ else return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [bvh-hit]: [bvh.h] Bounding volume hierarchy hit function]
@@ -785,6 +803,7 @@ box = surrounding_box(box_left, box_right); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [bvh-node]: [bvh.h] Bounding volume hierarchy node]
The check for whether there is a bounding box at all is in case you sent in something like an @@ -810,6 +829,7 @@ return 1; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [bvh-x-comp]: [bvh.h] BVH comparison function, X-axis] @@ -838,6 +858,7 @@ vec3 color; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [texture]: [texture.h] A texture class]
Now we can make textured materials by replacing the vec3 color with a texture pointer: @@ -845,20 +866,27 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ class lambertian : public material { public: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight lambertian(texture *a) : albedo(a) {} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ virtual bool scatter( const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered ) const { vec3 target = rec.p + rec.normal + random_unit_vector(); scattered = ray(rec.p, target - rec.p); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight attenuation = albedo->value(0, 0, rec.p); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ return true; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight texture *albedo; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lambertian-textured]: [material.h] Lambertian material with texture]
@@ -867,12 +895,14 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ new lambertian(vec3(0.5, 0.5, 0.5))) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lam-solid]: [main.cc] Lambertian material with solid color] now you should replace the `vec3(...)` with `new constant_texture(vec3(...))` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ new lambertian(new constant_texture(vec3(0.5, 0.5, 0.5)))) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lam-textured]: [main.cc] Lambertian material with texture]
@@ -896,6 +926,7 @@ texture *even; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [checker-texture]: [texture.h] Checkered texture]
Those checker odd/even pointers can be to a constant texture or to some other procedural texture. @@ -911,6 +942,7 @@ ); list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(checker)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [checker-example]: [main.cc] Checkered texture in use] We get: @@ -934,6 +966,7 @@ return new hittable_list(list,2); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-two-checker]: [main.cc] Scene with two checkered spheres] With camera: @@ -946,6 +979,7 @@ camera cam(lookfrom, lookat, vec3(0,1,0), 20, double(nx)/ny, aperture, dist_to_focus, 0.0, 1.0); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-two-checker-view]: [main.cc] Viewing parameters] We get: @@ -1035,6 +1069,7 @@ int *perlin::perm_y = perlin_generate_perm(); int *perlin::perm_z = perlin_generate_perm(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin]: [perlin.h] A Perlin texture class and functions]
@@ -1051,6 +1086,7 @@ perlin noise; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [noise-texture]: [texture.h] Noise texture]
@@ -1065,6 +1101,7 @@ return new hittable_list(list, 2); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-perlin]: [main.cc] Scene with two Perlin-textured spheres]
@@ -1078,6 +1115,7 @@ camera cam(lookfrom, lookat, vec3(0,1,0), 20, double(nx)/ny, aperture, dist_to_focus, 0.0, 1.0); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-perlin-view]: [main.cc] Viewing parameters]
@@ -1128,6 +1166,7 @@ static int *perm_z; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-trilinear]: [perlin.h] Perlin with trilienear interpolation]
@@ -1161,6 +1200,7 @@ int k = floor(p.z()); ... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-smoothed]: [perlin.h] Perlin smoothed]
@@ -1189,6 +1229,7 @@ double scale; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-smoothed-2]: [perlin.h] Perlin smoothed, higher frequency] which gives: @@ -1208,6 +1249,7 @@ int *perlin::perm_y = perlin_generate_perm(); int *perlin::perm_z = perlin_generate_perm(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-randunit]: [perlin.h] Perlin with random unit translations]
@@ -1226,6 +1268,7 @@ return p; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-gen-2]: [perlin.h] New perlin_generate()]
@@ -1258,6 +1301,7 @@ static int *perm_z; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-2]: [perlin.h] The perlin class so far]
@@ -1280,6 +1324,7 @@ return accum; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-interp]: [perlin.h] Perlin interpolation function so far]
@@ -1306,6 +1351,7 @@ return fabs(accum); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [perlin-turb]: [perlin.h] Turbulence function]
Here `fabs()` is the `math.h` absolute value function. @@ -1340,6 +1386,7 @@ double scale; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [noise-tex-2]: [texture.h] Noise texture with turbulence] Which yields: @@ -1411,6 +1458,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ get_sphere_uv((rec.p-center)/radius, rec.u, rec.v); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [get-sphere-uv-call]: [sphere.h] Sphere UV coordinates from hit]
@@ -1424,6 +1472,7 @@ v = (theta + pi/2) / pi; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [get-sphere-uv]: [sphere.h] get_sphere_uv function]
Now we also need to create a texture class that holds an image. I am going to use my favorite image @@ -1454,6 +1503,7 @@ return vec3(r, g, b); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [img-texture]: [surface_texture.h] Image texture class]
The representation of a packed array in that order is pretty standard. Thankfully, the `stb_image` @@ -1462,6 +1512,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ #include "common/rtw_stb_image.h" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [incl-stb-img]: Including the STB image package]
@@ -1477,6 +1528,7 @@ unsigned char *tex_data = stbi_load("earthmap.jpg", &nx, &ny, &nn, 0); material *mat = new lambertian(new image_texture(tex_data, nx, ny)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [stbi-load-use]: [main.cc] Using stbi_load() to load an image]
We start to see some of the power of all colors being textures -- we can assign any kind of texture @@ -1497,8 +1549,8 @@
First, let’s make a light emitting material. We need to add an emitted function (we could also add -it to hit_record instead -- that’s a matter of design taste). Like the background, it just tells the -ray what color it is and performs no reflection. It’s very simple: +it to `hit_record instead` -- that’s a matter of design taste). Like the background, it just tells +the ray what color it is and performs no reflection. It’s very simple: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ class diffuse_light : public material { @@ -1512,6 +1564,7 @@ texture *emit; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [diffuse-light]: [material.h] A diffuse light class]
@@ -1523,11 +1576,14 @@ public: virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const = 0; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight virtual vec3 emitted(double u, double v, const vec3& p) const { return vec3(0,0,0); } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [matl-emit]: [material.h] New emitted function in class material]
@@ -1539,6 +1595,7 @@ if (world->hit(r, 0.001, infinity, rec)) { ray scattered; vec3 attenuation; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight vec3 emitted = rec.mat_ptr->emitted(rec.u, rec.v, rec.p); if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) return emitted + attenuation * ray_color(scattered, world, depth+1); @@ -1547,8 +1604,10 @@ } else return vec3(0,0,0); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-emitted]: [main.cc] ray_color function for emitting materials]
Now, let’s make some rectangles. Rectangles are often convenient for modelling man-made @@ -1601,6 +1660,7 @@ double x0, x1, y0, y1, k; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [xy-rect]: [aarect.h] XY-plane rectangle objects]
@@ -1624,6 +1684,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [xy-rect-hit]: [aarect.h] Hit function for XY rectangle objects]
@@ -1642,6 +1703,7 @@ return new hittable_list(list,4); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rect-light]: [main.cc] A simple rectangle light]
@@ -1698,6 +1760,7 @@ double y0, y1, z0, z1, k; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [xz-yz-rects]: [aarect.h] XZ and YZ rectangle objects]
@@ -1738,6 +1801,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [xz-yz]: [aarect.h] XZ and YZ rectangle object hit functions]
@@ -1761,6 +1825,7 @@ return new hittable_list(list,i); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cornell-box-empty]: [main.cc] Cornell box scene, empty]
@@ -1776,6 +1841,7 @@ camera cam(lookfrom, lookat, vec3(0,1,0), vfov, double(nx)/ny, aperture, dist_to_focus, 0.0, 1.0); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cornell-box-view]: [main.cc] Viewing parameters]
@@ -1813,6 +1879,7 @@ hittable *ptr; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [flip-normals]: [hittable.h] Flip-normals function]
@@ -1827,16 +1894,23 @@ material *green = new lambertian(new constant_texture(vec3(0.12, 0.45, 0.15))); material *light = new diffuse_light(new constant_texture(vec3(15, 15, 15))); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ list[i++] = new yz_rect(0, 555, 0, 555, 0, red); list[i++] = new xz_rect(213, 343, 227, 332, 554, light); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight list[i++] = new flip_normals(new xz_rect(0, 555, 0, 555, 555, white)); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ list[i++] = new xz_rect(0, 555, 0, 555, 0, white); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight list[i++] = new flip_normals(new xy_rect(0, 555, 0, 555, 555, white)); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ return new hittable_list(list,i); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cornell-box-flipped]: [main.cc] Empty Cornell box with flipped rectangles]
@@ -1888,6 +1962,7 @@ return list_ptr->hit(r, t0, t1, rec); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [box-class]: [box.h] A box object]
Now we can add two blocks (but not rotated) @@ -1896,6 +1971,7 @@ list[i++] = new box(vec3(130, 0, 65), vec3(295, 165, 230), white); list[i++] = new box(vec3(265, 0, 295), vec3(430, 330, 460), white); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [add-boxes]: [main.cc] Adding box objects]
@@ -1954,6 +2030,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [translate-class]: [hittable.h] Hittable translation class]
@@ -2016,6 +2093,7 @@ aabb bbox; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rot-y]: [hittable.h] Hittable rotate-Y class]
@@ -2038,8 +2116,7 @@ auto newx = cos_theta*x + sin_theta*z; auto newz = -sin_theta*x + cos_theta*z; vec3 tester(newx, y, newz); - for (int c = 0; c < 3; c++) - { + for (int c = 0; c < 3; c++) { if (tester[c] > max[c]) max[c] = tester[c]; if (tester[c] < min[c]) @@ -2051,6 +2128,7 @@ bbox = aabb(min, max); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rot-y-rot]: [hittable.h] Rotate-Y rotate method]
@@ -2080,6 +2158,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rot-y-hit]: [hittable.h] Hittable Y-rotate hit function]
@@ -2095,6 +2174,7 @@ vec3(265,0,295) ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-rot-y]: [main.cc] Cornell scene with Y-rotated boxes]
@@ -2153,6 +2233,7 @@ material *phase_function; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [const-med-class]: [constant_medium.h] Constant medium class]
@@ -2175,6 +2256,7 @@ texture *albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [isotropic-class]: [material.h] The isotropic class]
@@ -2230,6 +2312,7 @@ return false; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [const-med-hit]: [constant_medium.h] Constant medium hit method]
The reason we have to be so careful about the logic around the boundary is we need to make sure this @@ -2271,6 +2354,7 @@ return new hittable_list(list,i); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cornell-smoke]: [main.cc] Cornell box, with smoke]
@@ -2345,6 +2429,7 @@ return new hittable_list(list,l); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-final]: [main.cc] Final scene]
Running it with 10,000 rays per pixel yields: diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html index 2694149e..fd9c65fe 100644 --- a/books/RayTracingTheRestOfYourLife.html +++ b/books/RayTracingTheRestOfYourLife.html @@ -87,9 +87,10 @@ if(x*x + y*y < 1) inside_circle++; } - std::cout << "Estimate of Pi = " << 4*double(inside_circle) / N << "\n"; + std::cout << "Estimate of Pi = " << 4*double(inside_circle) / N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [estpi-1]: [pi.cc] Estimating π]
This gives me the answer `Estimate of Pi = 3.196` @@ -122,6 +123,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [estpi-2]: [pi.cc] Estimating π, v2]
@@ -159,12 +161,16 @@ inside_circle_stratified++; } } - std::cout << "Regular Estimate of Pi = " << - 4*double(inside_circle) / (sqrt_N*sqrt_N) << "\n"; - std::cout << "Stratified Estimate of Pi = " << - 4*double(inside_circle_stratified) / (sqrt_N*sqrt_N) << "\n"; + + auto N = static_cast(sqrt_N) * sqrt_N; + std::cout + << "Regular Estimate of Pi = " + << 4*double(inside_circle) / (sqrt_N*sqrt_N) << '\n' + << "Stratified Estimate of Pi = " + << 4*double(inside_circle_stratified) / (sqrt_N*sqrt_N) << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [estpi-3]: [pi.cc] Estimating π, v3] I get: @@ -207,6 +213,12 @@ This suggests a MC approach: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + #include "common/rtweekend.h" + + #include + #include + #include + int main() { int inside_circle = 0; int inside_circle_stratified = 0; @@ -219,6 +231,7 @@ std::cout << "I =" << 2*sum/N << "\n"; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [integ-xsq-1]: [integrate_x_sq.cc] Integrating $x^2$]
This, as expected, produces approximately the exact answer we get with algebra, $I = 8/3$. But we @@ -381,29 +394,27 @@ down-weight. The _pdf_ is a perfect measure of how much or little sampling is being done. So the weighting function should be proportional to $1/pdf$ . In fact it is exactly $1/pdf$ : - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #include "common/rtweekend.h" - - #include - #include - #include - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight inline double pdf(double x) { return 0.5*x; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ int main() { int inside_circle = 0; int inside_circle_stratified = 0; int N = 1000000; - double sum; + auto sum = 0.0; for (int i = 0; i < N; i++) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight auto x = sqrt(4*random_double()); sum += x*x / pdf(x); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ } - std::cout << "I =" << sum/N << "\n"; + std::cout << "I = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [integ-xsq-2]: [integrate_x_sq.cc] Integrating $x^2$ with _pdf_] Since we are sampling more where the integrand is big, we might expect less noise and thus faster @@ -414,30 +425,27 @@ If we take that same code with uniform samples so the pdf = $1/2$ over the range [0,2] we can use the machinery to get `x = 2*random_double()` and the code is: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #include "common/rtweekend.h" - #include "random.h" - - #include - #include - #include - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight inline double pdf(double x) { return 0.5; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ int main() { int inside_circle = 0; int inside_circle_stratified = 0; int N = 1000000; - double sum; + auto sum = 0.0; for (int i = 0; i < N; i++) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight auto x = 2*random_double(); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ sum += x*x / pdf(x); } - std::cout << "I =" << sum/N << "\n"; + std::cout << "I = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [integ-xsq-3]: [integrate_x_sq.cc] Integrating $x^2$, v3]
@@ -461,29 +469,29 @@ integrating $p$ analytically), but it’s a good exercise to make sure our code works. For just 1 sample we get: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - #include "common/rtweekend.h" - - #include - #include - #include - + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight inline double pdf(double x) { return 3*x*x/8; } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ int main() { int inside_circle = 0; int inside_circle_stratified = 0; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight int N = 1; - double sum; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + auto sum = 0.0; for (int i = 0; i < N; i++) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight auto x = pow(8*random_double(), 1./3.); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ sum += x*x / pdf(x); } - std::cout << "I =" << sum/N << "\n"; + std::cout << "I = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [integ-xsq-4]: [integrate_x_sq.cc] Integrating $x^2$, final version]
Which always returns the exact answer. @@ -504,7 +512,7 @@ ==================================================================================================== In our ray tracer we pick random directions, and directions can be represented as points on the -unit-sphere. The same methodology as before applies. But now we need to have a pdf defined over 2D. +unit sphere. The same methodology as before applies, but now we need to have a pdf defined over 2D. Suppose we have this integral over all directions: $$ \int cos^2(\theta) $$ @@ -520,11 +528,12 @@ vec3 random_in_unit_sphere() { vec3 p; do { - p = 2.0*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); - } while (dot(p,p) >= 1.0); + p = 2*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); + } while (p.squared_length() >= 1); return p; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rand-unit-sphere]: [pdf.h] Random point in unit sphere]
@@ -533,12 +542,16 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ vec3 random_on_unit_sphere() { vec3 p; + double len_squared; do { - p = 2.0*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); - } while (dot(p,p) >= 1.0); - return unit_vector(p); + p = 2*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); + len_squared = p.squared_length(); + } while (len_squared >= 1); + return p / sqrt(len_squared); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rand-on-sphere]: [sphere_importance.cc] + Random point on the surface of the unit sphere, importance sampled]
@@ -553,15 +566,17 @@ int main() { int N = 1000000; - double sum; + auto sum = 0.0; for (int i = 0; i < N; i++) { - vec3 d = random_on_unit_sphere(); - auto cosine_squared = d.z()*d.z(); - sum += cosine_squared / pdf(d); + vec3 d = random_on_unit_sphere(); + auto cosine_squared = d.z()*d.z(); + sum += cosine_squared / pdf(d); } - std::cout << "I =" << sum/N << "\n"; + std::cout << "I = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [main-sphereimp]: [sphere_importance.cc] + Generating importance-sampled points on the unit sphere]
The analytic answer (if you remember enough advanced calc, check me!) is $\frac{4}{3} \pi$, and the @@ -702,12 +717,13 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ void cornell_box(hittable **scene, camera **cam, double aspect) { - int i = 0; - hittable **list = new hittable*[8]; material *red = new lambertian( new constant_texture(vec3(0.65, 0.05, 0.05)) ); material *white = new lambertian( new constant_texture(vec3(0.73, 0.73, 0.73)) ); material *green = new lambertian( new constant_texture(vec3(0.12, 0.45, 0.15)) ); material *light = new diffuse_light( new constant_texture(vec3(15, 15, 15)) ); + + hittable **list = new hittable*[8]; + int i = 0; list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)); list[i++] = new yz_rect(0, 555, 0, 555, 0, red); list[i++] = new xz_rect(213, 343, 227, 332, 554, light); @@ -719,6 +735,7 @@ list[i++] = new translate(new rotate_y( new box(vec3(0, 0, 0), vec3(165, 330, 165), white), 15), vec3(265,0,295)); *scene = new hittable_list(list,i); + vec3 lookfrom(278, 278, -800); vec3 lookat(278, 278, 0); auto dist_to_focus = 10.0; @@ -728,10 +745,11 @@ vfov, aspect, aperture, dist_to_focus, 0.0, 1.0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cornell-box]: [main.cc] Cornell box, refactored]
-At 500x500 my code produces this image in 10min on 1 core of my Macbook: +At 500×500 my code produces this image in 10min on 1 core of my Macbook: ![Figure 6-1](../images/img-3-06-1.jpg) @@ -744,10 +762,10 @@ let’s sample like we do now: $p(direction) = \cos(\theta) / \pi$.
-We modify the base-class _material_ to enable this importance sampling: +We modify the base-class `material` to enable this importance sampling: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class material { + class material { public: virtual bool scatter( @@ -768,6 +786,8 @@ } }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-material]: [material.h] + The material class, adding importance sampling]
@@ -798,6 +818,8 @@ texture *albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-lambertian-impsample]: [material.h] + Lambertian material, modified for importance sampling]
@@ -824,6 +846,8 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-impsample]: [main.cc] + The ray_color function, modified for importance sampling]
You should get exactly the same picture. @@ -845,6 +869,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scatter-mod]: [material.h] Modified scatter function]
@@ -945,11 +970,11 @@ auto x = cos(2*pi*r1)*2*sqrt(r2*(1-r2)); auto y = sin(2*pi*r1)*2*sqrt(r2*(1-r2)); auto z = 1 - 2*r2; - - std::cout << x << " " << y << " " << z << "\n"; + std::cout << x << " " << y << " " << z << '\n'; } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rand-unit-sphere-plot]: [sphere_plot.cc] Random points on the unit sphere]
@@ -993,10 +1018,11 @@ auto z = 1 - r2; sum += z*z*z / (1.0/(2.0*pi)); } - std::cout << "PI/2 = " << pi/2 << "\n"; - std::cout << "Estimate = " << sum/N << "\n"; + std::cout << "PI/2 = " << pi/2 << '\n'; + std::cout << "Estimate = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cos-cubed]: [cos_cubed.cc] Integration using $cos^3(x)$]
@@ -1019,6 +1045,11 @@ Let’s also start generating them as random vectors: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + #include "common/rtweekend.h" + + #include + #include + inline vec3 random_cosine_direction() { auto r1 = random_double(); auto r2 = random_double(); @@ -1036,10 +1067,11 @@ vec3 v = random_cosine_direction(); sum += v.z()*v.z()*v.z() / (v.z()/(pi)); } - std::cout << "PI/2 = " << pi/2 << "\n"; - std::cout << "Estimate = " << sum/N << "\n"; + std::cout << "PI/2 = " << pi/2 << '\n'; + std::cout << "Estimate = " << sum/N << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [cos-density]: [cos_density.cc] Integration with cosine density function]
We can generate other densities later as we need them. In the next chapter we’ll get them aligned to @@ -1126,14 +1158,13 @@ utility functions: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class onb - { + class onb { public: onb() {} inline vec3 operator[](int i) const { return axis[i]; } - vec3 u() const { return axis[0]; } - vec3 v() const { return axis[1]; } - vec3 w() const { return axis[2]; } + vec3 u() const { return axis[0]; } + vec3 v() const { return axis[1]; } + vec3 w() const { return axis[2]; } vec3 local(double a, double b, double c) const { return a*u() + b*v() + c*w(); } vec3 local(const vec3& a) const { return a.x()*u() + a.y()*v() + a.z()*w(); } void build_from_w(const vec3&); @@ -1152,6 +1183,7 @@ axis[0] = cross(w(), v()); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-onb]: [onb.h] Ortho-normal basis class]
@@ -1170,6 +1202,7 @@ return true; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scatter-onb]: [material.h] Scatter function, with ortho-normal basis]
@@ -1262,6 +1295,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-lights]: [main.cc] Ray color with light sampling]
@@ -1287,6 +1321,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [emitted-directional]: [material.h] Material emission, directional]
@@ -1343,12 +1378,13 @@ minimal interface works, and for the _pdf_ this implies: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class pdf { + class pdf { public: virtual double value(const vec3& direction) const = 0; virtual vec3 generate() const = 0; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-pdf]: [pdf.h] The PDF class]
We’ll see if that works by fleshing out the subclasses. For sampling the light, we will need @@ -1370,12 +1406,13 @@ else return 0; } - virtual vec3 generate() const { + virtual vec3 generate() const { return uvw.local(random_cosine_direction()); } onb uvw; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-cos-pdf]: [pdf.h] The cosine_pdf class]
@@ -1409,6 +1446,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-cos-pdf]: [main.cc] The ray_color function, using cosine pdf]
This yields an apparently matching result so all we’ve done so far is refactor where `pdf` is @@ -1436,6 +1474,7 @@ hittable *ptr; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-hittable-pdf]: [pdf.h] The hittable_pdf class]
@@ -1444,22 +1483,25 @@ class: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class hittable { + class hittable { public: - virtual bool hit(const ray& r, double t_min, double t_max, - hit_record& rec) const = 0; + virtual bool hit( + const ray& r, double t_min, double t_max, hit_record& rec) const = 0; virtual bool bounding_box(double t0, double t1, aabb& box) const = 0; - virtual double pdf_value(const vec3& o, const vec3& v) const {return 0.0;} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + virtual double pdf_value(const vec3& o, const vec3& v) const {return 0.0;} virtual vec3 random(const vec3& o) const {return vec3(1, 0, 0);} + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [hittable-plus2]: [hittable.h] The hittable class, with two new methods]
And we change `xz_rect` to implement those functions: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class xz_rect: public hittable { + class xz_rect: public hittable { public: xz_rect() {} xz_rect( @@ -1493,6 +1535,7 @@ double x0, x1, z0, z1, k; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [xz-rect-pdf]: [aarect.h] XZ rect with pdf]
@@ -1526,6 +1569,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-hittable-pdf]: [main.cc] ray_color function with hittable pdf]
@@ -1555,6 +1599,7 @@ pdf *p[2]; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [class-mixturepdf]: [pdf.h] The mixture_pdf class]
@@ -1590,6 +1635,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-mixture]: [main.cc] The ray_color function, using mixture pdf]
@@ -1673,19 +1719,21 @@ We can redesign `material` and stuff all the new arguments into a `struct` like we did for `hittable`: - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - struct scatter_record - { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight + struct scatter_record { ray specular_ray; bool is_specular; vec3 attenuation; pdf *pdf_ptr; }; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - class material { + class material { public: virtual bool scatter( + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight const ray& r_in, const hit_record& hrec, scatter_record& srec + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ ) const { return false; } @@ -1697,12 +1745,15 @@ } virtual vec3 emitted( + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight const ray& r_in, const hit_record& rec, double u, double v, const vec3& p + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ ) const { return vec3(0,0,0); } }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [material-refactor]: [material.h] Refactoring the material class]
@@ -1725,8 +1776,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - bool scatter(const ray& r_in, const hit_record& hrec, - scatter_record& srec) const { + bool scatter(const ray& r_in, const hit_record& hrec, scatter_record& srec + ) const { srec.is_specular = false; srec.attenuation = albedo->value(hrec.u, hrec.v, hrec.p); srec.pdf_ptr = new cosine_pdf(hrec.normal); @@ -1737,6 +1788,7 @@ texture *albedo; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [lambertian-scatter]: [material.h] New lambertian scatter() method]
@@ -1767,6 +1819,7 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-scatter]: [main.cc] Ray color with scatter]
@@ -1793,6 +1846,7 @@ double fuzz; }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [metal-scatter]: [material.h] The metal class scatter method]
Note that if fuzziness is high, this surface isn’t ideally specular, but the implicit sampling works @@ -1833,6 +1887,8 @@ return vec3(0,0,0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [ray-color-implicit]: [main.cc] + Ray color function with implicitly-sampled rays]
@@ -1871,6 +1927,7 @@ vfov, aspect, aperture, dist_to_focus, 0.0, 1.0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-cornell-al]: [main.cc] Cornell box scene with aluminum material]
@@ -1968,6 +2025,7 @@ return uvw.local(random_to_sphere(radius, distance_squared)); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sphere-pdf]: [sphere.h] Sphere with pdf]
@@ -1984,6 +2042,7 @@ return vec3(x, y, z); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [rand-to-sphere]: [pdf.h] The random_to_sphere utility function]
@@ -2004,6 +2063,7 @@ col += ray_color(r, world, glass_sphere, 0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [sampling-sphere]: [main.cc] Sampling just the sphere]
@@ -2035,6 +2095,7 @@ return list[ index ]->random(o); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [density-mixture]: [hittable_list.h] Creating a mixture of densities]
@@ -2048,6 +2109,7 @@ a[1] = glass_sphere; hittable_list hlist(a,2); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [scene-density-mixture]: [main.cc] Updating the scene]
@@ -2100,6 +2162,7 @@ << static_cast(255.999 * clamp(b, 0.0, 1.0)) << '\n'; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [Listing [write-color-nan]: [common/vec3.h] NaN-tolerant write_color function]
diff --git a/src/TheRestOfYourLife/bucamera.h b/src/TheRestOfYourLife/bucamera.h new file mode 100644 index 00000000..0763377c --- /dev/null +++ b/src/TheRestOfYourLife/bucamera.h @@ -0,0 +1,49 @@ +#ifndef CAMERAH +#define CAMERAH +//================================================================================================== +// Written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "ray.h" + + +class camera { + public: + camera() { + lower_left_corner = vec3(-2.0, -1.0, -1.0); + horizontal = vec3(4.0, 0.0, 0.0); + vertical = vec3(0.0, 2.0, 0.0); + /* + lower_left_corner = vec3(-.1, -0.05, -1.0); + horizontal = vec3(0.2, 0.0, 0.0); + vertical = vec3(0.0, 0.1, 0.0); + */ + origin = vec3(0.0, 0.0, 0.0); + } + + camera(vec3 lookfrom, vec3 lookat, vec3 view_up, float aspect, float vfov, float aperture, float distance_to_focus) { + origin = lookfrom; + w = unit_vector(lookfrom - lookat; + u = unit_vector(cross(vup, w)); + v = cross(w, u); + ZZ + } + ray get_ray(float s, float t) { return ray(origin, lower_left_corner + s*horizontal + t*vertical - origin); } + + vec3 origin; + vec3 lower_left_corner; + vec3 horizontal; + vec3 vertical; + vec3 u, v, w; + float radius; +}; + +#endif + diff --git a/src/TheRestOfYourLife/cos_cubed.cc b/src/TheRestOfYourLife/cos_cubed.cc new file mode 100644 index 00000000..fb34605d --- /dev/null +++ b/src/TheRestOfYourLife/cos_cubed.cc @@ -0,0 +1,31 @@ +//================================================================================================== +// Originally written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include + + +int main() { + int N = 1000000; + auto sum = 0.0; + for (int i = 0; i < N; i++) { + auto r1 = random_double(); + auto r2 = random_double(); + auto x = cos(2*pi*r1)*2*sqrt(r2*(1-r2)); + auto y = sin(2*pi*r1)*2*sqrt(r2*(1-r2)); + auto z = 1 - r2; + sum += z*z*z / (1.0/(2.0*pi)); + } + std::cout << "PI/2 = " << pi/2 << '\n'; + std::cout << "Estimate = " << sum/N << '\n'; +} diff --git a/src/TheRestOfYourLife/cos_density.cc b/src/TheRestOfYourLife/cos_density.cc new file mode 100644 index 00000000..eb8f92d7 --- /dev/null +++ b/src/TheRestOfYourLife/cos_density.cc @@ -0,0 +1,38 @@ +//================================================================================================== +// Written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include + + +inline vec3 random_cosine_direction() { + auto r1 = random_double(); + auto r2 = random_double(); + auto z = sqrt(1-r2); + auto phi = 2*pi*r1; + auto x = cos(phi)*sqrt(r2); + auto y = sin(phi)*sqrt(r2); + return vec3(x, y, z); +} + + +int main() { + int N = 1000000; + auto sum = 0.0; + for (int i = 0; i < N; i++) { + vec3 v = random_cosine_direction(); + sum += v.z()*v.z()*v.z() / (v.z()/(pi)); + } + std::cout << "PI/2 = " << pi/2 << '\n'; + std::cout << "Estimate = " << sum/N << '\n'; +} diff --git a/src/TheRestOfYourLife/hittable.h b/src/TheRestOfYourLife/hittable.h index ea8786f7..e3e2ffe1 100644 --- a/src/TheRestOfYourLife/hittable.h +++ b/src/TheRestOfYourLife/hittable.h @@ -38,12 +38,12 @@ struct hit_record material *mat_ptr; }; -class hittable { +class hittable { public: virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const = 0; virtual bool bounding_box(double t0, double t1, aabb& box) const = 0; - virtual double pdf_value(const vec3& o, const vec3& v) const {return 0.0;} - virtual vec3 random(const vec3& o) const {return vec3(1, 0, 0);} + virtual double pdf_value(const vec3& o, const vec3& v) const { return 0.0; } + virtual vec3 random(const vec3& o) const { return vec3(1,0,0); } }; class flip_normals : public hittable { @@ -120,8 +120,7 @@ rotate_y::rotate_y(hittable *p, double angle) : ptr(p) { auto newx = cos_theta*x + sin_theta*z; auto newz = -sin_theta*x + cos_theta*z; vec3 tester(newx, y, newz); - for ( int c = 0; c < 3; c++ ) - { + for ( int c = 0; c < 3; c++ ) { if ( tester[c] > max[c] ) max[c] = tester[c]; if ( tester[c] < min[c] ) diff --git a/src/TheRestOfYourLife/integrate_x_sq.cc b/src/TheRestOfYourLife/integrate_x_sq.cc new file mode 100644 index 00000000..ab08b48c --- /dev/null +++ b/src/TheRestOfYourLife/integrate_x_sq.cc @@ -0,0 +1,33 @@ +//================================================================================================== +// Originally written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include +#include + + +inline double pdf(double x) { + return 3*x*x/8; +} + +int main() { + int inside_circle = 0; + int inside_circle_stratified = 0; + int N = 1; + auto sum = 0.0; + for (int i = 0; i < N; i++) { + auto x = pow(8*random_double(), 1./3.); + sum += x*x / pdf(x); + } + std::cout << "I = " << sum/N << "\n"; +} diff --git a/src/TheRestOfYourLife/main.cc b/src/TheRestOfYourLife/main.cc index 6f5e6010..9b0859b5 100644 --- a/src/TheRestOfYourLife/main.cc +++ b/src/TheRestOfYourLife/main.cc @@ -57,12 +57,13 @@ vec3 ray_color(const ray& r, hittable *world, hittable *light_shape, int depth) } void cornell_box(hittable **scene, camera **cam, double aspect) { - int i = 0; - hittable **list = new hittable*[8]; material *red = new lambertian( new constant_texture(vec3(0.65, 0.05, 0.05)) ); material *white = new lambertian( new constant_texture(vec3(0.73, 0.73, 0.73)) ); material *green = new lambertian( new constant_texture(vec3(0.12, 0.45, 0.15)) ); material *light = new diffuse_light( new constant_texture(vec3(15, 15, 15)) ); + + hittable **list = new hittable*[8]; + int i = 0; list[i++] = new flip_normals(new yz_rect(0, 555, 0, 555, 555, green)); list[i++] = new yz_rect(0, 555, 0, 555, 0, red); list[i++] = new flip_normals(new xz_rect(213, 343, 227, 332, 554, light)); @@ -74,6 +75,7 @@ void cornell_box(hittable **scene, camera **cam, double aspect) { list[i++] = new translate(new rotate_y( new box(vec3(0, 0, 0), vec3(165, 330, 165), white), 15), vec3(265,0,295)); *scene = new hittable_list(list,i); + vec3 lookfrom(278, 278, -800); vec3 lookat(278, 278, 0); auto dist_to_focus = 10.0; diff --git a/src/TheRestOfYourLife/pdf.h b/src/TheRestOfYourLife/pdf.h index ad442933..5a2d7527 100644 --- a/src/TheRestOfYourLife/pdf.h +++ b/src/TheRestOfYourLife/pdf.h @@ -35,17 +35,14 @@ inline vec3 random_to_sphere(double radius, double distance_squared) { return vec3(x, y, z); } - vec3 random_in_unit_sphere() { vec3 p; do { - p = 2.0*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); - } while (dot(p,p) >= 1.0); + p = 2*vec3(random_double(),random_double(),random_double()) - vec3(1,1,1); + } while (p.squared_length() >= 1); return p; } - - class pdf { public: virtual double value(const vec3& direction) const = 0; @@ -53,7 +50,6 @@ class pdf { virtual ~pdf() {} }; - class cosine_pdf : public pdf { public: cosine_pdf(const vec3& w) { uvw.build_from_w(w); } diff --git a/src/TheRestOfYourLife/pi.cc b/src/TheRestOfYourLife/pi.cc new file mode 100644 index 00000000..3c368d08 --- /dev/null +++ b/src/TheRestOfYourLife/pi.cc @@ -0,0 +1,42 @@ +//================================================================================================== +// Originally written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include +#include + + +int main() { + int inside_circle = 0; + int inside_circle_stratified = 0; + int sqrt_N = 10000; + for (int i = 0; i < sqrt_N; i++) { + for (int j = 0; j < sqrt_N; j++) { + auto x = 2*random_double() - 1; + auto y = 2*random_double() - 1; + if (x*x + y*y < 1) + inside_circle++; + x = 2*((i + random_double()) / sqrt_N) - 1; + y = 2*((j + random_double()) / sqrt_N) - 1; + if (x*x + y*y < 1) + inside_circle_stratified++; + } + } + + auto N = static_cast(sqrt_N) * sqrt_N; + std::cout + << "Regular Estimate of Pi = " + << 4*double(inside_circle) / N << '\n' + << "Stratified Estimate of Pi = " + << 4*double(inside_circle_stratified) / N << '\n'; +} diff --git a/src/TheRestOfYourLife/sphere_importance.cc b/src/TheRestOfYourLife/sphere_importance.cc new file mode 100644 index 00000000..f6d552f8 --- /dev/null +++ b/src/TheRestOfYourLife/sphere_importance.cc @@ -0,0 +1,42 @@ +//================================================================================================== +// Originally written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include +#include + + +vec3 random_on_unit_sphere() { + vec3 p; + double len_squared; + do { + p = 2*vec3(random_double(), random_double(), random_double()) - vec3(1,1,1); + len_squared = p.squared_length(); + } while (len_squared >= 1); + return p / sqrt(len_squared); +} + +inline double pdf(const vec3& p) { + return 1.0 / (4.0*pi); +} + +int main() { + int N = 1000000; + auto sum = 0.0; + for (int i = 0; i < N; i++) { + vec3 d = random_on_unit_sphere(); + auto cosine_squared = d.z()*d.z(); + sum += cosine_squared / pdf(d); + } + std::cout << "I = " << sum/N << '\n'; +} diff --git a/src/TheRestOfYourLife/sphere_plot.cc b/src/TheRestOfYourLife/sphere_plot.cc new file mode 100644 index 00000000..d01f47f7 --- /dev/null +++ b/src/TheRestOfYourLife/sphere_plot.cc @@ -0,0 +1,27 @@ +//================================================================================================== +// Originally written in 2016 by Peter Shirley +// +// To the extent possible under law, the author(s) have dedicated all copyright and related and +// neighboring rights to this software to the public domain worldwide. This software is distributed +// without any warranty. +// +// You should have received a copy (see file COPYING.txt) of the CC0 Public Domain Dedication along +// with this software. If not, see . +//================================================================================================== + +#include "common/rtweekend.h" + +#include +#include + + +int main() { + for (int i = 0; i < 2000; i++) { + auto r1 = random_double(); + auto r2 = random_double(); + auto x = cos(2*pi*r1)*2*sqrt(r2*(1-r2)); + auto y = sin(2*pi*r1)*2*sqrt(r2*(1-r2)); + auto z = 1 - 2*r2; + std::cout << x << " " << y << " " << z << '\n'; + } +} diff --git a/style/book.css b/style/book.css index e5028d31..3a60951d 100644 --- a/style/book.css +++ b/style/book.css @@ -131,6 +131,14 @@ body { color: #a0a0a0; } +.md div.listingcaption { + margin-left: 3ex; +} + +.md div.listingcaption kbd { + font-style: normal; +} + /* ------------------------------------------------------------------------------------------------- ** Images & Figures ** -----------------------------------------------------------------------------------------------*/ @@ -195,4 +203,9 @@ body { .md pre.listing.tilde code { font-size: 65%; } + + .md div.listingcaption.tilde { + margin-left: 5ex; + } + }