Refactor some method code

This commit is contained in:
bijan2005 2021-03-20 17:48:03 -04:00
parent 6ef2c65009
commit 0d3500ceb5
9 changed files with 38 additions and 50 deletions

2
.gitignore vendored
View file

@ -11,4 +11,4 @@ Cargo.lock
**/*.rs.bk **/*.rs.bk
# Debug output of program # Debug output of program
*.ppm *.ppm

View file

@ -36,15 +36,16 @@ fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()>
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
let camera = Camera::new(Point3::new(0.0,0.0,2.5), Vector3::new(0.0,0.0,-1.0), 1.0, 16.0 / 9.0, 2.0, 720); let camera = Camera::new(Point3::new(0.0,0.0,3.0), Vector3::new(0.0,0.0,-1.0), 1.0, 16.0 / 9.0, 2.0, 720);
let scene = Scene { let scene = Scene {
objects: vec![ objects: vec![
Object::new(Sphere::new(0.0, 0.0, 0.0, 1.0, |a, b| Texture::new(0.0, a, b, 1.0))) Object::new(Sphere::new_solid(1.0, 0.2, 1.7, 0.2, Texture::new(1.0, 1.0, 1.0, 1.0))),
Object::new(Sphere::new_solid(0.0, -1.0, 0.0, 1.0, Texture::new(1.0, 1.0, 1.0, 1.0)))
], ],
lights: vec![ lights: vec![
Box::new(PointLight::new(Point3::new(1.0, 0.7, 1.5), Color::white(), 3.0)), Box::new(PointLight::new(Point3::new(1.5, 1.0, 2.5), Color::white(), 3.0)),
Box::new(PointLight::new(Point3::new(-1.0, -0.3, 0.4), Color::new(1.0, 0.0, 0.0), 4.0)) Box::new(PointLight::new(Point3::new(1.0, -0.4, 1.5), Color::white(), 2.0))
], ],
background: Color::gray(0.5) background: Color::gray(0.5)
}; };

View file

