mirror of
https://github.com/Manoj-HV30/multithreaded-raytracer.git
synced 2026-05-16 19:35:24 +00:00
188 lines
5.6 KiB
C++
188 lines
5.6 KiB
C++
#ifndef CAMERA_H
|
|
#define CAMERA_H
|
|
|
|
#include "hittable.h"
|
|
#include "material.h"
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
|
|
class camera {
|
|
public:
|
|
|
|
double aspect_ratio = 1.0;
|
|
int image_width = 100;
|
|
int samples_per_pixel = 10;
|
|
int max_depth = 10;
|
|
|
|
double vfov = 90;
|
|
point3 lookfrom = point3(0,0,0);
|
|
point3 lookat = point3(0,0,-1);
|
|
vec3 vup = vec3(0,1,0);
|
|
|
|
|
|
double defocus_angle = 0;
|
|
double focus_dist = 10;
|
|
|
|
void render(const hittable& world) {
|
|
initialize();
|
|
|
|
std::vector<color> framebuffer(image_width * image_height);
|
|
|
|
int thread_count = std::thread::hardware_concurrency();
|
|
if (thread_count == 0) thread_count = 8; // fallback
|
|
|
|
std::vector<std::thread> threads;
|
|
int rows_per_thread = image_height / thread_count;
|
|
|
|
auto render_rows = [&](int start_row, int end_row) {
|
|
|
|
for (int j = start_row; j < end_row; j++) {
|
|
|
|
for (int i = 0; i < image_width; i++) {
|
|
|
|
color pixel_color(0,0,0);
|
|
|
|
for (int sample = 0; sample < samples_per_pixel; sample++) {
|
|
ray r = get_ray(i, j);
|
|
pixel_color += ray_color(r, max_depth, world);
|
|
}
|
|
|
|
framebuffer[j * image_width + i] =
|
|
pixel_samples_scale * pixel_color;
|
|
}
|
|
}
|
|
};
|
|
|
|
for (int t = 0; t < thread_count; t++) {
|
|
int start = t * rows_per_thread;
|
|
int end = (t == thread_count - 1)
|
|
? image_height
|
|
: start + rows_per_thread;
|
|
|
|
threads.emplace_back(render_rows, start, end);
|
|
}
|
|
|
|
for (auto& t : threads)
|
|
t.join();
|
|
|
|
// Print image after rendering completes (single-threaded)
|
|
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
|
|
|
|
for (int j = 0; j < image_height; j++) {
|
|
for (int i = 0; i < image_width; i++) {
|
|
write_color(std::cout,
|
|
framebuffer[j * image_width + i]);
|
|
}
|
|
}
|
|
|
|
std::clog << "Done.\n";
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
/* Private Camera Variables Here */
|
|
int image_height; // Rendered image height
|
|
point3 center; // Camera center
|
|
double pixel_samples_scale;// color scale factor for a sum of pixel samples
|
|
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;
|
|
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_samples_scale = 1.0/ samples_per_pixel;
|
|
|
|
center = lookfrom;
|
|
|
|
|
|
|
|
// Determine viewport dimensions.
|
|
|
|
auto theta = degrees_to_radians(vfov);
|
|
auto h = std::tan(theta/2);
|
|
auto viewport_height = 2 * h * focus_dist;
|
|
auto viewport_width = viewport_height * (double(image_width)/image_height);
|
|
|
|
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;
|
|
vec3 viewport_v = viewport_height*-v;
|
|
|
|
// Calculate the horizontal and vertical delta vectors from pixel to 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 * std::tan(degrees_to_radians(defocus_angle / 2));
|
|
defocus_disk_u = u * defocus_radius;
|
|
defocus_disk_v = v * defocus_radius;
|
|
|
|
}
|
|
|
|
ray get_ray(int i, int j) const {
|
|
// 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
|
|
+ ((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;
|
|
|
|
return ray(ray_origin, ray_direction);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
point3 defocus_disk_sample() const {
|
|
// Returns a random point in the camera defocus disk.
|
|
auto p = random_in_unit_disk();
|
|
return center + (p[0] * defocus_disk_u) + (p[1] * defocus_disk_v);
|
|
}
|
|
|
|
|
|
|
|
color ray_color(const ray& r,int depth, const hittable& world) const {
|
|
if(depth<=0)
|
|
return color(0,0,0);
|
|
|
|
hit_record rec;
|
|
|
|
if (world.hit(r, interval(0.001, infinity), rec)) {
|
|
ray scattered;
|
|
color attenuation;
|
|
if (rec.mat->scatter(r, rec, attenuation, scattered))
|
|
return attenuation * ray_color(scattered, depth-1, world);
|
|
return color(0,0,0);
|
|
}
|
|
|
|
vec3 unit_direction = unit_vector(r.direction());
|
|
auto a = 0.5*(unit_direction.y() + 1.0);
|
|
return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|