From 639518c31722c2ec8b784640208eabfcfac3ffa0 Mon Sep 17 00:00:00 2001 From: bijan2005 Date: Mon, 30 Nov 2020 11:56:55 -0500 Subject: [PATCH] Add color mapping to planes --- README.md | 4 +-- src/camera.rs | 14 +++++++--- src/main.rs | 6 +++-- src/object.rs | 23 +++++++++++++++- src/object/base.rs | 14 ---------- src/object/plane.rs | 63 +++++++++++++++++++++++++++++++++++++++----- src/object/sphere.rs | 8 +++--- src/types.rs | 2 +- 8 files changed, 99 insertions(+), 35 deletions(-) delete mode 100644 src/object/base.rs diff --git a/README.md b/README.md index c019091..2a660ce 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ This list may be changed or extended in the future. - [x] Sphere intersection test - [x] Sphere normal generation - [x] Color mapping on spheres -- [ ] Plane objects +- [x] Plane objects - [x] Plane struct - [x] Plane intersection test - - [ ] Color mapping on planes + - [x] Color mapping on planes - [ ] Triangle objects - [ ] Triangle struct - [ ] Triangle intersection test diff --git a/src/camera.rs b/src/camera.rs index b3adcca..8d9e776 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -17,11 +17,11 @@ pub struct Camera { } impl Camera { - // Constructs a new camera from a position and viewing direction - // (assuming the camera is oriented upright). - pub fn new(pos: Point3, dir: Vector3, focal_length: f32, + + // Constructs a new camera from a position and viewing direction. + pub fn new_(pos: Point3, dir: Vector3, up: Vector3, focal_length: f32, canvas_x: f32, canvas_y: f32, image_x: u32, image_y: u32) -> Self { - let iso = Isometry3::face_towards(&pos, &(pos + dir), &Vector3::y()); + let iso = Isometry3::face_towards(&pos, &(pos + dir), &up); Camera { matrix: iso, focal_length: focal_length, @@ -30,6 +30,12 @@ impl Camera { } } + // Constructs a new camera from a position and viewing direction + // (assuming the camera is oriented upright). + pub fn new(pos: Point3, dir: Vector3, focal_length: f32, + canvas_x: f32, canvas_y: f32, image_x: u32, image_y: u32) -> Self + { Camera::new_(pos, dir, Vector3::y(), focal_length, canvas_x, canvas_y, image_x, image_y) } + pub fn pos(&self) -> Point3 { Point3::from(self.matrix.translation.vector) } // Takes a 2D point in the image space and diff --git a/src/main.rs b/src/main.rs index e2fe974..5a0036d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,10 +52,12 @@ fn render(camera: &Camera, scene: &Scene, filename: &str) -> std::io::Result<()> fn main() -> std::io::Result<()> { - let camera = Camera::new(Point3::new(0.0,0.0,0.0), Vector3::new(0.0,0.0,-1.0), 1.0, 2.0, 2.0, 500, 500); + let camera = Camera::new(Point3::new(0.0,1.0,0.0), Vector3::new(0.0,0.0,1.0), 1.0, 2.0, 2.0, 500, 500); let scene = vec![ - Object::new(Sphere::new(0.0,0.0,-3.0,2.0, |x, y| Color::new(x, 0.0, y * 2.0))) + Object::new(Plane::xz(|x, y| Color::new(y.sin(), x.cos(), 0.0))), + Object::new(Plane::new(Point3::new(0.0, 2.0, 0.0), Vector3::z(), Vector3::x(), |x, y| Color::new(x.sin(), y.cos(), 0.0))) + // Object::new(Sphere::new_solid(0.0, 0.0, 0.0, 3.0, Color::white())) ]; render(&camera, &scene, "out.ppm") diff --git a/src/object.rs b/src/object.rs index 6b7d272..42bf6e2 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,5 +1,4 @@ -mod base; pub use base::*; mod sphere; pub use sphere::*; mod plane; pub use plane::*; mod triangle; pub use triangle::*; @@ -8,6 +7,14 @@ use na::*; use crate::types::*; +pub trait Surface { + fn intersect(&self, ray: Ray) -> Option; + + fn normal(&self, point: Point3) -> Unit>; + + fn getcolor(&self, point: Point3) -> Color; +} + pub struct Object { pub surface: Box } @@ -23,3 +30,17 @@ impl Object { } pub type Scene = Vec; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn obj_getcolor() { + let sphere = Object::new(Sphere::new_solid(0.0, 0.0, 0.0, 1.0, Color::white())); + + let point = Point3::new(1.0, 0.0, 0.0); + + assert_eq!(sphere.getcolor(point), Color::white()); + } +} diff --git a/src/object/base.rs b/src/object/base.rs deleted file mode 100644 index c8489ce..0000000 --- a/src/object/base.rs +++ /dev/null @@ -1,14 +0,0 @@ -extern crate nalgebra as na; - -use na::*; -use na::geometry::Point3; - -use crate::types::*; - -pub trait Surface { - fn intersect(&self, ray: Ray) -> Option; - - fn normal(&self, point: Point3) -> Unit>; - - fn getcolor(&self, point: Point3) -> Color; -} diff --git a/src/object/plane.rs b/src/object/plane.rs index a32a039..c6fdffc 100644 --- a/src/object/plane.rs +++ b/src/object/plane.rs @@ -4,28 +4,38 @@ use na::*; use na::geometry::Point3; use crate::types::*; -use super::base::*; +use super::Surface; pub struct Plane { pub center: Point3, pub normal: Unit>, - pub texture: Box Color> + x_axis: Vector3, + y_axis: Vector3, + texture: Box Color> } impl Plane { - pub fn new(center: Point3, normal: Vector3, texture: F) -> Self + pub fn new(center: Point3, x_axis: Vector3, y_axis: Vector3, texture: F) -> Self where F: Fn(f32, f32) -> Color { Plane { center: center, - normal: Unit::new_normalize(normal), + normal: Unit::new_normalize(x_axis.cross(&y_axis)), + x_axis: x_axis, + y_axis: y_axis, texture: Box::new(texture) } } - pub fn new_solid(center: Point3, normal: Vector3, color: Color) -> Self - { Plane::new(center, normal, move |_, _| color) } + pub fn new_solid(center: Point3, x_axis: Vector3, y_axis: Vector3, color: Color) -> Self + { Plane::new(center, x_axis, y_axis, move |_, _| color) } + + pub fn xy Color>(texture: F) -> Self + { Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) } + + pub fn xz Color>(texture: F) -> Self + { Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) } } impl Surface for Plane { @@ -43,6 +53,45 @@ impl Surface for Plane { fn normal(&self, _point: Point3) -> Unit> { self.normal } fn getcolor(&self, point: Point3) -> Color { - unimplemented!() + let rel_pos = point - self.center; + let proj_point3 = rel_pos - (*self.normal * self.normal.dot(&rel_pos)); + + let x = proj_point3.dot(&self.x_axis); + let y = proj_point3.dot(&self.y_axis); + + (*self.texture)(x, y) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn plane_new() { + let plane = Plane::xy(|_, _| Color::black()); + + assert_eq!(plane.center, Point3::new(0.0, 0.0, 0.0)); + assert_eq!(plane.normal, Unit::new_unchecked(Vector3::z())); + } + + #[test] + fn plane_intersect() { + const N: f32 = 5.0; + let plane = Plane::xz(|_, _| Color::black()); + + let ray = Ray::new(Point3::new(0.0, N, 0.0), Vector3::new(0.0, -1.0, 0.0)); + + assert_eq!(plane.intersect(ray), Some(N)); + } + + #[test] + fn plane_getcolor() { + const N: f32 = 5.0; + let plane = Plane::xz(|x, y| Color::new(x, y, 0.0)); + + let point = Point3::new(5.0, 7.0, 6.0); + + assert_eq!(plane.getcolor(point), Color::new(5.0, 6.0, 0.0)); } } diff --git a/src/object/sphere.rs b/src/object/sphere.rs index b91848d..fa04633 100644 --- a/src/object/sphere.rs +++ b/src/object/sphere.rs @@ -6,13 +6,13 @@ use na::*; use na::geometry::Point3; use crate::types::*; -use super::base::*; +use super::Surface; pub struct Sphere { pub center: Point3, pub radius: f32, - pub texture: Box Color> + texture: Box Color> } impl Sphere { @@ -54,8 +54,8 @@ impl Surface for Sphere { if t0 > t1 { std::mem::swap(&mut t0, &mut t1); } - if t0 > 0.0 { Some(t0) } - else if t1 > 0.0 { Some(t1) } + if t0 >= 0.0 { Some(t0) } + else if t1 >= 0.0 { Some(t1) } else { None } } diff --git a/src/types.rs b/src/types.rs index eed0554..9e14623 100644 --- a/src/types.rs +++ b/src/types.rs @@ -21,7 +21,7 @@ impl Ray { pub fn project(&self, t: f32) -> Point3 { self.origin + t * self.direction.into_inner() } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Color { pub red: f32, pub green: f32,