use crate::{Color, Vec3}; use crate::hittable::{HitRecord, HittableList}; use crate::material::Scatterable; use crate::vec3::Point3; #[derive(Debug)] pub struct Ray { origin: Point3, direction: Vec3, time: f64 } impl Default for Ray { fn default() -> Self { Ray::new(Vec3::default(), Vec3::default(), 0.0) } } impl Ray { pub fn new(origin: Point3, direction: Point3, time: f64) -> Ray { Ray { origin, direction, time } } pub fn at(&self, t: f64) -> Point3 { self.origin + self.direction * t } pub fn direction(&self) -> Vec3 { self.direction } pub fn origin(&self) -> Point3 { self.origin } pub fn time(&self) -> f64 { self.time } pub fn pixel_color(&self, world: &HittableList, depth: i32) -> Color { if depth <= 0 { return Color::default(); } if let Some(rect) = self.hit_world(world, 0.001, f64::INFINITY) { let scattered = rect.material.scatter(self, &rect); return match scattered { Some((scattered_ray, albedo)) => { match scattered_ray { Some(sr) => { albedo * sr.pixel_color(world, depth-1) }, None => albedo } }, None => { return Color::default() } }; } //Hot nothing, display sky color let unit_direction = self.direction().unit_vector(); let t = 0.5 * (unit_direction.y() + 1.0); (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0) } fn hit_world<'material>( &self, world: &'material HittableList, t_min: f64, t_max: f64, ) -> Option> { let mut closest_so_far = t_max; let mut hit_record = None; for sphere in world { if let Some(hit) = sphere.hit(self, t_min, closest_so_far) { closest_so_far = hit.t; hit_record = Some(hit); } } hit_record } }