rustracer/src/ray.rs

70 lines
2.1 KiB
Rust

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<HitRecord<'material>> {
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
}
}