Create triangle struct (and add comments)
This commit is contained in:
parent
ef6ce4bbde
commit
822941d561
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue