use crate::{hittable::Hittable, material::MaterialKind, math_utils::is_front_face, types_defined::{HitRecord, Point, Ray, Vec3}}; pub struct Triangle { pub points: Vec, pub material: Option, } impl Triangle { pub fn new(p1: Point, p2: Point, p3: Point, material: Option,) -> Self { Triangle { points: vec![ p1, p2, p3 ], material: material } } } impl Hittable for Triangle { fn hit(&self, r: &Ray, t_min: f32, t_max: f32, hit_record: &mut HitRecord) -> bool { let p0 = self.points[0]; let p1 = self.points[1]; let p2 = self.points[2]; let u = Vec3 { x: p1.x - p0.x, y: p1.y - p0.y, z: p1.z - p0.z, }; let v = Vec3 { x: p2.x - p0.x, y: p2.y - p0.y, z: p2.z - p0.z, }; let normal = Vec3 { x: u.y * v.z - u.z * v.y, y: u.z * v.x - u.x * v.z, z: u.x * v.y - u.y * v.x, }; let denominator = r.direction.x * normal.x + r.direction.y * normal.y + r.direction.z * normal.z; if denominator.abs() < std::f32::EPSILON { return false; } let w0 = Vec3 { x: r.point.x - p0.x, y: r.point.y - p0.y, z: r.point.z - p0.z, }; let t = -(w0.x * normal.x + w0.y * normal.y + w0.z * normal.z) / denominator; if t < t_min || t > t_max { return false; } let P = Vec3 { x: r.point.x + t * r.direction.x, y: r.point.y + t * r.direction.y, z: r.point.z + t * r.direction.z, }; let w = Vec3 { x: P.x - p0.x, y: P.y - p0.y, z: P.z - p0.z, }; let uv_cross = Vec3 { x: u.y * v.z - u.z * v.y, y: u.z * v.x - u.x * v.z, z: u.x * v.y - u.y * v.x, }; let wv_cross = Vec3 { x: w.y * v.z - w.z * v.y, y: w.z * v.x - w.x * v.z, z: w.x * v.y - w.y * v.x, }; let uw_cross = Vec3 { x: u.y * w.z - u.z * w.y, y: u.z * w.x - u.x * w.z, z: u.x * w.y - u.y * w.x, }; let alpha = (wv_cross.x * normal.x + wv_cross.y * normal.y + wv_cross.z * normal.z) / (uv_cross.x * normal.x + uv_cross.y * normal.y + uv_cross.z * normal.z); let beta = (uw_cross.x * normal.x + uw_cross.y * normal.y + uw_cross.z * normal.z) / (uv_cross.x * normal.x + uv_cross.y * normal.y + uv_cross.z * normal.z); if alpha >= 0.0 && beta >= 0.0 && alpha + beta <= 1.0 { hit_record.p = P; hit_record.t = t; hit_record.normal = normal; hit_record.front_face = is_front_face(r, normal); hit_record.material = if let Some(ref m) = self.material { match m { MaterialKind::Lambertian(l) => Some(MaterialKind::Lambertian(l.clone())), MaterialKind::Metal(m) => Some(MaterialKind::Metal(m.clone())), MaterialKind::Dielectric(d) => Some(MaterialKind::Dielectric(d.clone())), } } else { None }; return true; } false } }