1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
use crate::{ Camera, Color, Ray, Real, Shape, shape::Group }; use rayon::iter::{ IntoParallelIterator, ParallelIterator }; pub struct RayTracer { pub camera : Camera, pub ixsize : u32, pub iysize : u32, pub spp : u32, pub rdepth : u32 } impl RayTracer { pub fn new(camera: Camera, ixsize: u32, spp: u32, rdepth: u32) -> Self { let iysize = (ixsize as Real / camera.ratio) as u32; Self { camera, ixsize, iysize, spp, rdepth } } fn get_st(&self, (x, y): (Real, Real)) -> (Real, Real) { (x / (self.ixsize - 1) as Real, (self.iysize as Real - y - 1.0) / (self.iysize - 1) as Real) } fn sample_vars(&self) -> impl Iterator< Item = (Real, Real) > { (0..self.spp).map(|_| (rand::random(), rand::random())) } fn ray_color(world: &Group, ray: Ray, depth: u32) -> Color { match (0..depth).try_fold( (Color::new(1.0, 1.0, 1.0), ray), |(color, ray), _| world.hit(ray, 0.001..Real::INFINITY) .ok_or_else(|| { let t = 0.5 * (1.0 + ray.dir.normalize().y); color * ((1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.86, 0.92, 1.0)) }) .and_then(|hr| hr.mat.scatter(ray, &hr) .map(|(scattered, attenuation)| (color * attenuation, scattered)) .ok_or_else(|| Color::new(0.0, 0.0, 0.0)))) { Ok(_) => Color::new(0.0, 0.0, 0.0), Err(color) => color, } } pub fn draw(&self, world: &Group) -> Vec< Color > { let pbar = indicatif::ProgressBar::new(self.iysize as u64); let sv = self.sample_vars().collect::< Vec< _ > >(); (0..self.iysize).into_par_iter().map(|y| { let ret = (0..self.ixsize).map(|x| Color::mix(sv.iter().map(|(xp, yp)| { let (xx, yy) = (x as Real + xp, y as Real + yp); let (s, t) = self.get_st((xx, yy)); let ray = self.camera.get_ray((s, t)); Self::ray_color(&world, ray, self.rdepth) })) ).collect::< Vec< _ > >(); pbar.inc(1); ret }).flatten().collect::< Vec< _ > >() } }