From 1147cc782efda9a54f796503e02ac60e7e740ecc Mon Sep 17 00:00:00 2001 From: Steve Hollasch Date: Sat, 9 Mar 2024 15:23:12 -0800 Subject: [PATCH 1/2] Refactor pixel subsampling - Simplify pixel sampling to make the sampling functions simpler and agnostic about their use as pixel sampling functions. Now they sample an idealized unit square or disk and are ignorant about image components. - pixel_sample_xxx() functions renamed to sample_xx(). - Rename pixel_sample_scale to pixel_samples_scale. - Reworded some comments for clarity. - I really wish I could have come up with a better rename for `sqrt_spp` and `recip_sqrt_spp`, but I've been unable to think of anything better. --- books/RayTracingInOneWeekend.html | 82 +++++++++++++------------- books/RayTracingTheNextWeek.html | 6 +- books/RayTracingTheRestOfYourLife.html | 43 ++++++++------ src/InOneWeekend/camera.h | 41 +++++++------ src/TheNextWeek/camera.h | 43 +++++++------- src/TheRestOfYourLife/camera.h | 58 ++++++++++-------- 6 files changed, 145 insertions(+), 128 deletions(-) diff --git a/books/RayTracingInOneWeekend.html b/books/RayTracingInOneWeekend.html index 046484c8..8f0b7376 100644 --- a/books/RayTracingInOneWeekend.html +++ b/books/RayTracingInOneWeekend.html @@ -2041,7 +2041,7 @@ Now let's update the camera class to define and use a new `camera::get_ray(i,j)` function, which will generate different samples for each pixel. This function will use a new helper function -`pixel_sample_square()` that generates a random sample point within the unit square centered at the +`sample_square()` that generates a random sample point within the unit square centered at the origin. We then transform the random sample from this ideal square back to the particular pixel we're currently sampling. @@ -2068,7 +2068,7 @@ ray r = get_ray(i, j); pixel_color += ray_color(r, world); } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ } } @@ -2077,11 +2077,11 @@ } ... private: - int image_height; // Rendered image height + int image_height; // Rendered image height ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - double pixel_sample_scale; // Color scale factor for a pixel sample + double pixel_samples_scale; // Color scale factor for a sum of pixel samples ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - point3 center; // Camera center + point3 center; // Camera center ... void initialize() { @@ -2090,7 +2090,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ center = point3(0, 0, 0); @@ -2102,8 +2102,10 @@ ray get_ray(int i, int j) const { // Get a randomly sampled camera ray for the pixel at location i,j. - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(); + auto offset = sample_square(); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = center; auto ray_direction = pixel_sample - ray_origin; @@ -2111,11 +2113,9 @@ return ray(ray_origin, ray_direction); } - vec3 pixel_sample_square() const { - // Returns a random point in the square surrounding a pixel at the origin. - auto px = -0.5 + random_double(); - auto py = -0.5 + random_double(); - return (px * pixel_delta_u) + (py * pixel_delta_v); + vec3 sample_square() const { + // Returns the vector to a random point in the [-.5,-.5]-[+.5,+.5] unit square. + return vec3(random_double() - 0.5, random_double() - 0.5, 0); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ @@ -2128,10 +2128,10 @@ -(In addition to the new `pixel_sample_square()` function above, you'll also find the function -`pixel_sample_disk()` in the Github source code. This is included in case you'd like to experiment -with non-square pixels, but we won't be using it in this book. `pixel_sample_disk()` depends on the -function `random_in_unit_disk()` which is defined later on.) +(In addition to the new `sample_square()` function above, you'll also find the function +`sample_disk()` in the Github source code. This is included in case you'd like to experiment with +non-square pixels, but we won't be using it in this book. `sample_disk()` depends on the function +`random_in_unit_disk()` which is defined later on.)
Main is updated to set the new camera parameter. @@ -2398,7 +2398,7 @@ pixel_color += ray_color(r, max_depth, world); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } @@ -3572,7 +3572,7 @@ image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; center = point3(0, 0, 0); @@ -3698,21 +3698,21 @@ ... private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample - point3 center; // Camera center - point3 pixel00_loc; // Location of pixel 0, 0 - vec3 pixel_delta_u; // Offset to pixel to the right - vec3 pixel_delta_v; // Offset to pixel below + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples + point3 center; // Camera center + point3 pixel00_loc; // Location of pixel 0, 0 + vec3 pixel_delta_u; // Offset to pixel to the right + vec3 pixel_delta_v; // Offset to pixel below ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - vec3 u, v, w; // Camera frame basis vectors + vec3 u, v, w; // Camera frame basis vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ void initialize() { image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -3944,23 +3944,23 @@ ... private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample - point3 center; // Camera center - point3 pixel00_loc; // Location of pixel 0, 0 - vec3 pixel_delta_u; // Offset to pixel to the right - vec3 pixel_delta_v; // Offset to pixel below - vec3 u, v, w; // Camera frame basis vectors + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples + point3 center; // Camera center + point3 pixel00_loc; // Location of pixel 0, 0 + vec3 pixel_delta_u; // Offset to pixel to the right + vec3 pixel_delta_v; // Offset to pixel below + vec3 u, v, w; // Camera frame basis vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - vec3 defocus_disk_u; // Defocus disk horizontal radius - vec3 defocus_disk_v; // Defocus disk vertical radius + vec3 defocus_disk_u; // Defocus disk horizontal radius + vec3 defocus_disk_v; // Defocus disk vertical radius ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ void initialize() { image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; center = lookfrom; @@ -4009,8 +4009,10 @@ // the camera defocus disk. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(); + auto offset = sample_square(); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight @@ -4021,7 +4023,7 @@ return ray(ray_origin, ray_direction); } - vec3 pixel_sample_square() const { + vec3 sample_square() const { ... } diff --git a/books/RayTracingTheNextWeek.html b/books/RayTracingTheNextWeek.html index 5e42a8a1..b3f7148e 100644 --- a/books/RayTracingTheNextWeek.html +++ b/books/RayTracingTheNextWeek.html @@ -147,8 +147,10 @@ // Get a randomly-sampled camera ray for the pixel at location i,j, originating from // the camera defocus disk. - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(); + auto offset = sample_square(); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample(); auto ray_direction = pixel_sample - ray_origin; diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html index be1fa417..58f83aae 100644 --- a/books/RayTracingTheRestOfYourLife.html +++ b/books/RayTracingTheRestOfYourLife.html @@ -324,7 +324,7 @@ } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } @@ -332,13 +332,13 @@ } ... private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - int sqrt_spp; // Square root of number of samples per pixel - double recip_sqrt_spp; // 1 / sqrt_spp + int sqrt_spp; // Square root of number of samples per pixel + double recip_sqrt_spp; // 1 / sqrt_spp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - point3 center; // Camera center + point3 center; // Camera center ... void initialize() { @@ -348,7 +348,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight sqrt_spp = int(sqrt(samples_per_pixel)); - pixel_sample_scale = 1.0 / (sqrt_spp * sqrt_spp); + pixel_samples_scale = 1.0 / (sqrt_spp * sqrt_spp); recip_sqrt_spp = 1.0 / sqrt_spp; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ @@ -357,14 +357,15 @@ } ... ray get_ray(int i, int j, int s_i, int s_j) const { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight // Get a randomly-sampled camera ray for the pixel at location i,j, originating from // the camera defocus disk, and randomly sampled around the pixel location. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - auto pixel_sample = pixel_center + pixel_sample_square(s_i, s_j); + auto offset = sample_square_stratified(s_i, s_j); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample(); auto ray_direction = pixel_sample - ray_origin; @@ -375,13 +376,19 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - vec3 pixel_sample_square(int s_i, int s_j) const { - // Returns a random point in the square surrounding a pixel at the origin, given - // the two subpixel indices. - auto px = -0.5 + recip_sqrt_spp * (s_i + random_double()); - auto py = -0.5 + recip_sqrt_spp * (s_j + random_double()); + vec3 sample_square_stratified(int s_i, int s_j) const { + // Returns the vector to a random point in the square sub-pixel specified by grid + // indices s_i and s_j, for an idealized unit square pixel [-.5,-.5] to [+.5,+.5]. + + auto px = ((s_i + random_double()) * recip_sqrt_spp) - 0.5; + auto py = ((s_j + random_double()) * recip_sqrt_spp) - 0.5; + + return vec3(px, py, 0); + } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ - return (px * pixel_delta_u) + (py * pixel_delta_v); + + vec3 sample_square() const { + ... } ... @@ -2836,7 +2843,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ } } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } diff --git a/src/InOneWeekend/camera.h b/src/InOneWeekend/camera.h index 85dc8872..017910de 100644 --- a/src/InOneWeekend/camera.h +++ b/src/InOneWeekend/camera.h @@ -48,7 +48,7 @@ class camera { ray r = get_ray(i, j); pixel_color += ray_color(r, max_depth, world); } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } @@ -56,21 +56,21 @@ class camera { } private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample - point3 center; // Camera center - point3 pixel00_loc; // Location of pixel 0, 0 - vec3 pixel_delta_u; // Offset to pixel to the right - vec3 pixel_delta_v; // Offset to pixel below - vec3 u, v, w; // Camera frame basis vectors - vec3 defocus_disk_u; // Defocus disk horizontal radius - vec3 defocus_disk_v; // Defocus disk vertical radius + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples + point3 center; // Camera center + point3 pixel00_loc; // Location of pixel 0, 0 + vec3 pixel_delta_u; // Offset to pixel to the right + vec3 pixel_delta_v; // Offset to pixel below + vec3 u, v, w; // Camera frame basis vectors + vec3 defocus_disk_u; // Defocus disk horizontal radius + vec3 defocus_disk_v; // Defocus disk vertical radius void initialize() { image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; center = lookfrom; @@ -107,8 +107,10 @@ class camera { // Get a randomly-sampled camera ray for the pixel at location i,j, originating from // the camera defocus disk. - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(); + auto offset = sample_square(); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample(); auto ray_direction = pixel_sample - ray_origin; @@ -116,17 +118,14 @@ class camera { return ray(ray_origin, ray_direction); } - vec3 pixel_sample_square() const { + vec3 sample_square() const { // Returns a random point in the square surrounding a pixel at the origin. - auto px = -0.5 + random_double(); - auto py = -0.5 + random_double(); - return (px * pixel_delta_u) + (py * pixel_delta_v); + return vec3(random_double() - 0.5, random_double() - 0.5, 0); } - vec3 pixel_sample_disk(double radius) const { - // Generate a sample from the disk of given radius around a pixel at the origin. - auto p = radius * random_in_unit_disk(); - return (p[0] * pixel_delta_u) + (p[1] * pixel_delta_v); + vec3 sample_disk(double radius) const { + // Returns a random point in the unit (radius 0.5) disk centered at the origin. + return radius * random_in_unit_disk(); } point3 defocus_disk_sample() const { diff --git a/src/TheNextWeek/camera.h b/src/TheNextWeek/camera.h index 4dc9e6b9..a677ea06 100644 --- a/src/TheNextWeek/camera.h +++ b/src/TheNextWeek/camera.h @@ -49,7 +49,7 @@ class camera { ray r = get_ray(i, j); pixel_color += ray_color(r, max_depth, world); } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } @@ -57,21 +57,21 @@ class camera { } private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample - point3 center; // Camera center - point3 pixel00_loc; // Location of pixel 0, 0 - vec3 pixel_delta_u; // Offset to pixel to the right - vec3 pixel_delta_v; // Offset to pixel below - vec3 u, v, w; // Camera frame basis vectors - vec3 defocus_disk_u; // Defocus disk horizontal radius - vec3 defocus_disk_v; // Defocus disk vertical radius + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples + point3 center; // Camera center + point3 pixel00_loc; // Location of pixel 0, 0 + vec3 pixel_delta_u; // Offset to pixel to the right + vec3 pixel_delta_v; // Offset to pixel below + vec3 u, v, w; // Camera frame basis vectors + vec3 defocus_disk_u; // Defocus disk horizontal radius + vec3 defocus_disk_v; // Defocus disk vertical radius void initialize() { image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; - pixel_sample_scale = 1.0 / samples_per_pixel; + pixel_samples_scale = 1.0 / samples_per_pixel; center = lookfrom; @@ -106,10 +106,12 @@ class camera { ray get_ray(int i, int j) const { // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk. + // the camera defocus disk, and randomly sampled around the pixel location. - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(); + auto offset = sample_square(); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample(); auto ray_direction = pixel_sample - ray_origin; @@ -118,17 +120,14 @@ class camera { return ray(ray_origin, ray_direction, ray_time); } - vec3 pixel_sample_square() const { + vec3 sample_square() const { // Returns a random point in the square surrounding a pixel at the origin. - auto px = -0.5 + random_double(); - auto py = -0.5 + random_double(); - return (px * pixel_delta_u) + (py * pixel_delta_v); + return vec3(random_double() - 0.5, random_double() - 0.5, 0); } - vec3 pixel_sample_disk(double radius) const { - // Generate a sample from the disk of given radius around a pixel at the origin. - auto p = radius * random_in_unit_disk(); - return (p[0] * pixel_delta_u) + (p[1] * pixel_delta_v); + vec3 sample_disk(double radius) const { + // Returns a random point in the unit (radius 0.5) disk centered at the origin. + return radius * random_in_unit_disk(); } point3 defocus_disk_sample() const { diff --git a/src/TheRestOfYourLife/camera.h b/src/TheRestOfYourLife/camera.h index 3be5d515..2f68a81a 100644 --- a/src/TheRestOfYourLife/camera.h +++ b/src/TheRestOfYourLife/camera.h @@ -51,7 +51,7 @@ class camera { pixel_color += ray_color(r, max_depth, world, lights); } } - write_color(std::cout, pixel_sample_scale * pixel_color); + write_color(std::cout, pixel_samples_scale * pixel_color); } } @@ -59,24 +59,24 @@ class camera { } private: - int image_height; // Rendered image height - double pixel_sample_scale; // Color scale factor for a pixel sample - int sqrt_spp; // Square root of number of samples per pixel - double recip_sqrt_spp; // 1 / sqrt_spp - point3 center; // Camera center - point3 pixel00_loc; // Location of pixel 0, 0 - vec3 pixel_delta_u; // Offset to pixel to the right - vec3 pixel_delta_v; // Offset to pixel below - vec3 u, v, w; // Camera frame basis vectors - vec3 defocus_disk_u; // Defocus disk horizontal radius - vec3 defocus_disk_v; // Defocus disk vertical radius + int image_height; // Rendered image height + double pixel_samples_scale; // Color scale factor for a sum of pixel samples + int sqrt_spp; // Square root of number of samples per pixel + double recip_sqrt_spp; // 1 / sqrt_spp + point3 center; // Camera center + point3 pixel00_loc; // Location of pixel 0, 0 + vec3 pixel_delta_u; // Offset to pixel to the right + vec3 pixel_delta_v; // Offset to pixel below + vec3 u, v, w; // Camera frame basis vectors + vec3 defocus_disk_u; // Defocus disk horizontal radius + vec3 defocus_disk_v; // Defocus disk vertical radius void initialize() { image_height = int(image_width / aspect_ratio); image_height = (image_height < 1) ? 1 : image_height; sqrt_spp = int(sqrt(samples_per_pixel)); - pixel_sample_scale = 1.0 / (sqrt_spp * sqrt_spp); + pixel_samples_scale = 1.0 / (sqrt_spp * sqrt_spp); recip_sqrt_spp = 1.0 / sqrt_spp; center = lookfrom; @@ -114,8 +114,10 @@ class camera { // Get a randomly-sampled camera ray for the pixel at location i,j, originating from // the camera defocus disk, and randomly sampled around the pixel location. - auto pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); - auto pixel_sample = pixel_center + pixel_sample_square(s_i, s_j); + auto offset = sample_square_stratified(s_i, s_j); + auto pixel_sample = pixel00_loc + + ((i + offset.x()) * pixel_delta_u) + + ((j + offset.y()) * pixel_delta_v); auto ray_origin = (defocus_angle <= 0) ? center : defocus_disk_sample(); auto ray_direction = pixel_sample - ray_origin; @@ -124,18 +126,24 @@ class camera { return ray(ray_origin, ray_direction, ray_time); } - vec3 pixel_sample_square(int s_i, int s_j) const { - // Returns a random point in the square surrounding a pixel at the origin, given - // the two subpixel indices. - auto px = -0.5 + recip_sqrt_spp * (s_i + random_double()); - auto py = -0.5 + recip_sqrt_spp * (s_j + random_double()); - return (px * pixel_delta_u) + (py * pixel_delta_v); + vec3 sample_square_stratified(int s_i, int s_j) const { + // Returns the vector to a random point in the square sub-pixel specified by grid + // indices s_i and s_j, for an idealized unit square pixel [-.5,-.5] to [+.5,+.5]. + + auto px = ((s_i + random_double()) * recip_sqrt_spp) - 0.5; + auto py = ((s_j + random_double()) * recip_sqrt_spp) - 0.5; + + return vec3(px, py, 0); + } + + vec3 sample_square() const { + // Returns a random point in the square surrounding a pixel at the origin. + return vec3(random_double() - 0.5, random_double() - 0.5, 0); } - vec3 pixel_sample_disk(double radius) const { - // Generate a sample from the disk of given radius around a pixel at the origin. - auto p = radius * random_in_unit_disk(); - return (p[0] * pixel_delta_u) + (p[1] * pixel_delta_v); + vec3 sample_disk(double radius) const { + // Returns a random point in the unit (radius 0.5) disk centered at the origin. + return radius * random_in_unit_disk(); } point3 defocus_disk_sample() const { From f5216b0381452231bd8265fb38cc7c8d896a9f10 Mon Sep 17 00:00:00 2001 From: Steve Hollasch Date: Sun, 10 Mar 2024 14:36:01 -0700 Subject: [PATCH 2/2] Incorporate review feedback --- books/RayTracingInOneWeekend.html | 7 ++++--- books/RayTracingTheNextWeek.html | 4 ++-- books/RayTracingTheRestOfYourLife.html | 4 ++-- src/InOneWeekend/camera.h | 4 ++-- src/TheNextWeek/camera.h | 4 ++-- src/TheRestOfYourLife/camera.h | 4 ++-- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/books/RayTracingInOneWeekend.html b/books/RayTracingInOneWeekend.html index 8f0b7376..e6b6e0e3 100644 --- a/books/RayTracingInOneWeekend.html +++ b/books/RayTracingInOneWeekend.html @@ -2100,7 +2100,8 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight ray get_ray(int i, int j) const { - // Get a randomly sampled camera ray for the pixel at location i,j. + // Construct a camera ray originating from the origin and directed at randomly sampled + // point around the pixel location i, j. auto offset = sample_square(); auto pixel_sample = pixel00_loc @@ -4005,8 +4006,8 @@ ray get_ray(int i, int j) const { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ auto offset = sample_square(); diff --git a/books/RayTracingTheNextWeek.html b/books/RayTracingTheNextWeek.html index b3f7148e..c2c4c307 100644 --- a/books/RayTracingTheNextWeek.html +++ b/books/RayTracingTheNextWeek.html @@ -144,8 +144,8 @@ private: ... ray get_ray(int i, int j) const { - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j. auto offset = sample_square(); auto pixel_sample = pixel00_loc diff --git a/books/RayTracingTheRestOfYourLife.html b/books/RayTracingTheRestOfYourLife.html index 58f83aae..69357649 100644 --- a/books/RayTracingTheRestOfYourLife.html +++ b/books/RayTracingTheRestOfYourLife.html @@ -358,8 +358,8 @@ ... ray get_ray(int i, int j, int s_i, int s_j) const { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ highlight - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk, and randomly sampled around the pixel location. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j for stratified sample square s_i, s_j. auto offset = sample_square_stratified(s_i, s_j); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C++ diff --git a/src/InOneWeekend/camera.h b/src/InOneWeekend/camera.h index 017910de..a8abfbe3 100644 --- a/src/InOneWeekend/camera.h +++ b/src/InOneWeekend/camera.h @@ -104,8 +104,8 @@ class camera { } ray get_ray(int i, int j) const { - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j. auto offset = sample_square(); auto pixel_sample = pixel00_loc diff --git a/src/TheNextWeek/camera.h b/src/TheNextWeek/camera.h index a677ea06..2e128581 100644 --- a/src/TheNextWeek/camera.h +++ b/src/TheNextWeek/camera.h @@ -105,8 +105,8 @@ class camera { } ray get_ray(int i, int j) const { - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk, and randomly sampled around the pixel location. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j. auto offset = sample_square(); auto pixel_sample = pixel00_loc diff --git a/src/TheRestOfYourLife/camera.h b/src/TheRestOfYourLife/camera.h index 2f68a81a..1b75a022 100644 --- a/src/TheRestOfYourLife/camera.h +++ b/src/TheRestOfYourLife/camera.h @@ -111,8 +111,8 @@ class camera { } ray get_ray(int i, int j, int s_i, int s_j) const { - // Get a randomly-sampled camera ray for the pixel at location i,j, originating from - // the camera defocus disk, and randomly sampled around the pixel location. + // Construct a camera ray originating from the defocus disk and directed at a randomly + // sampled point around the pixel location i, j for stratified sample square s_i, s_j. auto offset = sample_square_stratified(s_i, s_j); auto pixel_sample = pixel00_loc