Skip to main content

dasom/
ray_tracer.rs

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