wip: parallelization

This commit is contained in:
2026-05-03 14:58:56 +02:00
parent eb90c36ae8
commit 10f9c0984d
23 changed files with 294 additions and 211 deletions

View File

@@ -1,34 +1,23 @@
use std::{f32::consts::PI, sync::Arc};
use std::f32::consts::PI;
use log::info;
use crate::{
objects::{hit::Hit, traits::Hittable},
ray::Ray,
vec3::{Colour, Vec3},
};
use crate::{ray::Ray, vec3::Vec3};
#[derive(Debug)]
pub struct Camera {
// output
image_width: u32,
image_height: u32,
// raytracing
anti_alias_rate: u32,
max_depth: u32,
pixel00_loc: Vec3,
pixel_delta_u: Vec3,
pixel_delta_v: Vec3,
pub anti_alias_rate: u32,
pub pixel00_loc: Vec3,
pub pixel_delta_u: Vec3,
pub pixel_delta_v: Vec3,
// camera
dirty: bool,
fov: f32,
look_from: Vec3,
look_at: Vec3,
pub fov: f32,
pub look_from: Vec3,
pub look_at: Vec3,
vup: Vec3,
defocus_angle: f32,
focus_dist: f32,
pub defocus_angle: f32,
pub focus_dist: f32,
// camera helpers
u: Vec3,
@@ -44,12 +33,9 @@ fn deg_to_rad(deg: f32) -> f32 {
}
impl Camera {
pub fn new(image_width: u32, image_height: u32) -> Self {
pub fn new() -> Self {
Self {
image_width,
image_height,
anti_alias_rate: 1,
max_depth: 10,
dirty: true,
fov: 60.,
pixel00_loc: Vec3::default(),
@@ -69,10 +55,7 @@ impl Camera {
}
pub fn new_full(
image_width: u32,
image_height: u32,
anti_alias_rate: u32,
max_depth: u32,
fov: f32,
look_from: Vec3,
look_at: Vec3,
@@ -81,10 +64,7 @@ impl Camera {
focus_dist: f32,
) -> Self {
Self {
image_width,
image_height,
anti_alias_rate,
max_depth,
pixel00_loc: Vec3::default(),
pixel_delta_u: Vec3::default(),
pixel_delta_v: Vec3::default(),
@@ -103,7 +83,11 @@ impl Camera {
}
}
fn init(&mut self) {
pub fn init(&mut self, w: f32, hi: f32) {
if !self.dirty {
return;
}
// camera
let theta = deg_to_rad(self.fov);
let h = (theta / 2.).tan();
@@ -113,13 +97,13 @@ impl Camera {
// viewport
let viewport_height = 2. * h * self.focus_dist;
let viewport_width = viewport_height * (self.image_width as f32 / self.image_height as f32);
let viewport_width = viewport_height * (w / hi);
let viewport_u = viewport_width * self.u;
let viewport_v = viewport_height * -self.v;
// variables
self.pixel_delta_u = viewport_u / self.image_width as f32;
self.pixel_delta_v = viewport_v / self.image_height as f32;
self.pixel_delta_u = viewport_u / w;
self.pixel_delta_v = viewport_v / hi;
self.pixel00_loc =
self.look_from - (self.focus_dist * self.w) - viewport_u / 2. - viewport_v / 2.;
self.dirty = false;
@@ -131,6 +115,19 @@ impl Camera {
}
}
pub fn get_ray(&self, pixel_tl: Vec3, x: u32, y: u32) -> Ray {
let pixel_loc = pixel_tl
+ (x * self.pixel_delta_u / (self.anti_alias_rate + 1) as f32)
+ (y * self.pixel_delta_v / (self.anti_alias_rate + 1) as f32);
let ray_orig = if self.defocus_angle > 0. {
self.defocus_disk_sample()
} else {
self.look_from
};
let ray_dir = pixel_loc - ray_orig;
Ray::new(ray_orig, ray_dir)
}
pub fn set_fov(&mut self, fov: f32) {
if self.fov != fov {
self.fov = fov;
@@ -138,13 +135,6 @@ impl Camera {
}
}
pub fn set_max_depth(&mut self, depth: u32) {
if self.max_depth != depth {
self.max_depth = depth;
self.dirty = true;
}
}
pub fn set_anti_alias_rate(&mut self, rate: u32) {
if self.anti_alias_rate != rate {
self.anti_alias_rate = rate;
@@ -181,72 +171,8 @@ impl Camera {
}
}
fn defocus_disk_sample(&self) -> Vec3 {
pub fn defocus_disk_sample(&self) -> Vec3 {
let p = Vec3::random_in_unit_disk();
self.look_from + (p.x() * self.defocus_disk_u) + (p.y() * self.defocus_disk_v)
}
pub fn render(&mut self, hittables: &Vec<Arc<dyn Hittable>>) {
if self.dirty {
self.init()
}
let mut imgbuf = image::ImageBuffer::new(self.image_width, self.image_height);
// render
for j in 0..self.image_height {
info!("{}\tScanlines remaining.", (self.image_height - j));
for i in 0..self.image_width {
let pixel_tl =
self.pixel00_loc + (i * self.pixel_delta_u) + (j * self.pixel_delta_v);
let mut pixel_colour = Colour::default();
for y in 1..(self.anti_alias_rate + 1) {
for x in 1..(self.anti_alias_rate + 1) {
let pixel_loc = pixel_tl
+ (x * self.pixel_delta_u / (self.anti_alias_rate + 1) as f32)
+ (y * self.pixel_delta_v / (self.anti_alias_rate + 1) as f32);
let ray_orig = if self.defocus_angle > 0. {
self.defocus_disk_sample()
} else {
self.look_from
};
let ray_dir = pixel_loc - ray_orig;
let r = Ray::new(ray_orig, ray_dir);
pixel_colour += self.ray_colour(hittables, &r, self.max_depth);
}
}
let pixel = imgbuf.get_pixel_mut(i, j);
*pixel =
(pixel_colour / (self.anti_alias_rate * self.anti_alias_rate) as f32).output();
}
}
info!("Writing image file...");
imgbuf.save("output.png").unwrap();
}
fn ray_colour(&self, hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
if depth == 0 {
return Colour::default();
}
let closest = Hit::hit_list(hittables, r);
if let Some(hit) = closest {
if let Some((scattered, att)) = hit.mat().scatter(&hit, r) {
if let Some(ray) = scattered {
return att * self.ray_colour(hittables, &ray, depth - 1);
}
return att;
}
return Colour::default();
}
// background
let unit_dir = r.dir().get_unit();
let a = 0.5 * (unit_dir.y() + 1.);
(1.0 - a) * Colour::new(1., 1., 1.) + a * Colour::new(0.5, 0.7, 1.0)
}
}