diff options
author | Julian T <julian@jtle.dk> | 2021-08-05 15:44:40 +0200 |
---|---|---|
committer | Julian T <julian@jtle.dk> | 2021-08-05 15:44:40 +0200 |
commit | 3ef8f4d918406eec6bdc29e0ebd883fabfac9b2e (patch) | |
tree | aa4b1aac1e165821c16f222ebfb9212a9740e98b /src/core | |
parent | 45119506c0293fdde6cef35f6e6f82d4055b46b6 (diff) |
Add picture for c5505ab84820248c6dba35fc06aef9e0ced183derendered
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/bound2.rs | 127 | ||||
-rw-r--r-- | src/core/bound3.rs | 113 | ||||
-rw-r--r-- | src/core/mod.rs | 34 | ||||
-rw-r--r-- | src/core/ray.rs | 35 | ||||
-rw-r--r-- | src/core/spectrum.rs | 88 | ||||
-rw-r--r-- | src/core/vector2.rs | 167 | ||||
-rw-r--r-- | src/core/vector3.rs | 185 |
7 files changed, 0 insertions, 749 deletions
diff --git a/src/core/bound2.rs b/src/core/bound2.rs deleted file mode 100644 index bc0e7cd..0000000 --- a/src/core/bound2.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! Implements a 2d axis aligned bounding box -use crate::{Number, Float}; -use super::vector2::Vector2; -use crate::core; -use crate::core::{min, max}; - -/// Implements a region between min and max -#[derive(Clone)] -pub struct Bound2<T: Number> { - pub min: Vector2<T>, - pub max: Vector2<T> -} - -pub type Bound2i = Bound2<i32>; -pub type Bound2f = Bound2<Float>; - -impl<T: Number> Bound2<T> { - /// Creates a new bound from two points - /// - /// p0 does not have to be smaller than p1 - pub fn new(p0: &Vector2<T>, p1: &Vector2<T>) -> 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), - ) - } - - /// Finds the intersected area between two bounds - pub fn intersect(&self, b: &Bound2<T>) -> Bound2<T> { - Bound2::new( - &Vector2::new_xy(max(self.min.x, b.min.x), max(self.min.y, b.min.y)), - &Vector2::new_xy(min(self.max.x, b.max.x), min(self.max.y, b.max.y)), - ) - } - - - /// Calculates the diagonal vector - /// - /// Can be used to calculate the size of the bound - /// - /// # Examples - /// - /// ``` - /// use rendering::core::Bound2i; - /// let b = Bound2i::new_xyxy(2, 2, 6, 7); - /// let diag = b.diagonal(); - /// - /// assert!(diag.x == 4 && diag.y == 5); - /// ``` - pub fn diagonal(&self) -> Vector2<T> { - self.max - self.min - } - - /// Calculates the area of of the bounded region - /// - /// # Examples - /// - /// ``` - /// use rendering::core::Bound2i; - /// let b = Bound2i::new_xyxy(10, 10, 20, 20); - /// - /// assert!(b.area() == 100); - /// ``` - pub fn area(&self) -> T { - let diag = self.diagonal(); - diag.x * diag.y - } -} - -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), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn create_test() -> Bound2<i32> { - 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 = b1.intersect(&b2); - - assert!( - b.min.x == 10 && - b.min.y == 11 && - b.max.x == 20 && - b.max.y == 17 - ) - } -} diff --git a/src/core/bound3.rs b/src/core/bound3.rs deleted file mode 100644 index ce6bb09..0000000 --- a/src/core/bound3.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Implements 3d axis aligned bounding box -use crate::{Number, Float}; -use super::vector3::{Vector3, Vector3f}; -use crate::core::{min, max}; -use crate::core::Ray; - -#[derive(Clone)] -pub struct Bound3<T: Number> { - pub min: Vector3<T>, - pub max: Vector3<T> -} - -pub type Bound3f = Bound3<Float>; - -impl<T: Number> Bound3<T> { - /// Creates a bound from two points - pub fn new(p0: Vector3<T>, p1: Vector3<T>) -> Self { - // Elliminate some code duplication here - let min = Vector3::new_xyz( - min(p0.x, p1.x), - min(p0.y, p1.y), - min(p0.z, p1.z) - ); - let max = Vector3::new_xyz( - max(p0.x, p1.x), - max(p0.y, p1.y), - max(p0.z, p1.z) - ); - - Self {min, max} - } - - pub fn combine(&self, op: &Self) -> Self { - let min = Vector3::new_xyz( - min(self.min.x, op.min.x), - min(self.min.y, op.min.y), - min(self.min.z, op.min.z) - ); - let max = Vector3::new_xyz( - max(self.max.x, op.max.x), - max(self.max.y, op.max.y), - max(self.max.z, op.max.z) - ); - - Self {min, max} - } - - pub fn and(&self, op: &Self) -> Self { - let min_b = Vector3::new_xyz( - max(self.min.x, op.min.x), - max(self.min.y, op.min.y), - max(self.min.z, op.min.z) - ); - let max_b = Vector3::new_xyz( - min(self.max.x, op.max.x), - min(self.max.y, op.max.y), - min(self.max.z, op.max.z) - ); - - Self {min: min_b, max: max_b} - } - - pub fn area(&self) -> T { - let diag = self.max - self.min; - diag.x * diag.y * diag.z - } -} - -impl Bound3f { - pub const EMPTY: Bound3f = Bound3f{min: Vector3f::ZERO, max: Vector3f::ZERO}; - - /// Calculate whether there is a intersect between a bounding box and a ray - /// - /// # Examples: - /// - /// ``` - /// use rendering::core::{Bound3f, Vector3f, Ray}; - /// use rendering::INFTY; - /// let b = Bound3f::new(Vector3f::new(7.0), Vector3f::new(10.0)); - /// let r1 = Ray::new_to(Vector3f::new(0.0), Vector3f::new(5.0)); - /// let r2 = Ray::new_to(Vector3f::new(-0.0), Vector3f::new(-5.0)); - /// let r3 = Ray::new(Vector3f::new_xyz(-1.0, 0.0, 0.0), Vector3f::new_xyz(1.0, 0.0, 0.0)); - /// - /// assert!(b.intersect(&r1, 0.0, INFTY)); - /// assert!(!b.intersect(&r2, 0.0, INFTY)); - /// assert!(!b.intersect(&r3, 0.0, INFTY)); - /// ``` - pub fn intersect(&self, ray: &Ray, t_min: Float, t_max: Float) -> bool { - println!("BIN: {} -> {}", self.min, self.max); - // Method stolen from Ray tracing the next week. - // They mention its from pixar - for i in 0..3 { - let inv = 1.0 / ray.direction[i]; - let mut t0 = (self.min[i] - ray.origin[i]) * inv; - let mut t1 = (self.max[i] - ray.origin[i]) * inv; - - if inv < 0.0 { - let tmp = t0; - t0 = t1; - t1 = tmp; - } - - let t_min = max(t0, t_min); - let t_max = min(t1, t_max); - - if t_max <= t_min { - return false; - } - } - - return true; - } -} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index 95d450c..0000000 --- a/src/core/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Contains a collection of core modules used by other modules -//! -//! Also creates a shortcut for some common types - -mod vector2; -mod vector3; -mod bound2; -mod bound3; -mod spectrum; -mod ray; - -pub use vector2::{Vector2i, Vector2f}; -pub use vector3::Vector3f; -pub use bound2::{Bound2i, Bound2f}; -pub use bound3::Bound3f; -pub use spectrum::Spectrum; -pub use ray::Ray; - -use crate::Number; - -pub fn min<T: Number> (a: T, b: T) -> T { - if b < a { - return b; - } - a -} - -pub fn max<T: Number> (a: T, b: T) -> T { - if b > a { - return b; - } - a -} - diff --git a/src/core/ray.rs b/src/core/ray.rs deleted file mode 100644 index 19d3cf1..0000000 --- a/src/core/ray.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! The ray class used when probing the 3d scene -use crate::core::Vector3f; -use crate::Float; - -/// A ray that is sent into the world. -/// This is the main type used for testing intersections. -pub struct Ray { - /// Origin of the ray - pub origin: Vector3f, - /// Direction is assumed to be a unit vector. - pub direction: Vector3f, -} - -impl Ray { - pub fn new(origin: Vector3f, direction: Vector3f) -> Ray { - Ray { - origin, - direction, - } - } - - pub fn new_to(origin: Vector3f, target: Vector3f) -> Ray { - let dir = (target - origin).norm(); - Ray { - origin, - direction: dir - } - } - - /// Resolve a point on the ray at time t - pub fn at(&self, t: Float) -> Vector3f { - self.origin + self.direction * t - } -} - diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs deleted file mode 100644 index ed3505b..0000000 --- a/src/core/spectrum.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Used to represent color -//! -//! Currently only implements RGB colors -use crate::Float; - -// TODO implement SampledSpectrum instead for nicer images - -#[derive(Clone, Copy, Default)] -pub struct Spectrum { - c: [Float; 3], -} - -impl Spectrum { - pub const ZERO: Self = Spectrum { c: [0.0; 3] }; - pub const WHITE: Self = Spectrum { c: [1.0; 3] }; - - pub fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum { - Spectrum { c: [r, g, b] } - } - - pub fn to_rgb(&self, scale: Float) -> (Float, Float, Float) { - (self.c[0] * scale, self.c[1] * scale, self.c[2] * scale) - } - - pub fn gamma_correct(&self) -> Self { - Self::new_rgb( - self.c[0].sqrt(), - self.c[1].sqrt(), - self.c[2].sqrt(), - ) - } -} - -impl std::ops::Mul<Float> 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::Mul for Spectrum { - type Output = Spectrum; - - fn mul(self, op: Self) -> Self::Output { - Self::Output::new_rgb( - self.c[0] * op.c[0], - self.c[1] * op.c[1], - self.c[2] * op.c[2], - ) - } -} - -impl std::ops::Div<Float> for Spectrum { - type Output = Spectrum; - - fn div(self, op: Float) -> Self::Output { - Self::Output::new_rgb( - self.c[0] / op, - self.c[1] / op, - self.c[2] / op, - ) - } -} - -impl std::ops::Add for Spectrum { - type Output = Spectrum; - - fn add(self, op: Self) -> Self::Output { - Self::Output::new_rgb( - self.c[0] + op.c[0], - self.c[1] + op.c[1], - self.c[2] + op.c[2], - ) - } -} - -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 deleted file mode 100644 index 405b12a..0000000 --- a/src/core/vector2.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! Implements 2d vectors -//! -//! This is implemented generictly with types that fit in the Number trait -use crate::{Float, Number}; -use std::ops::{Sub, Add, Mul, Div}; -use std::fmt; -use std::cmp::min; - -#[derive(Clone, Copy)] -pub struct Vector2<T: Number> { - pub x: T, - pub y: T, -} - -pub type Vector2f = Vector2<Float>; -pub type Vector2i = Vector2<i32>; - - -impl<T: Number> Vector2<T> { - pub fn new(initial: T) -> Vector2<T> { - Vector2 { x: initial, y: initial } - } - - pub fn new_xy(x: T, y: T) -> Vector2<T> { - Vector2 { x, y } - } -} - -impl<T: Number> Sub for Vector2<T> { - type Output = Self; - fn sub(self, op: Self) -> Self::Output { - Self::new_xy( - self.x - op.x, - self.y - op.y, - ) - } -} - -impl<T: Number> Add for Vector2<T> { - type Output = Self; - fn add(self, op: Self) -> Self::Output { - Self::new_xy( - self.x + op.x, - self.y + op.y, - ) - } -} - -impl<T: Number> Mul for Vector2<T> { - type Output = Self; - fn mul(self, op: Self) -> Self::Output { - Self::new_xy( - self.x * op.x, - self.y * op.y, - ) - } -} - -impl<T: Number> Mul<T> for Vector2<T> { - type Output = Self; - fn mul(self, op: T) -> Self::Output { - Self::new_xy( - self.x * op, - self.y * op, - ) - } -} - -impl<T: Number> Div for Vector2<T> { - type Output = Self; - fn div(self, op: Self) -> Self::Output { - Self::new_xy( - self.x / op.x, - self.y / op.y, - ) - } -} - -impl<T: Number> fmt::Display for Vector2<T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!("[{}, {}]", self.x, self.y)) - } -} - -impl From<Vector2i> for Vector2f { - fn from(v: Vector2i) -> Self { - Self { - x: v.x as Float, - y: v.y as Float, - } - } -} - -impl From<Vector2f> for Vector2i { - fn from(v: Vector2f) -> Self { - Self { - x: v.x as i32, - y: v.y as i32, - } - } -} - -impl Vector2i { - pub const ZERO: Self = Vector2i {x: 0, y: 0}; - - pub fn cap(&self, x: i32, y: i32) -> Self { - Self::new_xy( - min(self.x, x), - min(self.y, y), - ) - } -} - -impl Vector2f { - pub fn length(&self) -> Float { - (self.x*self.x + self.y*self.y).sqrt() - } - - pub fn ceil(&self) -> Self { - Self::new_xy( - self.x.ceil(), - self.y.ceil() - ) - } - - pub fn floor(&self) -> Self { - Self::new_xy( - self.x.floor(), - self.y.floor() - ) - } -} - - -#[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 deleted file mode 100644 index 1cc6f60..0000000 --- a/src/core/vector3.rs +++ /dev/null @@ -1,185 +0,0 @@ -//! Implements 3d vectors -//! -//! Also add more 3d math things needed for shading and 3d calculations. -use crate::{Float, Number, NEAR_ZERO}; -use std::ops::{Mul, Sub, Add, DivAssign, Neg, AddAssign, Index}; -use std::fmt; - -#[derive(Clone, Copy)] -pub struct Vector3<T: Number> { - pub x: T, - pub y: T, - pub z: T, -} - -pub type Vector3f = Vector3<Float>; - -impl<T: Number> Vector3<T> { - pub fn new(initial: T) -> Vector3<T> { - Vector3 { - x: initial, - y: initial, - z: initial, - } - } - - pub fn new_xyz(x: T, y: T, z: T) -> Vector3<T> { - Vector3 { x, y, z} - } -} - -impl<T: Number> Sub for Vector3<T> { - type Output = Self; - fn sub(self, op: Self) -> Self::Output { - Self::new_xyz( - self.x - op.x, - self.y - op.y, - self.z - op.z, - ) - } -} - -impl<T: Number> Add for Vector3<T> { - type Output = Self; - fn add(self, op: Self) -> Self::Output { - Self::new_xyz( - self.x + op.x, - self.y + op.y, - self.z + op.z, - ) - } -} - -impl<T: Number> Add<T> for Vector3<T> { - type Output = Self; - - fn add(self, op: T) -> Self::Output { - Self::new_xyz( - self.x + op, - self.y + op, - self.z + op, - ) - } -} - -impl<T: Number> Mul<T> for Vector3<T> { - type Output = Self; - fn mul(self, op: T) -> Self::Output { - Self::Output::new_xyz( - self.x * op, - self.y * op, - self.z * op, - ) - } -} - -impl<T: Number> Neg for Vector3<T> { - type Output = Self; - - fn neg(self) -> Self::Output { - Self::Output::new_xyz( - -self.x, - -self.y, - -self.z, - ) - } -} - -impl<T: Number> AddAssign<&Self> for Vector3<T> { - fn add_assign(&mut self, op: &Self) { - self.x += op.x; - self.y += op.y; - self.z += op.z; - } -} - -impl<T: Number> DivAssign<T> for Vector3<T> { - fn div_assign(&mut self, op: T) { - self.x /= op; - self.y /= op; - self.z /= op; - } -} - -impl<T: Number> fmt::Display for Vector3<T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!("[{}, {}, {}]", self.x, self.y, self.z)) - } -} - -// Ohh god -impl<T: Number> Index<u32> for Vector3<T> { - type Output = T; - - fn index(&self, i: u32) -> &Self::Output { - match i { - 0 => &self.x, - 1 => &self.y, - 2 => &self.z, - _ => panic!("index out of bounds: index {} is not possible with 3d vector", i) - } - } -} - -impl Vector3f { - pub const ZERO: Self = Vector3f {x: 0.0, y: 0.0, z: 0.0}; - - /// Calculates the length times itself - /// - /// This is faster than using len * len as the square is ommited - pub fn len_squared(&self) -> Float { - self.x * self.x + self.y * self.y + self.z * self.z - } - - pub fn length(&self) -> Float { - self.len_squared().sqrt() - } - - pub fn dot(&self, op: &Self) -> Float { - self.x * op.x + self.y * op.y + self.z * op.z - } - - /// Inplace normal instead of creating a new vector - /// - /// # Example - /// - /// ``` - /// use rendering::core::Vector3f; - /// let mut v = Vector3f::new_xyz(10.0, 0.0, 0.0); - /// v.norm_in(); - /// assert!(v.x == 1.0); - /// ``` - pub fn norm_in(&mut self) { - // TODO Experiment with checking for normality with len_squared - let len = self.length(); - if len == 0.0 { - *self = Self::new(0.0); - } - - *self /= len; - } - - pub fn norm(&self) -> Self { - let mut new = *self; - new.norm_in(); - new - } - - pub fn cross(&self, op: &Self) -> Self { - Self::new_xyz( - self.y * op.z - self.z * op.y, - self.z * op.x - self.x * op.z, - self.x * op.y - self.y * op.x, - ) - - } - - /// Check if vector is close to [0, 0, 0] - /// - /// This is based on the NEAR_ZERO constant - pub fn near_zero(&self) -> bool { - (self.x.abs() < NEAR_ZERO) && - (self.y.abs() < NEAR_ZERO) && - (self.z.abs() < NEAR_ZERO) - } -} |