rustracer/src/triangle.rs

79 lines
2.4 KiB
Rust

use std::sync::Arc;
use crate::hittable::{HitRecord, Hittable};
use crate::{Aabb, Material, Point3, Ray, Vec3};
//https://github.com/perliedman/raytracing-in-one-weekend/blob/master/src/geometry/triangle.rs
pub struct Triangle {
a: Point3,
b: Point3,
c: Point3,
normal: Vec3,
material: Arc<Material>,
}
impl Triangle {
pub fn new(a: Point3, b: Point3, c: Point3, normal: Vec3, material: Arc<Material>, ) -> Self {
Self { a, b, c, normal, material }
}
pub fn without_normal(a: Point3, b: Point3, c: Point3, material: Arc<Material>, ) -> Self {
let normal = (b - a).cross(&(c - a));
Self { a, b, c, normal, material }
}
}
impl Hittable for Triangle {
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
let ab = self.b - self.a;
let ac = self.c - self.a;
let pvec = ray.direction().cross(&ac);
let det = ab.dot(&pvec);
if det.abs() < 1e-4 {
return None;
}
let inv_det = 1.0 / det;
let tvec = ray.origin() - self.a;
let u = tvec.dot(&pvec) * inv_det;
if u < 0.0 || u > 1.0 {
return None;
}
let qvec = tvec.cross(&ab);
let v = ray.direction().dot(&qvec) * inv_det;
if v < 0.0 || u + v > 1.0 {
return None;
}
match ac.dot(&qvec) * inv_det {
t if t < t_min || t > t_max => None,
t => {
let mut rec = HitRecord {
point: ray.at(t),
normal: self.normal,
t,
u,
v,
front_face: true,
material: &self.material
};
rec.normalized(ray);
Some(rec)
}
}
}
fn bounding_box(&self, _time0: f64, _time1: f64) -> Option<Aabb> {
Some(Aabb {
minimum: Point3::new(
self.a.x().min(self.b.x()).min(self.c.x()),
self.a.y().min(self.b.y()).min(self.c.y()),
self.a.z().min(self.b.z()).min(self.c.z()),
),
maximum: Point3::new(
self.a.x().max(self.b.x()).max(self.c.x()),
self.a.y().max(self.b.y()).max(self.c.y()),
self.a.z().max(self.b.z()).max(self.c.z()),
),
})
}
}