rustracer/src/ray.rs

68 lines
2.0 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, 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<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
}
}