feat: triangle

This commit is contained in:
dengqn 2025-08-20 15:44:09 +08:00
parent ff7cde8758
commit 27905c888f
1 changed files with 100 additions and 0 deletions

100
src/triangle.rs Normal file
View File

@ -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<Vec3>,
pub material: Option<MaterialKind>,
}
impl Triangle {
pub fn new(p1: Point, p2: Point, p3: Point, material: Option<MaterialKind>,) -> 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
}
}