raytracers/rtiow/src/cube.rs

66 lines
2.0 KiB
Rust

use aabb::AABB;
use hitable::Hit;
use hitable::HitRecord;
use material::Material;
use ray::Ray;
use vec3::dot;
use vec3::Vec3;
// Cube is an axis-aligned cube with dimensions length x length x length with center in the middle.
pub struct Cube {
center: Vec3,
length: f32,
material: Box<Material>,
}
impl Cube {
pub fn new(center: Vec3, length: f32, material: Box<Material>) -> Cube {
Cube {
center,
length,
material,
}
}
}
impl Hit for Cube {
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
// See if it hit the positive X wall first.
let oc = r.origin - self.center;
let a = dot(r.direction, r.direction);
let b = dot(oc, r.direction);
let c = dot(oc, oc) - self.length * self.length;
let discriminant = b * b - a * c;
if discriminant > 0. {
let temp = (-b - (b * b - a * c).sqrt()) / a;
if temp < t_max && temp > t_min {
let point = r.point_at_parameter(temp);
return Some(HitRecord {
t: temp,
p: point,
normal: (point - self.center) / self.length,
material: &*self.material,
});
}
let temp = (-b + (b * b - a * c).sqrt()) / a;
if temp < t_max && temp > t_min {
let point = r.point_at_parameter(temp);
return Some(HitRecord {
t: temp,
p: point,
normal: (point - self.center) / self.length,
material: &*self.material,
});
}
}
None
}
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
Some(AABB::new(
self.center - Vec3::new(self.length / 2., self.length / 2., self.length / 2.),
self.center + Vec3::new(self.length / 2., self.length / 2., self.length / 2.),
))
}
}