diff --git a/src/triangle.rs b/src/triangle.rs new file mode 100644 index 0000000..009a332 --- /dev/null +++ b/src/triangle.rs @@ -0,0 +1,100 @@ +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 + } +} \ No newline at end of file