From 86303936ab3180828b984ebb256bab8e69dab5cf Mon Sep 17 00:00:00 2001 From: Julian T Date: Sat, 30 Jan 2021 15:37:07 +0100 Subject: Finished initial film, reorganization and started work on shapes --- src/bound.rs | 108 ------------------------------------------ src/camera/film.rs | 92 ++++++++++++++++++++++++------------ src/camera/mod.rs | 2 +- src/core/bound.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++ src/core/mod.rs | 11 +++++ src/core/ray.rs | 6 +++ src/core/spectrum.rs | 35 ++++++++++++++ src/core/vector2.rs | 110 +++++++++++++++++++++++++++++++++++++++++++ src/core/vector3.rs | 47 +++++++++++++++++++ src/lib.rs | 5 +- src/main.rs | 10 ++-- src/scene/mod.rs | 3 ++ src/scene/shapes/mod.rs | 12 +++++ src/scene/shapes/sphere.rs | 16 +++++++ src/spectrum.rs | 13 ------ src/vector.rs | 110 ------------------------------------------- 16 files changed, 423 insertions(+), 271 deletions(-) delete mode 100644 src/bound.rs create mode 100644 src/core/bound.rs create mode 100644 src/core/mod.rs create mode 100644 src/core/ray.rs create mode 100644 src/core/spectrum.rs create mode 100644 src/core/vector2.rs create mode 100644 src/core/vector3.rs create mode 100644 src/scene/mod.rs create mode 100644 src/scene/shapes/mod.rs create mode 100644 src/scene/shapes/sphere.rs delete mode 100644 src/spectrum.rs delete mode 100644 src/vector.rs diff --git a/src/bound.rs b/src/bound.rs deleted file mode 100644 index ab0e703..0000000 --- a/src/bound.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::{Number, Float}; -use crate::vector::*; - -pub struct Bound2 { - pub min: Vector2, - pub max: Vector2 -} - -pub type Bound2i = Bound2; -pub type Bound2f = Bound2; - -fn min (a: T, b: T) -> T { - if b < a { - return b; - } - a -} - -fn max (a: T, b: T) -> T { - if b > a { - return b; - } - a -} - -impl Bound2 { - pub fn new(p0: &Vector2, p1: &Vector2) -> Self { - let min = Vector2::new_xy(min(p0.x, p1.x), min(p0.y, p1.y)); - let max = Vector2::new_xy(max(p0.x, p1.x), max(p0.y, p1.y)); - - Self { min, max } - } - - pub fn new_xyxy(x1: T, y1: T, x2: T, y2: T) -> Self { - Self::new( - &Vector2::new_xy(x1, y1), - &Vector2::new_xy(x2, y2), - ) - } - - pub fn diagonal(&self) -> Vector2 { - self.max - self.min - } - - pub fn area(&self) -> T { - let diag = self.diagonal(); - return diag.x * diag.y; - } -} - -impl From<&Bound2i> for Bound2f { - fn from(b: &Bound2i) -> Self { - Self { - min: Vector2f::from(b.min), - max: Vector2f::from(b.max), - } - } -} - -impl From<&Bound2f> for Bound2i { - fn from(b: &Bound2f) -> Self { - Self { - min: Vector2i::from(b.min), - max: Vector2i::from(b.max), - } - } -} - -pub fn intersect(a: &Bound2, b: &Bound2) -> Bound2 { - Bound2::new( - &Vector2::new_xy(max(a.min.x, b.min.x), max(a.min.y, b.min.y)), - &Vector2::new_xy(min(a.max.x, b.max.x), min(a.max.y, b.max.y)), - ) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn create_test() -> Bound2 { - Bound2::new( - &Vector2::new_xy(1, 2), - &Vector2::new_xy(10, 3) - ) - } - - #[test] - fn area() { - let b = create_test(); - - assert!(b.area() == 9); - } - - #[test] - fn intersect_test() { - let b1 = Bound2i::new_xyxy(10, 10, 20, 20); - let b2 = Bound2i::new_xyxy(2, 11, 22, 17); - - let b = intersect(&b1, &b2); - - assert!( - b.min.x == 10 && - b.min.y == 11 && - b.max.x == 20 && - b.max.y == 17 - ) - } -} diff --git a/src/camera/film.rs b/src/camera/film.rs index 6661529..1d87399 100644 --- a/src/camera/film.rs +++ b/src/camera/film.rs @@ -1,67 +1,101 @@ -use crate::vector::*; +use crate::core::*; use crate::Float; -use crate::bound; -use crate::spectrum::Spectrum; - -use bound::{Bound2i, Bound2f}; -use super::filter::Filter; -use std::rc::Rc; #[derive(Clone)] pub struct Pixel { - pub rgb: [Float; 3], + rgb: Spectrum, + samples: u32, } pub struct Film { - pub resolution: Vector2i, + size: Vector2i, drawingBound: Bound2i, pixels: Vec, - filter: Rc, } pub struct FilmTile { - pub bounds: Bound2i, - filter: Rc, + bounds: Bound2i, + size: Vector2i, + + pixels: Vec, } +//const HalfPixel = Vector2f::new(0.5); + impl Pixel { fn new() -> Pixel { - Pixel { rgb: [0.0, 0.0, 0.0] } + Pixel { + rgb: Default::default(), + samples: 0, + } + } + + fn add(&mut self, c: &Spectrum, weight: Float) { + self.rgb += &(c * weight); + self.samples += 1; + } +} + +impl std::ops::AddAssign<&Self> for Pixel { + fn add_assign(&mut self, op: &Self) { + self.rgb += &op.rgb; + self.samples += op.samples; } } impl Film { - pub fn new(resolution: Vector2i, filter: Rc) -> Film { - let area = resolution.x * resolution.y; + pub fn new(size: Vector2i) -> Film { + let area = size.x * size.y; Film { - resolution, - drawingBound: Bound2i::new(&Vector2::new(0), &resolution), + size, + drawingBound: Bound2i::new(&Vector2i::new(0), &size), pixels: vec![Pixel::new(); area as usize], - filter, } } pub fn get_tile(&self, bound: &Bound2i) -> FilmTile { - // Used to calculate descrete coordinates into continues - let halfpixel = Vector2f::new_xy(0.5, 0.5); - let fbound = Bound2f::from(bound); + FilmTile::new( + bound, + ) + + } - let p0 = Vector2i::from((fbound.min - halfpixel - self.filter.radius).ceil()); - let p1 = Vector2i::from((fbound.min - halfpixel + self.filter.radius).floor()); + pub fn commit_tile(&mut self, tile: &FilmTile) { + let offset = tile.bounds.min; - let tilebound = bound::intersect(&Bound2i::new(&p0, &p1), &self.drawingBound); + for y in 0 ..= tile.size.y { + let rowindex = (offset.y + y) * self.size.x; + let prowindex = y * tile.size.x; - FilmTile { - bounds: tilebound, - filter: self.filter.clone(), + for x in 0 ..= tile.size.x { + let index = offset.x + x + rowindex; + let pindex: i32 = x + prowindex; + + self.pixels[index as usize] += &tile.pixels[pindex as usize]; + } } } } impl FilmTile { - fn add_sample(point: &Vector2f, c: Spectrum) { - + fn new(bounds: &Bound2i) -> FilmTile { + FilmTile { + bounds: bounds.clone(), + pixels: vec![Pixel::new(); bounds.area() as usize], + size: bounds.diagonal(), + } + } + + pub fn add_sample(&mut self, point: &Vector2f, c: Spectrum) { + let point = Vector2i::from(point.floor()); + // Subtract the offset + let point = point - self.bounds.min; + + let index = point.x + point.y * self.size.x; + + let pixel = self.pixels.get_mut(index as usize).unwrap(); + pixel.add(&c, 1.0); } } diff --git a/src/camera/mod.rs b/src/camera/mod.rs index 8aed4bf..42de3b3 100644 --- a/src/camera/mod.rs +++ b/src/camera/mod.rs @@ -1,2 +1,2 @@ pub mod film; -pub mod filter; +//pub mod filter; diff --git a/src/core/bound.rs b/src/core/bound.rs new file mode 100644 index 0000000..ea9d990 --- /dev/null +++ b/src/core/bound.rs @@ -0,0 +1,114 @@ +use crate::{Number, Float}; +use super::vector2::Vector2; +use crate::core; + +#[derive(Clone)] +pub struct Bound2 { + pub min: Vector2, + pub max: Vector2 +} + +pub type Bound2i = Bound2; +pub type Bound2f = Bound2; + +fn min (a: T, b: T) -> T { + if b < a { + return b; + } + a +} + +fn max (a: T, b: T) -> T { + if b > a { + return b; + } + a +} + +impl Bound2 { + pub fn new(p0: &Vector2, p1: &Vector2) -> Self { + let min = Vector2::new_xy(min(p0.x, p1.x), min(p0.y, p1.y)); + let max = Vector2::new_xy(max(p0.x, p1.x), max(p0.y, p1.y)); + + Self { min, max } + } + + pub fn new_xyxy(x1: T, y1: T, x2: T, y2: T) -> Self { + Self::new( + &Vector2::new_xy(x1, y1), + &Vector2::new_xy(x2, y2), + ) + } + + pub fn diagonal(&self) -> Vector2 { + self.max - self.min + } + + pub fn area(&self) -> T { + let diag = self.diagonal(); + return diag.x * diag.y; + } + + pub fn width(&self) -> T { + self.diagonal().x + } +} + +impl From<&Bound2i> for Bound2f { + fn from(b: &Bound2i) -> Self { + Self { + min: core::Vector2f::from(b.min), + max: core::Vector2f::from(b.max), + } + } +} + +impl From<&Bound2f> for Bound2i { + fn from(b: &Bound2f) -> Self { + Self { + min: core::Vector2i::from(b.min), + max: core::Vector2i::from(b.max), + } + } +} + +pub fn intersect(a: &Bound2, b: &Bound2) -> Bound2 { + Bound2::new( + &Vector2::new_xy(max(a.min.x, b.min.x), max(a.min.y, b.min.y)), + &Vector2::new_xy(min(a.max.x, b.max.x), min(a.max.y, b.max.y)), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn create_test() -> Bound2 { + Bound2::new( + &Vector2::new_xy(1, 2), + &Vector2::new_xy(10, 3) + ) + } + + #[test] + fn area() { + let b = create_test(); + + assert!(b.area() == 9); + } + + #[test] + fn intersect_test() { + let b1 = Bound2i::new_xyxy(10, 10, 20, 20); + let b2 = Bound2i::new_xyxy(2, 11, 22, 17); + + let b = intersect(&b1, &b2); + + assert!( + b.min.x == 10 && + b.min.y == 11 && + b.max.x == 20 && + b.max.y == 17 + ) + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..938a16e --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,11 @@ +pub mod vector2; +pub mod vector3; +pub mod bound; +pub mod spectrum; +mod ray; + +pub use vector2::{Vector2i, Vector2f}; +pub use vector3::Vector3f; +pub use bound::{Bound2i, Bound2f}; +pub use spectrum::Spectrum; +pub use ray::Ray; diff --git a/src/core/ray.rs b/src/core/ray.rs new file mode 100644 index 0000000..7d73b93 --- /dev/null +++ b/src/core/ray.rs @@ -0,0 +1,6 @@ +use crate::core::Vector3f; + +pub struct Ray { + origin: Vector3f, + direction: Vector3f, +} diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs new file mode 100644 index 0000000..604c8c0 --- /dev/null +++ b/src/core/spectrum.rs @@ -0,0 +1,35 @@ +use crate::Float; +use std::ops; + +// TODO implement SampledSpectrum instead for nicer images + +#[derive(Clone, Default)] +pub struct Spectrum { + c: [Float; 3], +} + +impl Spectrum { + fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum { + Spectrum { c: [r, g, b] } + } +} + +impl std::ops::Mul for &Spectrum { + type Output = Spectrum; + + fn mul(self, op: Float) -> Self::Output { + Self::Output::new_rgb( + self.c[0] * op, + self.c[1] * op, + self.c[2] * op, + ) + } +} + +impl std::ops::AddAssign<&Self> for Spectrum { + fn add_assign(&mut self, op: &Self) { + self.c[0] += op.c[0]; + self.c[1] += op.c[1]; + self.c[2] += op.c[2]; + } +} diff --git a/src/core/vector2.rs b/src/core/vector2.rs new file mode 100644 index 0000000..ac70947 --- /dev/null +++ b/src/core/vector2.rs @@ -0,0 +1,110 @@ +use crate::{Float, Number}; +use std::ops::{Sub, Add}; + +#[derive(Clone, Copy)] +pub struct Vector2 { + pub x: T, + pub y: T, +} + +pub type Vector2f = Vector2; +pub type Vector2i = Vector2; + +impl Vector2 { + pub fn new(initial: T) -> Vector2 { + Vector2 { x: initial, y: initial } + } + + pub fn new_xy(x: T, y: T) -> Vector2 { + Vector2 { x, y } + } +} + +impl Sub for Vector2 { + type Output = Self; + fn sub(self, op: Self) -> Self::Output { + Self::new_xy( + self.x - op.x, + self.y - op.y, + ) + } +} + +impl Add for Vector2 { + type Output = Self; + fn add(self, op: Self) -> Self::Output { + Self::new_xy( + self.x + op.x, + self.y + op.y, + ) + } +} + +impl Vector2f { + pub fn ceil(&self) -> Self { + Self::new_xy( + self.x.ceil(), + self.y.ceil() + ) + } + + pub fn floor(&self) -> Self { + Self::new_xy( + self.x.ceil(), + self.y.ceil() + ) + } +} + +impl From for Vector2f { + fn from(v: Vector2i) -> Self { + Self { + x: v.x as Float, + y: v.y as Float, + } + } +} + +impl From for Vector2i { + fn from(v: Vector2f) -> Self { + Self { + x: v.x as i32, + y: v.y as i32, + } + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_vec2() { + let v = Vector2::new_xy(2.0, 10.0); + + assert!(v.x == 2.0 && v.y == 10.0); + + let v = Vector2::new(3); + + assert!(v.x == 3 && v.y == 3); + } + + #[test] + fn sub_vec2() { + let v1 = Vector2::new_xy(10, 11); + let v2 = Vector2::new_xy(2, 3); + + let v3 = v1-v2; + assert!(v3.x == 8 && v3.y == 8); + } + + #[test] + fn add_vec2() { + let v1 = Vector2::new_xy(10, 11); + let v2 = Vector2::new_xy(2, 3); + + let v3 = v1+v2; + assert!(v3.x == 12 && v3.y == 14); + } +} diff --git a/src/core/vector3.rs b/src/core/vector3.rs new file mode 100644 index 0000000..da09ceb --- /dev/null +++ b/src/core/vector3.rs @@ -0,0 +1,47 @@ +use crate::{Float, Number}; +use std::ops::{Sub, Add}; + +#[derive(Clone, Copy)] +pub struct Vector3 { + pub x: T, + pub y: T, + pub z: T, +} + +pub type Vector3f = Vector3; + +impl Vector3 { + pub fn new(initial: T) -> Vector3 { + Vector3 { + x: initial, + y: initial, + z: initial, + } + } + + pub fn new_xy(x: T, y: T, z: T) -> Vector3 { + Vector3 { x, y, z} + } +} + +impl Sub for Vector3 { + type Output = Self; + fn sub(self, op: Self) -> Self::Output { + Self::new_xy( + self.x - op.x, + self.y - op.y, + self.z - op.z, + ) + } +} + +impl Add for Vector3 { + type Output = Self; + fn add(self, op: Self) -> Self::Output { + Self::new_xy( + self.x + op.x, + self.y + op.y, + self.z + op.z, + ) + } +} diff --git a/src/lib.rs b/src/lib.rs index 96c9212..c78c51e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ -pub mod vector; -pub mod bound; +pub mod core; pub mod camera; -mod spectrum; +mod scene; use std::ops::{Add, Sub, Mul}; use std::cmp; diff --git a/src/main.rs b/src/main.rs index 0ac71df..c984176 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,12 @@ -use pathtrace::camera::filter::Filter; use pathtrace::camera::film::Film; -use pathtrace::vector::{Vector2i, Vector2f}; +use pathtrace::vector::{Vector2i}; use pathtrace::bound::Bound2i; -use std::rc::Rc; fn main() { - let filter = Rc::new(Filter::new_box(Vector2f::new(2.5))); - - let film = Film::new(Vector2i::new(100), filter.clone()); + let film = Film::new(Vector2i::new(100)); let tile = film.get_tile(&Bound2i::new_xyxy(10, 10, 100, 100)); - println!("Yo {}", tile.bounds.min.x); + //println!("Yo {}", tile.bounds.min.x); } diff --git a/src/scene/mod.rs b/src/scene/mod.rs new file mode 100644 index 0000000..3482bb6 --- /dev/null +++ b/src/scene/mod.rs @@ -0,0 +1,3 @@ +mod shapes; + + diff --git a/src/scene/shapes/mod.rs b/src/scene/shapes/mod.rs new file mode 100644 index 0000000..76fb6f2 --- /dev/null +++ b/src/scene/shapes/mod.rs @@ -0,0 +1,12 @@ +mod sphere; + +pub use sphere::Sphere; + +use crate::core::Ray; +use crate::Float; + +trait Shape { + // + fn intersect(ray: Ray) -> Float; + fn intersect_ +} diff --git a/src/scene/shapes/sphere.rs b/src/scene/shapes/sphere.rs new file mode 100644 index 0000000..9598422 --- /dev/null +++ b/src/scene/shapes/sphere.rs @@ -0,0 +1,16 @@ +use crate::Float; +use crate::core::{Ray, Vector3f}; + +pub struct Sphere { + radius: Float, + center: Vector3f, +} + +impl Sphere { + pub fn new(radius: Float, center: Vector3f) -> Sphere { + Sphere { + radius, + center, + } + } +} diff --git a/src/spectrum.rs b/src/spectrum.rs deleted file mode 100644 index aa37056..0000000 --- a/src/spectrum.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::Float; - -// TODO implement SampledSpectrum instead for nicer images - -pub struct Spectrum { - c: [Float; 3], -} - -impl Spectrum { - fn from_rgb(r: Float, g: Float, b: Float) -> Spectrum { - Spectrum { c: [r, g, b] } - } -} diff --git a/src/vector.rs b/src/vector.rs deleted file mode 100644 index ac70947..0000000 --- a/src/vector.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::{Float, Number}; -use std::ops::{Sub, Add}; - -#[derive(Clone, Copy)] -pub struct Vector2 { - pub x: T, - pub y: T, -} - -pub type Vector2f = Vector2; -pub type Vector2i = Vector2; - -impl Vector2 { - pub fn new(initial: T) -> Vector2 { - Vector2 { x: initial, y: initial } - } - - pub fn new_xy(x: T, y: T) -> Vector2 { - Vector2 { x, y } - } -} - -impl Sub for Vector2 { - type Output = Self; - fn sub(self, op: Self) -> Self::Output { - Self::new_xy( - self.x - op.x, - self.y - op.y, - ) - } -} - -impl Add for Vector2 { - type Output = Self; - fn add(self, op: Self) -> Self::Output { - Self::new_xy( - self.x + op.x, - self.y + op.y, - ) - } -} - -impl Vector2f { - pub fn ceil(&self) -> Self { - Self::new_xy( - self.x.ceil(), - self.y.ceil() - ) - } - - pub fn floor(&self) -> Self { - Self::new_xy( - self.x.ceil(), - self.y.ceil() - ) - } -} - -impl From for Vector2f { - fn from(v: Vector2i) -> Self { - Self { - x: v.x as Float, - y: v.y as Float, - } - } -} - -impl From for Vector2i { - fn from(v: Vector2f) -> Self { - Self { - x: v.x as i32, - y: v.y as i32, - } - } -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn new_vec2() { - let v = Vector2::new_xy(2.0, 10.0); - - assert!(v.x == 2.0 && v.y == 10.0); - - let v = Vector2::new(3); - - assert!(v.x == 3 && v.y == 3); - } - - #[test] - fn sub_vec2() { - let v1 = Vector2::new_xy(10, 11); - let v2 = Vector2::new_xy(2, 3); - - let v3 = v1-v2; - assert!(v3.x == 8 && v3.y == 8); - } - - #[test] - fn add_vec2() { - let v1 = Vector2::new_xy(10, 11); - let v2 = Vector2::new_xy(2, 3); - - let v3 = v1+v2; - assert!(v3.x == 12 && v3.y == 14); - } -} -- cgit v1.2.3