Skip to content

Commit

Permalink
Chap 15: triangles
Browse files Browse the repository at this point in the history
  • Loading branch information
fremag committed Jan 27, 2024
1 parent 5923007 commit 911d04c
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 6 deletions.
33 changes: 29 additions & 4 deletions src/shapes/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::core::bounds::Bounds;
use crate::core::math;
use crate::core::math::Float;
use crate::core::ray::Ray;
use crate::core::tuple::Tuple;
Expand All @@ -23,19 +24,43 @@ impl Triangle {
pub fn new(p1 : Tuple, p2 : Tuple, p3 : Tuple) -> Self {
let e1 = p2-p1;
let e2 = p3-p1;
let normal = e2 * &e1;
let normal = (e2 * &e1).normalize();
Self {p1, p2, p3, e1, e2, normal}
}

pub(crate) fn intersect(&self, point: &Ray) -> Vec<Float> {
todo!()
pub(crate) fn intersect(&self, ray: &Ray) -> Vec<Float> {
let dir_cross_e2 = ray.direction * &self.e2;
let det = self.e1.dot(&dir_cross_e2);
if det.abs() < math::EPSILON {
return vec![];
}
let f = 1.0 / det;
let p1_to_origin = ray.origin - self.p1;
let u = f * p1_to_origin.dot(&dir_cross_e2);
if u < 0.0 || u > 1.0 {
return vec![];
}

let origin_cross_e1 = p1_to_origin * &self.e1;
let v = f * ray.direction.dot(&origin_cross_e1);
if v < 0.0 || (u + v) > 1.0 {
return vec![];
}

let t = f * self.e2.dot(&origin_cross_e1);
return vec![t]
}

pub(crate) fn normal_at(&self, _: &Tuple) -> Tuple {
self.normal
}

pub(crate) fn bounds(&self) -> Bounds {
todo!()
let mut bounds = Bounds::new();
bounds.add(&self.p1);
bounds.add(&self.p2);
bounds.add(&self.p3);

bounds
}
}
46 changes: 44 additions & 2 deletions src/tests/triangle_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(test)]
mod tests {
use crate::core::ray::ray;
use crate::core::tuple::{point, vector};
use crate::shapes::triangle::Triangle;

Expand All @@ -11,8 +12,8 @@ mod tests {
let t = Triangle::new(p1, p2, p3);

assert_eq!(t.p1, point(0.0, 1.0, 0.0));
assert_eq!(t.p1, point(-1.0, 0.0, 0.0));
assert_eq!(t.p1, point(1.0, 0.0, 0.0));
assert_eq!(t.p2, point(-1.0, 0.0, 0.0));
assert_eq!(t.p3, point(1.0, 0.0, 0.0));

assert_eq!(t.e1, vector(-1.0, -1.0, 0.0));
assert_eq!(t.e2, vector(1.0, -1.0, 0.0));
Expand All @@ -29,4 +30,45 @@ mod tests {
assert_eq!(n2, t.normal);
assert_eq!(n3, t.normal);
}

#[test]
fn intersecting_a_ray_parallel_to_the_triangle_test() {
let t = Triangle::new(point(0.0, 1.0, 0.0), point(-1.0, 0.0, 0.0), point(1.0, 0.0, 0.0));
let r = ray(point(0.0, -1.0, -2.0), vector(0.0, 1.0, 0.0));
let xs = t.intersect(&r);
assert!(xs.is_empty());
}

#[test]
fn a_ray_misses_the_p1_p3_edge_test() {
let t = Triangle::new(point(0.0, 1.0, 0.0), point(-1.0, 0.0, 0.0), point(1.0, 0.0, 0.0));
let r = ray(point(1.0, 1.0, -2.0), vector(0.0, 0.0, 1.0));
let xs = t.intersect(&r);
assert!(xs.is_empty());
}

#[test]
fn a_ray_misses_the_p1_p2_edge_test() {
let t = Triangle::new(point(0.0, 1.0, 0.0), point(-1.0, 0.0, 0.0), point(1.0, 0.0, 0.0));
let r = ray(point(-1.0, 1.0, -2.0), vector(0.0, 0.0, 1.0));
let xs = t.intersect(&r);
assert!(xs.is_empty());
}

#[test]
fn a_ray_misses_the_p2_p3_edge_test() {
let t = Triangle::new(point(0.0, 1.0, 0.0), point(-1.0, 0.0, 0.0), point(1.0, 0.0, 0.0));
let r = ray(point(0.0, -1.0, -2.0), vector(0.0, 0.0, 1.0));
let xs = t.intersect(&r);
assert!(xs.is_empty());
}

#[test]
fn a_ray_strikes_a_triangle_test() {
let t = Triangle::new(point(0.0, 1.0, 0.0), point(-1.0, 0.0, 0.0), point(1.0, 0.0, 0.0));
let r = ray(point(0.0, 0.5, -2.0), vector(0.0, 0.0, 1.0));
let xs = t.intersect(&r);
assert_eq!(xs.len(), 1);
assert_eq!(xs[0], 2.0);
}
}

0 comments on commit 911d04c

Please sign in to comment.