Add color mapping to planes

This commit is contained in:
bijan2005 2020-11-30 11:56:55 -05:00
parent ff625f576f
commit 639518c317
8 changed files with 99 additions and 35 deletions

View file

@ -14,10 +14,10 @@ This list may be changed or extended in the future.
- [x] Sphere intersection test - [x] Sphere intersection test
- [x] Sphere normal generation - [x] Sphere normal generation
- [x] Color mapping on spheres - [x] Color mapping on spheres
- [ ] Plane objects - [x] Plane objects
- [x] Plane struct - [x] Plane struct
- [x] Plane intersection test - [x] Plane intersection test
- [ ] Color mapping on planes - [x] Color mapping on planes
- [ ] Triangle objects - [ ] Triangle objects
- [ ] Triangle struct - [ ] Triangle struct
- [ ] Triangle intersection test - [ ] Triangle intersection test

View file

@ -17,11 +17,11 @@ pub struct Camera {
} }
impl Camera { impl Camera {
// Constructs a new camera from a position and viewing direction
// (assuming the camera is oriented upright). // Constructs a new camera from a position and viewing direction.
pub fn new(pos: Point3<f32>, dir: Vector3<f32>, focal_length: f32, pub fn new_(pos: Point3<f32>, dir: Vector3<f32>, up: Vector3<f32>, focal_length: f32,
canvas_x: f32, canvas_y: f32, image_x: u32, image_y: u32) -> Self { 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 { Camera {
matrix: iso, matrix: iso,
focal_length: focal_length, 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<f32>, dir: Vector3<f32>, 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<f32> { Point3::from(self.matrix.translation.vector) } pub fn pos(&self) -> Point3<f32> { Point3::from(self.matrix.translation.vector) }
// Takes a 2D point in the image space and // Takes a 2D point in the image space and

View file

@ -52,10 +52,12 @@ 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,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![ 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") render(&camera, &scene, "out.ppm")

View file

@ -1,5 +1,4 @@
mod base; pub use base::*;
mod sphere; pub use sphere::*; 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::*;
@ -8,6 +7,14 @@ use na::*;
use crate::types::*; use crate::types::*;
pub trait Surface {
fn intersect(&self, ray: Ray) -> Option<f32>;
fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>>;
fn getcolor(&self, point: Point3<f32>) -> Color;
}
pub struct Object { pub struct Object {
pub surface: Box<dyn Surface> pub surface: Box<dyn Surface>
} }
@ -23,3 +30,17 @@ impl Object {
} }
pub type Scene = Vec<Object>; pub type Scene = Vec<Object>;
#[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());
}
}

View file

@ -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<f32>;
fn normal(&self, point: Point3<f32>) -> Unit<Vector3<f32>>;
fn getcolor(&self, point: Point3<f32>) -> Color;
}

View file

@ -4,28 +4,38 @@ use na::*;
use na::geometry::Point3; use na::geometry::Point3;
use crate::types::*; use crate::types::*;
use super::base::*; use super::Surface;
pub struct Plane { pub struct Plane {
pub center: Point3<f32>, pub center: Point3<f32>,
pub normal: Unit<Vector3<f32>>, pub normal: Unit<Vector3<f32>>,
pub texture: Box<dyn Fn(f32, f32) -> Color> x_axis: Vector3<f32>,
y_axis: Vector3<f32>,
texture: Box<dyn Fn(f32, f32) -> Color>
} }
impl Plane { impl Plane {
pub fn new<F: 'static>(center: Point3<f32>, normal: 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
{ {
Plane { Plane {
center: center, 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) texture: Box::new(texture)
} }
} }
pub fn new_solid(center: Point3<f32>, normal: 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, normal, move |_, _| color) } { Plane::new(center, x_axis, y_axis, move |_, _| color) }
pub fn xy<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::y(), texture) }
pub fn xz<F: 'static + Fn(f32, f32) -> Color>(texture: F) -> Self
{ Plane::new(Point3::origin(), Vector3::x(), Vector3::z(), texture) }
} }
impl Surface for Plane { impl Surface for Plane {
@ -43,6 +53,45 @@ impl Surface for Plane {
fn normal(&self, _point: Point3<f32>) -> Unit<Vector3<f32>> { self.normal } fn normal(&self, _point: Point3<f32>) -> Unit<Vector3<f32>> { self.normal }
fn getcolor(&self, point: Point3<f32>) -> Color { fn getcolor(&self, point: Point3<f32>) -> 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));
} }
} }

View file

@ -6,13 +6,13 @@ use na::*;
use na::geometry::Point3; use na::geometry::Point3;
use crate::types::*; use crate::types::*;
use super::base::*; use super::Surface;
pub struct Sphere { pub struct Sphere {
pub center: Point3<f32>, pub center: Point3<f32>,
pub radius: f32, pub radius: f32,
pub texture: Box<dyn Fn(f32, f32) -> Color> texture: Box<dyn Fn(f32, f32) -> Color>
} }
impl Sphere { impl Sphere {
@ -54,8 +54,8 @@ impl Surface for Sphere {
if t0 > t1 { std::mem::swap(&mut t0, &mut t1); } if t0 > t1 { std::mem::swap(&mut t0, &mut t1); }
if t0 > 0.0 { Some(t0) } if t0 >= 0.0 { Some(t0) }
else if t1 > 0.0 { Some(t1) } else if t1 >= 0.0 { Some(t1) }
else { None } else { None }
} }

View file

@ -21,7 +21,7 @@ impl Ray {
pub fn project(&self, t: f32) -> Point3<f32> { self.origin + t * self.direction.into_inner() } pub fn project(&self, t: f32) -> Point3<f32> { self.origin + t * self.direction.into_inner() }
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Color { pub struct Color {
pub red: f32, pub red: f32,
pub green: f32, pub green: f32,