use cgmath::prelude::*; use cgmath::{Vector3, vec3}; use rand::prelude::*; use std::f64::INFINITY; use crate::camera::Camera; use crate::scene::Scene; use crate::utils::{print_colour}; use crate::ray::Ray; use crate::hittable::Hittable; fn ray_colour(rng: &mut ThreadRng, ray: &Ray, scene: &Scene, depth: i32) -> Vector3 { if depth <= 0 { return vec3(0.0, 0.0, 0.0) } if let Some(t) = scene.is_hit(ray, 0.001, INFINITY) { if let Some(nray) = t.material.scatter(rng, ray, &t) { ray_colour(rng, &nray.ray, scene, depth-1).mul_element_wise(nray.attenuation) } else { vec3(0.0, 0.0, 0.0) } } else { 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) } } 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(rng, u, v); colour += ray_colour(rng, &ray, &world, max_depth); } print_colour(&colour, samples); } } }