use std::cmp::Ordering; use std::f64::consts::PI; use crate::object::*; use crate::util::*; fn trace(ray: Ray, objects: &Vec) -> Option<(&Object, f64)> { objects .iter() .filter_map(|obj| obj.intersect(ray).map(|x| (obj, x))) .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal)) } fn light_point(objects: &Vec, obj: &Object, point: Point3f, light: &dyn Light) -> Color { if light.check_shadow(point, objects) { let texture = obj.get_texture(point); light.get_color(point) * (texture.albedo / PI) * light.intensity(point) * obj.normal(point).dot(&*light.direction(point)) } else { // Point is in shadow Color::black() } } pub fn cast_ray(ray: Ray, scene: &Scene) -> Color { if let Some((obj, dist)) = trace(ray, &scene.objects) { let point = ray.project(dist); let surface_color = obj.get_texture(point).color; scene .lights .iter() .map(|light| light_point(&scene.objects, obj, point, &**light)) .fold(Color::black(), |acc, c| acc + c) * surface_color } else { scene.background } }