Create triangle struct (and add comments)

This commit is contained in:
bijan2005 2020-12-04 15:11:01 -05:00
parent ef6ce4bbde
commit 822941d561
5 changed files with 120 additions and 12 deletions

View file

@ -19,7 +19,7 @@ This list may be changed or extended in the future.
- [x] Plane intersection test - [x] Plane intersection test
- [x] Color mapping on planes - [x] Color mapping on planes
- [ ] Triangle objects - [ ] Triangle objects
- [ ] Triangle struct - [x] Triangle struct
- [ ] Triangle intersection test - [ ] Triangle intersection test
- [ ] Triangle normal generation - [ ] Triangle normal generation
- [ ] Color mapping on triangles - [ ] Color mapping on triangles

View file

@ -7,11 +7,20 @@ use na::*;
use crate::types::*; use crate::types::*;
// A trait for types that can be in Objects.
pub trait Surface { pub trait Surface {
// Takes in a ray and performs an intersection test
// on itself. If the ray intersects the object,
// returns the distance to the intersection point.
fn intersect(&self, ray: Ray) -> Option<f32>; fn intersect(&self, ray: Ray) -> Option<f32>;
// Takes in a point (assumed to be on the object's surface)
// and returns the normal vector off of that point.
fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>>; fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>>;
// Takes in a point (assumed to be on the object's surface)
// and returns the color information on that point.
fn getcolor(&self, point: Point3<f32>) -> Color; fn getcolor(&self, point: Point3<f32>) -> Color;
} }

View file

@ -7,15 +7,18 @@ use crate::types::*;
use super::Surface; use super::Surface;
pub struct Plane { pub struct Plane {
pub center: Point3<f32>, pub center: Point3<f32>, // Plane origin (used for texture mapping).
pub normal: Unit<Vector3<f32>>, pub normal: Unit<Vector3<f32>>, // Precomputed plane normal.
x_axis: Vector3<f32>, x_axis: Vector3<f32>, // Plane x-axis (The 3D direction that corresponds to the x-direction on the plane).
y_axis: Vector3<f32>, y_axis: Vector3<f32>, // Plane y-axis (The 3D direction that corresponds to the y-direction on the plane).
texture: Box<dyn Fn(f32, f32) -> Color>
texture: Box<dyn Fn(f32, f32) -> Color> // Texture map.
// Input coordinates are defined in terms of the axes above.
} }
impl Plane { impl Plane {
// Creates a new plane.
pub fn new<F: 'static>(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, texture: F) -> Self pub fn new<F: 'static>(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, texture: F) -> Self
where F: Fn(f32, f32) -> Color where F: Fn(f32, f32) -> Color
{ {
@ -28,12 +31,33 @@ impl Plane {
} }
} }
// Creates a new plane with the normal flipped.
pub fn new_flip<F: 'static>(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, texture: F) -> Self
where F: Fn(f32, f32) -> Color
{
Plane {
center: center,
normal: Unit::new_normalize(y_axis.cross(&x_axis)),
x_axis: x_axis,
y_axis: y_axis,
texture: Box::new(texture)
}
}
// Creates a new plane of a solid color.
pub fn new_solid(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, color: Color) -> Self pub fn new_solid(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, color: Color) -> Self
{ Plane::new(center, x_axis, y_axis, move |_, _| color) } { Plane::new(center, x_axis, y_axis, move |_, _| color) }
// Creates a new flipped plane of a solid color.
pub fn new_solid_flip(center: Point3<f32>, x_axis: Vector3<f32>, y_axis: Vector3<f32>, color: Color) -> Self
{ Plane::new_flip(center, x_axis, y_axis, move |_, _| color) }
// Creates a new XY-plane with the given texture map.
pub fn xy<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self pub fn xy<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) } { Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) }
// Creates a new XZ-plane with the given texture map.
pub fn xz<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self pub fn xz<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) } { Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) }
} }
@ -42,7 +66,7 @@ impl Surface for Plane {
fn intersect(&self, ray: Ray) -> Option<f32> { fn intersect(&self, ray: Ray) -> Option<f32> {
let d = self.normal.dot(&ray.direction); let d = self.normal.dot(&ray.direction);
if d < 1e-6 { return None; } if d < 1e-5 { return None; }
let t = (self.center - ray.origin).dot(&*self.normal) / d; let t = (self.center - ray.origin).dot(&*self.normal) / d;

View file

@ -9,13 +9,15 @@ use crate::types::*;
use super::Surface; use super::Surface;
pub struct Sphere { pub struct Sphere {
pub center: Point3<f32>, pub center: Point3<f32>, // Center point of the sphere.
pub radius: f32, pub radius: f32, // Radius of the sphere.
texture: Box<dyn Fn(f32, f32) -> Color> texture: Box<dyn Fn(f32, f32) -> Color> // Texture map.
// Uses spherical coordinates (normalized from 0-1) as input.
} }
impl Sphere { impl Sphere {
// Creates a new sphere.
pub fn new<F: 'static>(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self pub fn new<F: 'static>(x: f32, y: f32, z: f32, radius: f32, texture: F) -> Self
where F: Fn(f32, f32) -> Color where F: Fn(f32, f32) -> Color
{ {
@ -26,6 +28,7 @@ impl Sphere {
} }
} }
// Creates a new sphere of a solid color.
pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self pub fn new_solid(x: f32, y: f32, z: f32, radius: f32, color: Color) -> Self
{ Sphere::new(x, y, z, radius, move |_, _| color) } { Sphere::new(x, y, z, radius, move |_, _| color) }
} }
@ -69,8 +72,6 @@ impl Surface for Sphere {
// In this particular case, the normal is simular to a point on a unit sphere // In this particular case, the normal is simular to a point on a unit sphere
// centred around the origin. We can thus use the normal coordinates to compute // centred around the origin. We can thus use the normal coordinates to compute
// the spherical coordinates of the point. // the spherical coordinates of the point.
// atan2 returns a value in the range [-pi, pi] and we need to remap it to range [0, 1]
// acosf returns a value in the range [0, pi] and we also need to remap it to the range [0, 1]
let x = 0.5 + normal.z.atan2(normal.x) / (2.0 * PI); let x = 0.5 + normal.z.atan2(normal.x) / (2.0 * PI);
let y = normal.y.acos() / PI; let y = normal.y.acos() / PI;

View file

@ -0,0 +1,74 @@
extern crate nalgebra as na;
use na::*;
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>,
area: f32, // Precalculated area for barycentric calculations.
texture: Box<dyn Fn(f32, f32, f32) -> Color> // Texture map.
// Uses barycentric coordinates as input.
}
pub struct TriangleMesh<'a> {
pub points: Vec<Box<Point3<f32>>>,
pub tris: Vec<Triangle<'a>>
}
fn tri_area(a: &Point3<f32>, b: &Point3<f32>, c: &Point3<f32>) -> f32 {
let prlg_area: f32 = (b - a).cross(&(c - a)).norm();
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) }
// 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)
}
// 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;
(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
}
}
}