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, background: Color, world: &HittableList, depth: i32) -> Color { if depth <= 0 { return Color::default(); } match self.hit_world(world, 0.001, f64::INFINITY) { Some(rect) => { let scattered = rect.material.scatter(self, &rect); let emitted = rect.material.emitted(rect.u, rect.v, &rect.point); match scattered { Some((scattered, albedo)) => { match scattered { Some(scattered) => { emitted + albedo * scattered.pixel_color(background, world, depth-1) }, None => albedo } }, _ => emitted } }, None => background } } pub 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 } }