diff --git a/src/object.rs b/src/object.rs index eaa73dd..eb7276e 100644 --- a/src/object.rs +++ b/src/object.rs @@ -19,11 +19,11 @@ pub trait Surface { // 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) -> Unit>; + fn normal(&self, point: Point3f) -> Unit3f; // 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) -> Color; + fn getcolor(&self, point: Point3f) -> Color; // Creates a bounding sphere around the object. fn bound(&self) -> Bound; @@ -50,14 +50,17 @@ impl Object { self.surface.intersect(ray) } else { None } } - pub fn normal(&self, point: Point3) -> Unit> { self.surface.normal(point) } - pub fn getcolor(&self, point: Point3) -> Color { self.surface.getcolor(point) } + pub fn normal(&self, point: Point3f) -> Unit3f { self.surface.normal(point) } + pub fn getcolor(&self, point: Point3f) -> Color { self.surface.getcolor(point) } } pub trait Light { // Determine if the light is able to illuminate the point. // If so, return the color of the light. - fn illuminate(&self, point: Point3, objects: &Vec) -> Option; + fn illuminate(&self, point: Point3f, objects: &Vec) -> Option; + + // Return the direction from the point to the light source. + fn direction(&self, point: Point3f) -> Unit3f; } pub struct Scene { diff --git a/src/object/bound.rs b/src/object/bound.rs index 04db378..49c0246 100644 --- a/src/object/bound.rs +++ b/src/object/bound.rs @@ -3,13 +3,13 @@ extern crate nalgebra as na; // use na::distance; use na::geometry::Point3; -use crate::types::Ray; +use crate::types::*; // A bounding sphere, used for // intersection test optimization. #[derive(Debug)] pub struct Bound { - pub center: Point3, + pub center: Point3f, pub radius: f32, // If true, then the bounding sphere is disabled. @@ -24,7 +24,7 @@ impl Bound { l.norm_squared() >= self.radius * self.radius } - // pub fn contains(&self, point: &Point3) -> bool { distance(&self.center, point) < self.radius } + // pub fn contains(&self, point: &Point3f) -> bool { distance(&self.center, point) < self.radius } pub fn bypass() -> Self { Bound { center: Point3::origin(), radius: 0.0, bypass: true } } } diff --git a/src/object/plane.rs b/src/object/plane.rs index 87f6a52..fca079d 100644 --- a/src/object/plane.rs +++ b/src/object/plane.rs @@ -7,11 +7,11 @@ use crate::types::*; use super::{Surface, bound::*}; pub struct Plane { - pub center: Point3, // Plane origin (used for texture mapping). - pub normal: Unit>, // Precomputed plane normal. + pub center: Point3f, // Plane origin (used for texture mapping). + pub normal: Unit3f, // Precomputed plane normal. - x_axis: Vector3, // Plane x-axis (The 3D direction that corresponds to the x-direction on the plane). - y_axis: Vector3, // Plane y-axis (The 3D direction that corresponds to the y-direction on the plane). + x_axis: Vector3f, // Plane x-axis (The 3D direction that corresponds to the x-direction on the plane). + y_axis: Vector3f, // Plane y-axis (The 3D direction that corresponds to the y-direction on the plane). texture: Box Color> // Texture map. // Input coordinates are defined in terms of the axes above. @@ -20,7 +20,7 @@ pub struct Plane { #[allow(dead_code)] impl Plane { // Creates a new plane. - pub fn new(center: Point3, x_axis: Vector3, y_axis: Vector3, texture: F) -> Self + pub fn new(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self where F: Fn(f32, f32) -> Color { Plane { @@ -33,7 +33,7 @@ impl Plane { } // Creates a new plane with the normal flipped. - pub fn new_flip(center: Point3, x_axis: Vector3, y_axis: Vector3, texture: F) -> Self + pub fn new_flip(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, texture: F) -> Self where F: Fn(f32, f32) -> Color { Plane { @@ -46,11 +46,11 @@ impl Plane { } // Creates a new plane of a solid color. - pub fn new_solid(center: Point3, x_axis: Vector3, y_axis: Vector3, color: Color) -> Self + pub fn new_solid(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, color: Color) -> Self { 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, x_axis: Vector3, y_axis: Vector3, color: Color) -> Self + pub fn new_solid_flip(center: Point3f, x_axis: Vector3f, y_axis: Vector3f, color: Color) -> Self { Plane::new_flip(center, x_axis, y_axis, move |_, _| color) } @@ -75,9 +75,9 @@ impl Surface for Plane { else { None } } - fn normal(&self, _point: Point3) -> Unit> { self.normal } + fn normal(&self, _point: Point3f) -> Unit3f { self.normal } - fn getcolor(&self, point: Point3) -> Color { + fn getcolor(&self, point: Point3f) -> Color { let rel_pos = point - self.center; let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos)); diff --git a/src/object/pointlight.rs b/src/object/pointlight.rs index 607fb02..b8f0d1f 100644 --- a/src/object/pointlight.rs +++ b/src/object/pointlight.rs @@ -7,19 +7,21 @@ use crate::types::*; use super::*; pub struct PointLight { - pub pos: Point3, - pub color: Color + pub pos: Point3f, + pub color: Color, + pub intensity: f32 } impl PointLight { - pub fn new(pos: Point3, color: Color) -> PointLight { + pub fn new(pos: Point3f, color: Color, intensity: f32) -> PointLight { PointLight { pos: pos, - color: color + color: color, + intensity: intensity } } - fn check_point(&self, point: Point3, objects: &Vec) -> bool { + fn check_point(&self, point: Point3f, objects: &Vec) -> bool { let max_d = distance(&self.pos, &point); objects.iter() .filter_map(|obj| obj.intersect(Ray::from_points(self.pos, point))) @@ -28,9 +30,13 @@ impl PointLight { } impl Light for PointLight { - fn illuminate(&self, point: Point3, objects: &Vec) -> Option { + fn illuminate(&self, point: Point3f, objects: &Vec) -> Option { if self.check_point(point, objects) { Some(self.color) } else { None } } + + fn direction(&self, point: Point3f) -> Unit3f { + Unit::new_normalize(self.pos - point) + } } diff --git a/src/object/sphere.rs b/src/object/sphere.rs index 9cf01f3..7e20c63 100644 --- a/src/object/sphere.rs +++ b/src/object/sphere.rs @@ -9,7 +9,7 @@ use crate::types::*; use super::{Surface, bound::*}; pub struct Sphere { - pub center: Point3, // Center point of the sphere. + pub center: Point3f, // Center point of the sphere. pub radius: f32, // Radius of the sphere. texture: Box Color> // Texture map. @@ -62,11 +62,11 @@ impl Surface for Sphere { else { None } } - fn normal(&self, point: Point3) -> Unit> { + fn normal(&self, point: Point3f) -> Unit3f { Unit::new_normalize(point - self.center) } - fn getcolor(&self, point: Point3) -> Color { + fn getcolor(&self, point: Point3f) -> Color { let normal = self.normal(point); // In this particular case, the normal is simular to a point on a unit sphere diff --git a/src/object/triangle.rs b/src/object/triangle.rs index a759dc6..6f109ed 100644 --- a/src/object/triangle.rs +++ b/src/object/triangle.rs @@ -13,7 +13,7 @@ pub struct Triangle { pub v2: usize, pub v3: usize, - normal: Unit>, // Precalculated normal vector. + normal: Unit3f, // Precalculated normal vector. area: f32, // Precalculated area for barycentric calculations. texture: Box Color> // Texture map. @@ -21,28 +21,28 @@ pub struct Triangle { } pub struct TriangleMesh { - pub vertices: Vec>, + pub vertices: Vec, pub tris: Vec } -fn tri_area(a: &Point3, b: &Point3, c: &Point3) -> f32 { +fn tri_area(a: &Point3f, b: &Point3f, c: &Point3f) -> f32 { let prlg_area: f32 = (b - a).cross(&(c - a)).norm(); prlg_area / 2.0 } impl Triangle { - fn vertex1<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v1] } - fn vertex2<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v2] } - fn vertex3<'a>(&self, vertices: &'a Vec>) -> &'a Point3 { &vertices[self.v3] } + fn vertex1<'a>(&self, vertices: &'a Vec) -> &'a Point3f { &vertices[self.v1] } + fn vertex2<'a>(&self, vertices: &'a Vec) -> &'a Point3f { &vertices[self.v2] } + fn vertex3<'a>(&self, vertices: &'a Vec) -> &'a Point3f { &vertices[self.v3] } // Conversion of barycentric coordinates to // a point on the triangle. - fn from_bary(&self, vertices: &Vec>, t: f32, u: f32, v: f32) -> Point3 { + fn from_bary(&self, vertices: &Vec, t: f32, u: f32, v: f32) -> Point3f { Point::from(t * self.vertex1(vertices).coords + u * self.vertex2(vertices).coords + v * self.vertex3(vertices).coords) } // Conversion of a point to barycentric coordinates. - fn to_bary(&self, vertices: &Vec>, point: Point3) -> (f32, f32, f32) { + fn to_bary(&self, vertices: &Vec, point: Point3f) -> (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; @@ -50,7 +50,7 @@ impl Triangle { (t, u, v) } - fn intersect_(&self, vertices: &Vec>, ray: Ray) -> Option<(f32, f32, f32)> { + fn intersect_(&self, vertices: &Vec, ray: Ray) -> Option<(f32, f32, f32)> { let vect2_1 = self.vertex2(vertices) - self.vertex1(vertices); let vect3_1 = self.vertex3(vertices) - self.vertex1(vertices); @@ -74,11 +74,11 @@ impl Triangle { Some((t, u, v)) } - fn intersect(&self, vertices: &Vec>, ray: Ray) -> Option { + fn intersect(&self, vertices: &Vec, ray: Ray) -> Option { self.intersect_(vertices, ray).map(|(t, u, v)| distance(&ray.origin, &self.from_bary(vertices, t, u, v))) } - fn getcolor(&self, vertices: &Vec>, point: Point3) -> Color { + fn getcolor(&self, vertices: &Vec, point: Point3f) -> Color { let (t, u, v) = self.to_bary(vertices, point); (*self.texture)(t, u, v) } @@ -86,7 +86,7 @@ impl Triangle { #[allow(dead_code)] impl TriangleMesh { - pub fn new(vertices: Vec>, tris: Vec<(usize, usize, usize, Box Color>)>) -> Self { + pub fn new(vertices: Vec, tris: Vec<(usize, usize, usize, Box Color>)>) -> Self { let triangles = tris.into_iter() .map(|(v1, v2, v3, f)| Triangle { v1: v1, @@ -102,7 +102,7 @@ impl TriangleMesh { } } - pub fn new_solid(vertices: Vec>, tris: Vec<(usize, usize, usize)>, color: Color) -> Self { + pub fn new_solid(vertices: Vec, tris: Vec<(usize, usize, usize)>, color: Color) -> Self { let triangles = tris.into_iter() .map(|(v1, v2, v3)| Triangle { v1: v1, @@ -118,15 +118,15 @@ impl TriangleMesh { } } - pub fn singleton(vertex1: Point3, vertex2: Point3, vertex3: Point3, texture: F) -> Self + pub fn singleton(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, texture: F) -> Self where F: Fn(f32, f32, f32) -> Color { TriangleMesh::new(vec![vertex1, vertex2, vertex3], vec![(0, 1, 2, Box::new(texture))]) } - pub fn singleton_solid(vertex1: Point3, vertex2: Point3, vertex3: Point3, color: Color) -> Self + pub fn singleton_solid(vertex1: Point3f, vertex2: Point3f, vertex3: Point3f, color: Color) -> Self { TriangleMesh::singleton(vertex1, vertex2, vertex3, move |_, _, _| color) } - fn closest_tri(&self, point: Point3) -> &Triangle { + fn closest_tri(&self, point: Point3f) -> &Triangle { self.tris.iter() .map(move |tri| { @@ -155,17 +155,17 @@ impl Surface for TriangleMesh { .min_by(|a, b| a.partial_cmp(&b).unwrap_or(Ordering::Equal)) } - fn normal(&self, point: Point3) -> Unit> { + fn normal(&self, point: Point3f) -> Unit3f { self.closest_tri(point).normal } - fn getcolor(&self, point: Point3) -> Color { + fn getcolor(&self, point: Point3f) -> Color { self.closest_tri(point).getcolor(&self.vertices, point) } // Uses Welzl's algorithm to solve the bounding sphere problem fn bound(&self) -> Bound { - fn triangle_sphere(point1: &Point3, point2: &Point3, point3: &Point3) -> (Point3, f32) { + fn triangle_sphere(point1: &Point3f, point2: &Point3f, point3: &Point3f) -> (Point3f, f32) { let a = point3 - point1; let b = point2 - point1; @@ -179,7 +179,7 @@ impl Surface for TriangleMesh { (point1 + to_center, radius) } - fn tetrahedron_sphere(point1: &Point3, point2: &Point3, point3: &Point3, point4: &Point3) -> (Point3, f32) { + fn tetrahedron_sphere(point1: &Point3f, point2: &Point3f, point3: &Point3f, point4: &Point3f) -> (Point3f, f32) { let matrix = Matrix4::from_rows(&[point1.to_homogeneous().transpose(), point2.to_homogeneous().transpose(), point3.to_homogeneous().transpose(), @@ -204,7 +204,7 @@ impl Surface for TriangleMesh { (center, radius) } - fn smallest_sphere(points: Vec<&Point3>, boundary: Vec<&Point3>) -> (Point3, f32) { + fn smallest_sphere(points: Vec<&Point3f>, boundary: Vec<&Point3f>) -> (Point3f, f32) { if points.len() == 0 || boundary.len() == 4 { match boundary.len() { 0 => (Point3::new(0.0, 0.0, 0.0), 0.0), @@ -233,7 +233,7 @@ impl Surface for TriangleMesh { use rand::thread_rng; use rand::seq::SliceRandom; - let mut points: Vec<&Point3> = self.vertices.iter().collect(); + let mut points: Vec<&Point3f> = self.vertices.iter().collect(); points.shuffle(&mut thread_rng()); let (center, radius) = smallest_sphere(points, Vec::new()); diff --git a/src/render.rs b/src/render.rs index 1867e3a..133b7d8 100644 --- a/src/render.rs +++ b/src/render.rs @@ -18,8 +18,8 @@ fn trace(ray: Ray, objects: &Vec) -> Option<(&Object, f32)> { pub fn cast_ray(ray: Ray, scene: &Scene) -> Color { if let Some((obj, dist)) = trace(ray, &scene.objects) { let point = ray.project(dist); - - obj.getcolor(point) + let surface_color = obj.getcolor(point); + surface_color } else { scene.background } } diff --git a/src/types.rs b/src/types.rs index 2e97a97..5594066 100644 --- a/src/types.rs +++ b/src/types.rs @@ -5,23 +5,27 @@ use std::ops::{Add, Mul}; use na::*; use na::geometry::Point3; +pub type Point3f = Point3; +pub type Vector3f = Vector3; +pub type Unit3f = Unit>; + #[derive(Clone, Copy, Debug)] pub struct Ray { - pub origin: Point3, - pub direction: Unit> + pub origin: Point3f, + pub direction: Unit3f } impl Ray { - pub fn from_parts(origin: Point3, direction: Unit>) -> Self { + pub fn from_parts(origin: Point3f, direction: Unit3f) -> Self { Ray { origin: origin, direction: direction } } - pub fn new(origin: Point3, direction: Vector3) -> Self { Ray::from_parts(origin, Unit::new_normalize(direction)) } - pub fn from_points(origin: Point3, points_to: Point3) -> Self { Ray::new(origin, points_to - origin) } + pub fn new(origin: Point3f, direction: Vector3f) -> Self { Ray::from_parts(origin, Unit::new_normalize(direction)) } + pub fn from_points(origin: Point3f, points_to: Point3f) -> Self { Ray::new(origin, points_to - origin) } - pub fn project(&self, t: f32) -> Point3 { self.origin + t * self.direction.into_inner() } + pub fn project(&self, t: f32) -> Point3f { self.origin + t * self.direction.into_inner() } } #[derive(Clone, Copy, Debug, PartialEq)]