Refactor some method code
This commit is contained in:
parent
6ef2c65009
commit
0d3500ceb5
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,4 +11,4 @@ Cargo.lock
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
# Debug output of program
|
# Debug output of program
|
||||||
*.ppm
|
*.ppm
|
||||||
|
|
|
@ -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)
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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 } }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue