aboutsummaryrefslogtreecommitdiffstats
path: root/src/render.rs
blob: 6e2abf83fc09144c24c110086b7b95033b89cc13 (plain)
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
use cgmath::prelude::*;
use cgmath::{Vector3, vec3};
use rand::prelude::*;
use std::f64::INFINITY;
use crate::camera::Camera;
use crate::colour::print_colour;
use crate::scene::Scene;
use crate::random::random_in_unit_sphere;
use crate::ray::Ray;
use crate::hittable::Hittable;

fn ray_colour(rng: &mut ThreadRng, ray: &Ray, scene: &Scene, depth: i32) -> Vector3<f64> {
    if depth <= 0 { return vec3(0.0, 0.0, 0.0) }

    match scene.is_hit(ray, 0.001, INFINITY) {
        None => {
            let t = 0.5 * (ray.dir.normalize().y + 1.0);
            (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0)
        }
        Some(t) => {
            let target = t.p + t.normal + random_in_unit_sphere(rng);
            0.5 * ray_colour(rng, &Ray::new(t.p, target - t.p), scene, depth - 1)
        }
    }
}

pub fn render(world: &Scene, camera: Camera, image_height: i32, image_width: i32,
          samples: i32, max_depth: i32, rng: &mut ThreadRng) {
    for j in 0 .. image_height {
        eprint!("\rScanlines: {:3} / {:3}", j+1, image_height);
        for i in 0 .. image_width  {
            let mut colour = vec3(0.0, 0.0, 0.0);
            for _ in 0 .. samples {
                let ru: f64 = rng.gen();
                let rv: f64 = rng.gen();
                let u = (i as f64 + ru) / image_width as f64;
                let v = ((image_height - 1 - j) as f64 + rv) / image_height as f64;
                let ray = camera.get_ray(u, v);
                colour += ray_colour(rng, &ray, &world, max_depth);
            }
            print_colour(&colour, samples);
        }
    }
}