Renderer/src/hittable.rs
2022-06-29 16:17:28 +02:00

94 lines
2.5 KiB
Rust

use super::{Arc, Color, Material, Metal, Point3, Ray, Vec3};
pub struct HitRecord {
pub p: Point3,
pub normal: Vec3,
pub mat_ptr: Arc<dyn Material>,
pub t: f64,
pub front_face: bool,
}
pub struct Sphere {
center: Point3,
radius: f64,
pub mat_ptr: Arc<dyn Material>,
}
pub trait Hittable: Sync + Send {
fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool;
}
impl HitRecord {
fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) {
self.front_face = Vec3::dot(r.direction(), outward_normal) < 0.0;
if self.front_face {
self.normal = outward_normal;
} else {
self.normal = (-1.0) * outward_normal;
}
}
pub fn new(p: Point3, normal: Vec3, m: Arc<dyn Material>, t: f64, front_face: bool) -> Self {
HitRecord {
p: p,
normal: normal,
mat_ptr: m,
t: t,
front_face: front_face,
}
}
pub fn empty() -> Self {
Self::new(
Point3::null(),
Vec3::null(),
Arc::new(Metal::new(&Color::null(), 0.0)),
0.0,
false,
)
}
}
impl Sphere {
pub fn new(cen: Point3, r: f64, m: Arc<dyn Material>) -> Self {
Sphere {
center: cen,
radius: r,
mat_ptr: m,
}
}
}
impl Hittable for Sphere {
fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
let oc = r.origin() - self.center;
let a = r.direction().length_squared(); // gleiches Ergebnis wie Skalarprodukt
let half_b = Vec3::dot(oc, r.direction());
let c = oc.length_squared() - self.radius * self.radius;
let discriminant = half_b * half_b - a * c;
if discriminant < 0.0 {
return false;
}
let sqrtd = discriminant.sqrt();
let mut root = (-half_b - sqrtd) / a;
let normal = (r.at(root) - self.center) / self.radius;
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
root = (-half_b + sqrtd) / a;
let normal = (r.at(root) - self.center) / self.radius;
if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 {
return false;
}
}
rec.t = root;
rec.p = r.at(rec.t);
let outward_normal = (rec.p - self.center) / self.radius;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = self.mat_ptr.clone();
return true;
}
}