Realize the triangle struct doesn't work and completely refactor it

This commit is contained in:
bijan2005 2020-12-05 23:22:19 -05:00
parent 822941d561
commit cddec468de
6 changed files with 107 additions and 71 deletions

View file

@ -6,10 +6,10 @@ use na::geometry::Point3;
use crate::types::*;
use super::Surface;
pub struct Triangle<'a> {
pub vertex1: &'a Point3<f32>, // References to 3 vertices.
pub vertex2: &'a Point3<f32>,
pub vertex3: &'a Point3<f32>,
pub struct Triangle {
pub v1: usize, // Handles to 3 vertices.
pub v2: usize,
pub v3: usize,
area: f32, // Precalculated area for barycentric calculations.
@ -17,9 +17,9 @@ pub struct Triangle<'a> {
// Uses barycentric coordinates as input.
}
pub struct TriangleMesh<'a> {
pub points: Vec<Box<Point3<f32>>>,
pub tris: Vec<Triangle<'a>>
pub struct TriangleMesh {
pub points: Vec<Point3<f32>>,
pub tris: Vec<Triangle>
}
fn tri_area(a: &Point3<f32>, b: &Point3<f32>, c: &Point3<f32>) -> f32 {
@ -27,48 +27,96 @@ fn tri_area(a: &Point3<f32>, b: &Point3<f32>, c: &Point3<f32>) -> f32 {
prlg_area / 2.0
}
impl<'a> Triangle<'a> {
pub fn new<F: 'static>(vertex1: &'a Point3<f32>,
vertex2: &'a Point3<f32>,
vertex3: &'a Point3<f32>,
texture: F) -> Self
where F: Fn(f32, f32, f32) -> Color
{
Triangle {
vertex1: vertex1,
vertex2: vertex2,
vertex3: vertex3,
area: tri_area(vertex1, vertex2, vertex3),
texture: Box::new(texture)
}
}
pub fn new_solid(vertex1: &'a Point3<f32>,
vertex2: &'a Point3<f32>,
vertex3: &'a Point3<f32>, color: Color) -> Self
{ Triangle::new(vertex1, vertex2, vertex3, move |_, _, _| color) }
impl Triangle {
fn vertex1<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v1] }
fn vertex2<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v2] }
fn vertex3<'a>(&self, vertices: &'a Vec<Point3<f32>>) -> &'a Point3<f32> { &vertices[self.v3] }
// Conversion of barycentric coordinates to
// a point on the triangle.
pub fn from_bary(&self, t: f32, u: f32, v: f32) -> Point3<f32> {
Point::from(t * self.vertex1.coords + u * self.vertex2.coords + v * self.vertex3.coords)
fn from_bary(&self, vertices: &Vec<Point3<f32>>, t: f32, u: f32, v: f32) -> Point3<f32> {
Point::from(t * self.vertex1(vertices).coords + u * self.vertex2(vertices).coords + v * self.vertex3(vertices).coords)
}
// Conversion of a point to barycentric coordinates.
pub fn to_bary(&self, point: Point3<f32>) -> (f32, f32, f32) {
let t = tri_area(self.vertex2, self.vertex3, &point) / self.area;
let u = tri_area(self.vertex1, self.vertex3, &point) / self.area;
let v = tri_area(self.vertex1, self.vertex2, &point) / self.area;
fn to_bary(&self, vertices: &Vec<Point3<f32>>, point: Point3<f32>) -> (f32, f32, f32) {
let t = tri_area(self.vertex2(vertices), self.vertex3(vertices), &point) / self.area;
let u = tri_area(self.vertex1(vertices), self.vertex3(vertices), &point) / self.area;
let v = tri_area(self.vertex1(vertices), self.vertex2(vertices), &point) / self.area;
(t, u, v)
}
}
impl<'a> TriangleMesh<'a> {
pub fn new(points: Vec<Box<Point3<f32>>>, tris: Vec<Triangle<'a>>) -> Self {
TriangleMesh {
points: points,
tris: tris
}
fn intersect(&self, vertices: &Vec<Point3<f32>>, ray: Ray) -> Option<f32> {
let vect2_1 = self.vertex2(vertices) - self.vertex1(vertices);
let vect3_1 = self.vertex3(vertices) - self.vertex1(vertices);
let p_vect = ray.direction.cross(&vect3_1);
let det = p_vect.dot(&vect2_1);
if det.abs() < 1e-5 { return None; }
let t_vect = ray.origin - self.vertex1(vertices);
let u = t_vect.dot(&p_vect) / det;
if u < 0.0 || u > 1.0 { return None; }
let q_vect = t_vect.cross(&vect2_1);
let v = ray.direction.dot(&q_vect) / det;
if v < 0.0 || (u + v) > 1.0 { return None; }
let t = vect3_1.dot(&q_vect) / det;
// Convert from barycentric coordinates
Some(distance(&ray.origin, &self.from_bary(vertices, t, u, v)))
}
fn normal(&self, vertices: &Vec<Point3<f32>>, _point: Point3<f32>) -> Unit<Vector3<f32>> {
Unit::new_normalize((self.vertex2(vertices) - self.vertex1(vertices)).cross(&(self.vertex3(vertices) - self.vertex1(vertices))))
}
fn getcolor(&self, vertices: &Vec<Point3<f32>>, point: Point3<f32>) -> Color {
// Converting back and forth between barycentric coordinates
// like this is terrible, but it's necessary for this object to
// match the interface the other objects use.
let (t, u, v) = self.to_bary(vertices, point);
(*self.texture)(t, u, v)
}
}
impl TriangleMesh {
pub fn new(points: Vec<Point3<f32>>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Color>)>) -> Self {
let triangles = tris.into_iter()
.map(|(v1, v2, v3, f)| Triangle {
v1: v1,
v2: v2,
v3: v3,
area: tri_area(&points[v1], &points[v2], &points[v3]),
texture: f
}).collect();
TriangleMesh {
points: points,
tris: triangles
}
}
pub fn new_solid(points: Vec<Point3<f32>>, tris: Vec<(usize, usize, usize)>, color: Color) -> Self {
let triangles = tris.into_iter()
.map(|(v1, v2, v3)| Triangle {
v1: v1,
v2: v2,
v3: v3,
area: tri_area(&points[v1], &points[v2], &points[v3]),
texture: Box::new(move |_, _, _| color)
}).collect();
TriangleMesh {
points: points,
tris: triangles
}
}
pub fn singleton<F: 'static>(vertex1: Point3<f32>, vertex2: Point3<f32>, vertex3: Point3<f32>, texture: F) -> Self
where F: Fn(f32, f32, f32) -> Color
{ TriangleMesh::new(vec![vertex1, vertex2, vertex3], vec![(0, 1, 2, Box::new(texture))]) }