@ -3,7 +3,7 @@ mod sphere; pub use sphere::*;
mod plane; pub use plane::*; mod plane; pub use plane::*;
mod triangle; pub use triangle::*; mod triangle; pub use triangle::*;
mod bound; pub use bound::*; mod bound; pub use bound::*;
mod pointlight; pub use pointlight::*; mod point_light; pub use point_light::*;
use crate::types::*; use crate::types::*;
@ -21,7 +21,7 @@ pub trait Surface {
// Takes in a point (assumed to be on the object's surface) // Takes in a point (assumed to be on the object's surface)
// and returns the texture information on that point. // and returns the texture information on that point.
fn gettexture(&self, point: Point3f) -> Texture; fn get_texture(&self, point: Point3f) -> Texture;
// Creates a bounding sphere around the object. // Creates a bounding sphere around the object.
fn bound(&self) -> Bound; fn bound(&self) -> Bound;
@ -38,7 +38,7 @@ impl Object {
let bound = surface.bound(); let bound = surface.bound();
Object { Object {
surface: Box::new(surface), surface: Box::new(surface),
bound: bound bound
} }
} }
@ -49,7 +49,7 @@ impl Object {
} else { None } } else { None }
} }
pub fn normal(&self, point: Point3f) -> Unit3f { self.surface.normal(point) } pub fn normal(&self, point: Point3f) -> Unit3f { self.surface.normal(point) }
pub fn gettexture(&self, point: Point3f) -> Texture { self.surface.gettexture(point) } pub fn get_texture(&self, point: Point3f) -> Texture { self.surface.get_texture(point) }
} }
pub trait Light { pub trait Light {
@ -57,7 +57,7 @@ pub trait Light {
fn check_shadow(&self, point: Point3f, objects: &Vec<Object>) -> bool; fn check_shadow(&self, point: Point3f, objects: &Vec<Object>) -> bool;
// Compute color on a point. // Compute color on a point.
fn getcolor(&self, point: Point3f) -> Color; fn get_color(&self, point: Point3f) -> Color;
// Compute intensity on a point. // Compute intensity on a point.
fn intensity(&self, point: Point3f) -> f32; fn intensity(&self, point: Point3f) -> f32;

View file

@ -24,7 +24,7 @@ impl Plane {
where F: Fn(f32, f32) -> Texture where F: Fn(f32, f32) -> Texture
{ {
Plane { Plane {
center: center, center,
normal: Unit::new_normalize(x_axis.cross(&y_axis)), normal: Unit::new_normalize(x_axis.cross(&y_axis)),
x_axis: x_axis, x_axis: x_axis,
y_axis: y_axis, y_axis: y_axis,
@ -77,7 +77,7 @@ impl Surface for Plane {
fn normal(&self, _point: Point3f) -> Unit3f { self.normal } fn normal(&self, _point: Point3f) -> Unit3f { self.normal }
fn gettexture(&self, point: Point3f) -> Texture { fn get_texture(&self, point: Point3f) -> Texture {
let rel_pos = point - self.center; let rel_pos = point - self.center;
let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos)); let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos));

View file

@ -14,11 +14,7 @@ pub struct PointLight {
#[allow(dead_code)] #[allow(dead_code)]
impl PointLight { impl PointLight {
pub fn new(pos: Point3f, color: Color, intensity: f32) -> PointLight { pub fn new(pos: Point3f, color: Color, intensity: f32) -> PointLight {
PointLight { PointLight { pos, color, intensity }
pos: pos,
color: color,
intensity: intensity
}
} }
} }
@ -26,11 +22,11 @@ impl Light for PointLight {
fn check_shadow(&self, point: Point3f, objects: &Vec<Object>) -> bool { fn check_shadow(&self, point: Point3f, objects: &Vec<Object>) -> bool {
let max_d = distance(&self.pos, &point); let max_d = distance(&self.pos, &point);
objects.iter() objects.iter()
.filter_map(|obj| obj.intersect(Ray::from_points(self.pos, point))) .filter_map(|&obj| obj.intersect(Ray::from_points(self.pos, point)))
.all(|d| d - max_d > -1e-3 ) .all(|d| d - max_d > -1e-3 )
} }
fn getcolor(&self, _point: Point3f) -> Color { self.color } fn get_color(&self, _point: Point3f) -> Color { self.color }
fn intensity(&self, _point: Point3f) -> f32 { self.intensity } fn intensity(&self, _point: Point3f) -> f32 { self.intensity }
@ -44,7 +40,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn pointlight_checkshadow() { fn point_light_check_shadow() {
let light = PointLight::new(Point3::new(0.0, 1.0, 0.0), Color::white(), 1.0); let light = PointLight::new(Point3::new(0.0, 1.0, 0.0), Color::white(), 1.0);
let block = Object::new(Sphere::new_solid(0.0, 0.5, 0.0, 0.1, Texture::new(0.0, 0.0, 0.0, 0.0))); let block = Object::new(Sphere::new_solid(0.0, 0.5, 0.0, 0.1, Texture::new(0.0, 0.0, 0.0, 0.0)));

View file

@ -23,8 +23,7 @@ impl Sphere {
where F: Fn(f32, f32) -> Texture where F: Fn(f32, f32) -> Texture
{ {
Sphere { Sphere {
center: Point3::new(x, y, z), center: Point3::new(x, y, z), radius,
radius: radius,
texture: Box::new(texture) texture: Box::new(texture)
} }
} }
@ -66,10 +65,10 @@ impl Surface for Sphere {
Unit::new_normalize(point - self.center) Unit::new_normalize(point - self.center)
} }
fn gettexture(&self, point: Point3f) -> Texture { fn get_texture(&self, point: Point3f) -> Texture {
let normal = self.normal(point); let normal = self.normal(point);
// In this particular case, the normal is simular to a point on a unit sphere // In this particular case, the normal is similar 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.
let x = 0.5 + normal.z.atan2(normal.x) / (2.0 * PI); let x = 0.5 + normal.z.atan2(normal.x) / (2.0 * PI);
@ -78,5 +77,5 @@ impl Surface for Sphere {
(*self.texture)(x, y) (*self.texture)(x, y)
} }
fn bound(&self) -> Bound { Bound::bypass() } fn bound(&self) -> Bound { Bound { center: self.center, radius: self.radius, bypass: false } }
} }

View file

@ -22,7 +22,7 @@ pub struct Triangle {
pub struct TriangleMesh { pub struct TriangleMesh {
pub vertices: Vec<Point3f>, pub vertices: Vec<Point3f>,
pub tris: Vec<Triangle> pub triangles: Vec<Triangle>
} }
fn tri_area(a: &Point3f, b: &Point3f, c: &Point3f) -> f32 { fn tri_area(a: &Point3f, b: &Point3f, c: &Point3f) -> f32 {
@ -78,7 +78,7 @@ impl Triangle {
self.intersect_(vertices, ray).map(|(t, u, v)| distance(&ray.origin, &self.from_bary(vertices, t, u, v))) self.intersect_(vertices, ray).map(|(t, u, v)| distance(&ray.origin, &self.from_bary(vertices, t, u, v)))
} }
fn gettexture(&self, vertices: &Vec<Point3f>, point: Point3f) -> Texture { fn get_texture(&self, vertices: &Vec<Point3f>, point: Point3f) -> Texture {
let (t, u, v) = self.to_bary(vertices, point); let (t, u, v) = self.to_bary(vertices, point);
(*self.texture)(t, u, v) (*self.texture)(t, u, v)
} }
@ -89,32 +89,27 @@ impl TriangleMesh {
pub fn new(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Texture>)>) -> Self { pub fn new(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize, Box<dyn Fn(f32, f32, f32) -> Texture>)>) -> Self {
let triangles = tris.into_iter() let triangles = tris.into_iter()
.map(|(v1, v2, v3, f)| Triangle { .map(|(v1, v2, v3, f)| Triangle {
v1: v1, v1, v2, v3,
v2: v2,
v3: v3,
normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))), normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))),
area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]), area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]),
texture: f texture: f
}).collect(); }).collect();
TriangleMesh { TriangleMesh {
vertices: vertices, vertices, triangles
tris: triangles
} }
} }
pub fn new_solid(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize)>, texture: Texture) -> Self { pub fn new_solid(vertices: Vec<Point3f>, tris: Vec<(usize, usize, usize)>, texture: Texture) -> Self {
let triangles = tris.into_iter() let triangles = tris.into_iter()
.map(|(v1, v2, v3)| Triangle { .map(|(v1, v2, v3)| Triangle {
v1: v1, v1, v2, v3,
v2: v2,
v3: v3,
normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))), normal: Unit::new_normalize((&vertices[v2] - &vertices[v1]).cross(&(&vertices[v3] - &vertices[v1]))),
area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]), area: tri_area(&vertices[v1], &vertices[v2], &vertices[v3]),
texture: Box::new(move |_, _, _| texture) texture: Box::new(move |_, _, _| texture)
}).collect(); }).collect();
TriangleMesh { TriangleMesh {
vertices: vertices, vertices,
tris: triangles triangles
} }
} }
@ -127,7 +122,7 @@ impl TriangleMesh {
fn closest_tri(&self, point: Point3f) -> &Triangle { fn closest_tri(&self, point: Point3f) -> &Triangle {
self.tris.iter() self.triangles.iter()
.map(move |tri| { .map(move |tri| {
let rel_pos = point - tri.vertex1(&self.vertices); let rel_pos = point - tri.vertex1(&self.vertices);
@ -150,7 +145,7 @@ impl TriangleMesh {
impl Surface for TriangleMesh { impl Surface for TriangleMesh {
fn intersect(&self, ray: Ray) -> Option<f32> { fn intersect(&self, ray: Ray) -> Option<f32> {
self.tris.iter() self.triangles.iter()
.filter_map(|tri| tri.intersect(&self.vertices, ray)) .filter_map(|tri| tri.intersect(&self.vertices, ray))
.min_by(|a, b| a.partial_cmp(&b).unwrap_or(Ordering::Equal)) .min_by(|a, b| a.partial_cmp(&b).unwrap_or(Ordering::Equal))
} }
@ -159,8 +154,8 @@ impl Surface for TriangleMesh {
self.closest_tri(point).normal self.closest_tri(point).normal
} }
fn gettexture(&self, point: Point3f) -> Texture { fn get_texture(&self, point: Point3f) -> Texture {
self.closest_tri(point).gettexture(&self.vertices, point) self.closest_tri(point).get_texture(&self.vertices, point)
} }
// Uses Welzl's algorithm to solve the bounding sphere problem // Uses Welzl's algorithm to solve the bounding sphere problem
@ -238,6 +233,6 @@ impl Surface for TriangleMesh {
let (center, radius) = smallest_sphere(points, Vec::new()); let (center, radius) = smallest_sphere(points, Vec::new());
Bound { center: center, radius: radius + 1e-3, bypass: false } Bound { center, radius: radius + 1e-3, bypass: false }
} }
} }

View file

@ -11,9 +11,9 @@ use crate::object::*;
fn trace(ray: Ray, objects: &Vec<Object>) -> Option<(&Object, f32)> { fn trace(ray: Ray, objects: &Vec<Object>) -> Option<(&Object, f32)> {
objects.iter() objects.iter()
.filter_map(|obj| obj.intersect(ray) .filter_map(|&obj| obj.intersect(ray)
.map(|x| (obj, x))) .map(|x| (obj, x)))
.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal)) .min_by(|&a, &b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal))
} }
fn light_point(objects: &Vec<Object>, obj: &Object, point: Point3f, light: &dyn Light) -> Color { fn light_point(objects: &Vec<Object>, obj: &Object, point: Point3f, light: &dyn Light) -> Color {
@ -34,7 +34,7 @@ pub fn cast_ray(ray: Ray, scene: &Scene) -> Color {
let surface_color = obj.gettexture(point).color; let surface_color = obj.gettexture(point).color;
scene.lights.iter() scene.lights.iter()
.map(|light| light_point(&scene.objects, obj, point, &**light)) .map(|&light| light_point(&scene.objects, obj, point, &*light))
.fold(Color::black(), |acc, c| acc + c) * surface_color .fold(Color::black(), |acc, c| acc + c) * surface_color
} }
else { scene.background } else { scene.background }

View file

@ -17,10 +17,7 @@ pub struct Ray {
impl Ray { impl Ray {
pub fn from_parts(origin: Point3f, direction: Unit3f) -> Self { pub fn from_parts(origin: Point3f, direction: Unit3f) -> Self {
Ray { Ray { origin, direction }
origin: origin,
direction: direction
}
} }
pub fn new(origin: Point3f, direction: Vector3f) -> Self { Ray::from_parts(origin, Unit::new_normalize(direction)) } 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 from_points(origin: Point3f, points_to: Point3f) -> Self { Ray::new(origin, points_to - origin) }
@ -109,7 +106,7 @@ impl Texture {
pub fn new(red: f32, green: f32, blue: f32, albedo: f32) -> Self { pub fn new(red: f32, green: f32, blue: f32, albedo: f32) -> Self {
Texture { Texture {
color: Color::new(red, green, blue), color: Color::new(red, green, blue),
albedo: albedo albedo
} }
} }
} }