| #ifndef CAMERA_H |
| #define CAMERA_H |
| //============================================================================================== |
| // Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com> |
| // |
| // 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 |
| // <http://creativecommons.org/publicdomain/zero/1.0/>. |
| // |
| // The original source code is from |
| // https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek |
| // |
| // Changes to the original code follow the following license. |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| //============================================================================================== |
| |
| #include "rtweekend.h" |
| |
| #include "PPMImageFile.h" |
| #include "color.h" |
| #include "hittable.h" |
| #include "material.h" |
| #include <chrono> |
| #include <fstream> |
| #include <iostream> |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wunused-parameter" |
| |
| #define BLKDIM_X 16 |
| #define BLKDIM_Y 16 |
| |
| class camera { |
| public: |
| double aspect_ratio = 1.0; // Ratio of image width over height |
| int image_width = 100; // Rendered image width in pixel count |
| int image_height = 0; // Rendered image height |
| int samples_per_pixel = 10; // Count of random samples for each pixel |
| int max_depth = 10; // Maximum number of ray bounces into scene |
| color background; // Scene background color |
| |
| double vfov = 90; // Vertical view angle (field of view) |
| point3 lookfrom = point3(0,0,-1); // Point camera is looking from |
| point3 lookat = point3(0,0,0); // Point camera is looking at |
| vec3 vup = vec3(0,1,0); // Camera-relative "up" direction |
| |
| double defocus_angle = 0; // Variation angle of rays through each pixel |
| double focus_dist = 10; // Distance from camera lookfrom point to plane of perfect focus |
| |
| // Render the pixel at row i and column j. |
| __host__ __device__ void renderOnePixel(int i, int j, const hittable &world, |
| color *img) { |
| unsigned rnd = j * image_width + i; |
| color pixel_color(0, 0, 0); |
| for (int sample = 0; sample < samples_per_pixel; ++sample) { |
| ray r = get_ray(i, j, rnd); |
| pixel_color += ray_color(r, max_depth, world, rnd); |
| } |
| img[j * image_width + i] = pixel_color * (1.0 / samples_per_pixel); |
| } |
| |
| void render(const hittable &world, color *img) { |
| for (int j = 0; j < image_height; ++j) { |
| if ((image_height - j) % 100 == 0) |
| std::cout << "Scanlines remaining: " << (image_height - j) << '\n' |
| << std::flush; |
| for (int i = 0; i < image_width; ++i) { |
| renderOnePixel(i, j, world, img); |
| } |
| } |
| |
| std::cout << "Done.\n"; |
| } |
| |
| private: |
| 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 |
| |
| public: |
| __host__ __device__ void initialize() { |
| image_height = static_cast<int>(image_width / aspect_ratio); |
| image_height = (image_height < 1) ? 1 : image_height; |
| |
| center = lookfrom; |
| |
| // Determine viewport dimensions. |
| auto theta = degrees_to_radians(vfov); |
| auto h = tan(theta / 2); |
| auto viewport_height = 2 * h * focus_dist; |
| auto viewport_width = |
| viewport_height * (static_cast<double>(image_width) / image_height); |
| |
| // Calculate the u,v,w unit basis vectors for the camera coordinate frame. |
| w = unit_vector(lookfrom - lookat); |
| u = unit_vector(cross(vup, w)); |
| v = cross(w, u); |
| |
| // Calculate the vectors across the horizontal and down the vertical |
| // viewport edges. |
| vec3 viewport_u = |
| viewport_width * u; // Vector across viewport horizontal edge |
| vec3 viewport_v = |
| viewport_height * -v; // Vector down viewport vertical edge |
| |
| // Calculate the horizontal and vertical delta vectors to the next pixel. |
| pixel_delta_u = viewport_u / image_width; |
| pixel_delta_v = viewport_v / image_height; |
| |
| // Calculate the location of the upper left pixel. |
| auto viewport_upper_left = |
| center - (focus_dist * w) - viewport_u / 2 - viewport_v / 2; |
| pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v); |
| |
| // Calculate the camera defocus disk basis vectors. |
| auto defocus_radius = |
| focus_dist * tan(degrees_to_radians(defocus_angle / 2)); |
| defocus_disk_u = u * defocus_radius; |
| defocus_disk_v = v * defocus_radius; |
| } |
| |
| private: |
| __host__ __device__ ray get_ray(int i, int j, unsigned &rnd) const { |
| // 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(rnd); |
| |
| auto ray_origin = |
| (defocus_angle <= 0) ? center : defocus_disk_sample(rnd); |
| auto ray_direction = pixel_sample - ray_origin; |
| auto ray_time = random_double(rnd); |
| |
| return ray(ray_origin, ray_direction, ray_time); |
| } |
| |
| __host__ __device__ vec3 pixel_sample_square(unsigned &rnd) const { |
| // Returns a random point in the square surrounding a pixel at the origin. |
| auto px = -0.5 + random_double(rnd); |
| auto py = -0.5 + random_double(rnd); |
| return (px * pixel_delta_u) + (py * pixel_delta_v); |
| } |
| |
| __host__ __device__ vec3 pixel_sample_disk(double radius, |
| unsigned &rnd) const { |
| // Generate a sample from the disk of given radius around a pixel at the |
| // origin. |
| auto p = radius * random_in_unit_disk(rnd); |
| return (p[0] * pixel_delta_u) + (p[1] * pixel_delta_v); |
| } |
| |
| __host__ __device__ point3 defocus_disk_sample(unsigned &rnd) const { |
| // Returns a random point in the camera defocus disk. |
| auto p = random_in_unit_disk(rnd); |
| return center + (p[0] * defocus_disk_u) + (p[1] * defocus_disk_v); |
| } |
| |
| __host__ __device__ color ray_color(const ray &r, int depth, |
| const hittable &world, |
| unsigned &rnd) const { |
| // If we've exceeded the ray bounce limit, no more light is gathered. |
| if (depth <= 0) |
| return color(0, 0, 0); |
| |
| hit_record rec; |
| |
| // If the ray hits nothing, return the background color. |
| if (!world.hit(r, interval(0.001, infinity), rec, rnd)) |
| return background; |
| |
| ray scattered; |
| color attenuation; |
| color color_from_emission = rec.mat->emitted(rec.u, rec.v, rec.p); |
| |
| if (!rec.mat->scatter(r, rec, attenuation, scattered, rnd)) |
| return color_from_emission; |
| |
| color color_from_scatter = |
| attenuation * ray_color(scattered, depth - 1, world, rnd); |
| |
| return color_from_emission + color_from_scatter; |
| } |
| }; |
| |
| #pragma clang diagnostic pop |
| #endif |