Files

187 lines
4.7 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;
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();
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:
int image_height;
point3 center;
double pixel_samples_scale;
point3 pixel00_loc;
vec3 pixel_delta_u;
vec3 pixel_delta_v;
vec3 u,v,w;
vec3 defocus_disk_u;
vec3 defocus_disk_v;
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;
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);
vec3 viewport_u = viewport_width*u;
vec3 viewport_v = viewport_height*-v;
pixel_delta_u = viewport_u / image_width;
pixel_delta_v = viewport_v / image_height;
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);
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 {
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 {
return vec3(random_double() - 0.5, random_double() - 0.5, 0);
}
point3 defocus_disk_sample() const {
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