Compare commits

..

No commits in common. "4202cc8f2ee47e9b6a307cdaf95d82665e6bee55" and "80b2d87d22628e9736e9310b24fd97dd659c50a1" have entirely different histories.

12 changed files with 66 additions and 227 deletions

View File

@ -20,7 +20,7 @@ use vanrijn::materials::LambertianMaterial;
use vanrijn::math::Vec3; use vanrijn::math::Vec3;
use vanrijn::mesh::load_obj; use vanrijn::mesh::load_obj;
use vanrijn::partial_render_scene; use vanrijn::partial_render_scene;
use vanrijn::raycasting::{BoundingVolumeHierarchy, Plane, Primitive, Sphere}; use vanrijn::raycasting::{Aggregate, BoundingVolumeHierarchy, Plane, Primitive, Sphere};
use vanrijn::scene::Scene; use vanrijn::scene::Scene;
use vanrijn::util::TileIterator; use vanrijn::util::TileIterator;
@ -131,7 +131,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
}), }),
)?; )?;
println!("Building BVH..."); println!("Building BVH...");
let model_bvh: Box<dyn Primitive> = let model_bvh: Box<dyn Aggregate> =
Box::new(BoundingVolumeHierarchy::build(model_object.as_mut_slice())); Box::new(BoundingVolumeHierarchy::build(model_object.as_mut_slice()));
println!("Constructing Scene..."); println!("Constructing Scene...");
@ -183,7 +183,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
//specular_strength: 1.0, //specular_strength: 1.0,
}), }),
)), )),
]) as Box<dyn Primitive>, ]) as Box<dyn Aggregate>,
model_bvh, model_bvh,
], ],
}; };

View File

@ -1,160 +0,0 @@
use super::{Float, Mat3, Mat4, Vec3, Vec4};
use std::ops::{Mul, MulAssign};
#[derive(PartialEq, Debug)]
pub struct Affine3<T: Float> {
matrix: Mat4<T>,
}
impl<T: Float> Affine3<T> {
pub fn translation(delta: Vec3<T>) -> Self {
#[rustfmt::skip]
let matrix = Mat4::new(T::one(), T::zero(), T::zero(), delta.x(),
T::zero(), T::one() , T::zero(), delta.y(),
T::zero(), T::zero(), T::one(), delta.z(),
T::zero(), T::zero(), T::zero(), T::one());
Self { matrix }
}
pub fn rotation(axis: Vec3<T>, angle: T) -> Self {
let x = axis.x();
let y = axis.y();
let z = axis.z();
let cos = angle.cos();
let ncos = T::one() - cos;
let sin = angle.sin();
#[rustfmt::skip]
let matrix = Mat4::new(x*x*ncos+cos, y*x*ncos-z*sin, z*x*ncos+y*sin, T::zero(),
x*y*ncos+z*sin, y*y*ncos+cos, z*y*ncos-x*sin, T::zero(),
x*z*ncos-y*sin, y*z*ncos+x*sin, z*z*ncos+cos, T::zero(),
T::zero(), T::zero(), T::zero(), T::one());
Self { matrix }
}
pub fn scale(s: T) -> Self {
#[rustfmt::skip]
let matrix = Mat4::new(s, T::zero(), T::zero(), T::zero(),
T::zero(), s , T::zero(), T::zero(),
T::zero(), T::zero(), s, T::zero(),
T::zero(), T::zero(), T::zero(), T::one());
Self { matrix }
}
pub fn get_element(&self, row: usize, column: usize) -> T {
self.matrix.get_element(row, column)
}
pub fn get_row(&self, row: usize) -> Vec4<T> {
self.matrix.get_row(row)
}
pub fn get_column(&self, column: usize) -> Vec4<T> {
self.matrix.get_column(column)
}
pub fn linear_map(&self) -> Mat3<T> {
Mat3::new(
self.matrix.get_element(0, 0),
self.matrix.get_element(0, 1),
self.matrix.get_element(0, 2),
self.matrix.get_element(1, 0),
self.matrix.get_element(1, 1),
self.matrix.get_element(1, 2),
self.matrix.get_element(2, 0),
self.matrix.get_element(2, 1),
self.matrix.get_element(2, 2),
)
}
pub fn inverse(&self) -> Affine3<T> {
// linear map should always be invertable.
let inner = self.linear_map().try_inverse().unwrap();
let translation = inner * self.matrix.get_column(3).xyz();
#[rustfmt::skip]
let matrix = Mat4::new(
inner.get_element(0,0), inner.get_element(0,1), inner.get_element(0,2), translation.x(),
inner.get_element(1,0), inner.get_element(1,1), inner.get_element(1,2), translation.y(),
inner.get_element(2,0), inner.get_element(2,1), inner.get_element(2,2), translation.z(),
T::zero(), T::zero(), T::zero(), T::one());
Self { matrix }
}
}
impl<T: Float> Mul<Affine3<T>> for Affine3<T> {
type Output = Self;
fn mul(self, rhs: Affine3<T>) -> Affine3<T> {
let matrix = self.matrix * rhs.matrix;
Affine3 { matrix }
}
}
impl<T: Float> Mul<Mat4<T>> for Affine3<T> {
type Output = Mat4<T>;
fn mul(self, rhs: Mat4<T>) -> Mat4<T> {
self.matrix * rhs
}
}
impl<T: Float> Mul<Affine3<T>> for Mat4<T> {
type Output = Mat4<T>;
fn mul(self, rhs: Affine3<T>) -> Mat4<T> {
self * rhs.matrix
}
}
impl<T: Float> MulAssign<Affine3<T>> for Affine3<T> {
fn mul_assign(&mut self, rhs: Affine3<T>) {
self.matrix *= rhs.matrix
}
}
impl<T: Float> Mul<Vec4<T>> for Affine3<T> {
type Output = Vec4<T>;
fn mul(self, rhs: Vec4<T>) -> Vec4<T> {
self.matrix * rhs
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn translate_translates_vector() {
let p = Vec4::new(1.0, 2.0, 3.0, 1.0);
let v = Vec3::new(4.0, 5.0, 6.0);
let target = Affine3::translation(v);
let diff = (target * p).xyz() - (p.xyz() + v);
assert!(diff.norm() < 0.0000000001);
}
#[test]
fn rotate_rotates_vector() {
let x = Vec4::new(1.0, 0.0, 0.0, 1.0);
let y = Vec4::new(0.0, 1.0, 0.0, 1.0);
let z = Vec4::new(0.0, 0.0, 1.0, 1.0);
let target = Affine3::rotation(z.xyz(), std::f64::consts::PI/2.0) * y;
let diff = -x.xyz() - target.xyz();
assert!(diff.norm() < 0.0000000001);
}
#[test]
fn linear_map_is_inner_matrix() {
#[rustfmt::skip]
let target = Affine3{
matrix: Mat4::new(1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
0.0, 0.0, 0.0, 1.0)};
let linear_map = target.linear_map();
for i in 0..2 {
for j in 0..2 {
assert!(linear_map.get_element(i, j) == target.get_element(i, j));
}
}
}
}

View File

@ -18,6 +18,3 @@ pub use mat3::*;
mod mat4; mod mat4;
pub use mat4::*; pub use mat4::*;
mod affine3;
pub use affine3::*;

View File

@ -37,8 +37,6 @@ pub trait Float:
{ {
fn abs(self) -> Self; fn abs(self) -> Self;
fn sqrt(self) -> Self; fn sqrt(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
} }
impl HasZero for f64 { impl HasZero for f64 {
@ -57,16 +55,7 @@ impl Float for f64 {
fn abs(self) -> Self { fn abs(self) -> Self {
self.abs() self.abs()
} }
fn sqrt(self) -> Self { fn sqrt(self) -> Self {
self.sqrt() self.sqrt()
} }
fn sin(self) -> Self {
self.sin()
}
fn cos(self) -> Self {
self.cos()
}
} }

View File

@ -1,10 +1,10 @@
use super::{Float, Vec3}; use super::Float;
use itertools::izip; use itertools::izip;
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
#[derive(PartialEq, Debug, Clone, Copy)] #[derive(PartialEq, Debug)]
pub struct Vec4<T: Float> { pub struct Vec4<T: Float> {
pub coords: [T; 4], pub coords: [T; 4],
} }
@ -32,12 +32,6 @@ impl<T: Float> Vec4<T> {
self.coords[3] self.coords[3]
} }
pub fn xyz(&self) -> Vec3<T> {
let mut coords = [T::zero(); 3];
coords.copy_from_slice(&self.coords[0..3]);
Vec3 { coords }
}
pub fn dot(&self, rhs: &Vec4<T>) -> T { pub fn dot(&self, rhs: &Vec4<T>) -> T {
self.coords self.coords
.iter() .iter()
@ -144,14 +138,6 @@ mod tests {
assert!(target.w() == 4.0); assert!(target.w() == 4.0);
} }
#[test]
fn xyz_returns_expected_value() {
let target = Vec4::new(1.0, 2.0, 3.0, 4.0).xyz();
assert!(target.x() == 1.0);
assert!(target.y() == 2.0);
assert!(target.z() == 3.0);
}
#[test] #[test]
fn dot_product_returns_correct_result() { fn dot_product_returns_correct_result() {
let a = Vec4::new(1.0, 2.0, 3.0, 4.0); let a = Vec4::new(1.0, 2.0, 3.0, 4.0);

View File

@ -1,6 +1,8 @@
use crate::math::{Affine3, Vec3}; use crate::math::Vec3;
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectP, IntersectionInfo, Primitive, Ray}; use super::{
Aggregate, BoundingBox, HasBoundingBox, Intersect, IntersectP, IntersectionInfo, Primitive, Ray,
};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::sync::Arc; use std::sync::Arc;
@ -123,11 +125,7 @@ impl HasBoundingBox for BoundingVolumeHierarchy {
} }
} }
impl Primitive for BoundingVolumeHierarchy { impl Aggregate for BoundingVolumeHierarchy {}
fn transform(&self, transformation: &Affine3<f64>) -> Box<dyn Primitive> {
todo!()
}
}
#[cfg(test)] #[cfg(test)]
mod test {} mod test {}

View File

@ -1,4 +1,4 @@
use crate::math::{Affine3,Vec3}; use crate::math::Vec3;
use super::materials::Material; use super::materials::Material;
@ -121,12 +121,23 @@ pub trait HasBoundingBox: Send + Sync {
fn bounding_box(&self) -> BoundingBox; fn bounding_box(&self) -> BoundingBox;
} }
/// Any geometric object which can have an affine transformation applied to it
///
/// Used for moving, rotating or scaling primitives
/*pub trait Transform {
/// Create a new object by applying the transformation to this object.
fn transform(&self, transformation: &Affine3<f64>) -> Self;
}*/
/// A basic geometric primitive such as a sphere or a triangle /// A basic geometric primitive such as a sphere or a triangle
pub trait Primitive: Intersect + HasBoundingBox { pub trait Primitive: Intersect + HasBoundingBox {
// / Create a new object by applying the transformation to this object. // / Create a new object by applying the transformation to this object.
fn transform(&self, transformation: &Affine3<f64>) -> Box<dyn Primitive>; //fn transform(&self, transformation: &Affine3) -> dyn Primitive;
} }
/// Either a primitive or a collection of primitives
pub trait Aggregate: Intersect + HasBoundingBox {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use quickcheck_macros::quickcheck; use quickcheck_macros::quickcheck;

View File

@ -79,9 +79,21 @@ impl HasBoundingBox for Plane {
let p0 = self.normal * self.distance_from_origin; let p0 = self.normal * self.distance_from_origin;
let f = |v: Vec3<f64>| { let f = |v: Vec3<f64>| {
Vec3::new( Vec3::new(
if v.x() == 0.0 { 0.0 } else { f64::INFINITY }, if v.x() == 0.0 {
if v.y() == 0.0 { 0.0 } else { f64::INFINITY }, 0.0
if v.z() == 0.0 { 0.0 } else { f64::INFINITY }, } else {
f64::INFINITY
},
if v.y() == 0.0 {
0.0
} else {
f64::INFINITY
},
if v.z() == 0.0 {
0.0
} else {
f64::INFINITY
},
) )
}; };
let tangent = f(self.tangent); let tangent = f(self.tangent);
@ -94,11 +106,7 @@ impl HasBoundingBox for Plane {
} }
} }
impl Primitive for Plane { impl Primitive for Plane {}
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
todo!()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -99,11 +99,7 @@ impl HasBoundingBox for Sphere {
} }
} }
impl Primitive for Sphere { impl Primitive for Sphere {}
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
todo!()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -103,11 +103,7 @@ impl HasBoundingBox for Triangle {
} }
} }
impl Primitive for Triangle { impl Primitive for Triangle {}
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
todo!()
}
}
fn indices_with_index_of_largest_element_last(v: &Vec3<f64>) -> [usize; 3] { fn indices_with_index_of_largest_element_last(v: &Vec3<f64>) -> [usize; 3] {
#[allow(clippy::collapsible_else_if)] #[allow(clippy::collapsible_else_if)]

View File

@ -1,5 +1,4 @@
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray}; use super::{Aggregate, BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
use crate::math::Affine3;
impl HasBoundingBox for Vec<Box<dyn Primitive>> { impl HasBoundingBox for Vec<Box<dyn Primitive>> {
fn bounding_box(&self) -> BoundingBox { fn bounding_box(&self) -> BoundingBox {
@ -22,8 +21,27 @@ impl Intersect for Vec<Box<dyn Primitive>> {
} }
} }
impl Primitive for Vec<Box<dyn Primitive>> { impl Aggregate for Vec<Box<dyn Primitive>> {}
fn transform(&self, transformation: &Affine3<f64>) -> Box<dyn Primitive> {
todo!() impl HasBoundingBox for Vec<Box<dyn Aggregate>> {
fn bounding_box(&self) -> BoundingBox {
self.iter().fold(BoundingBox::empty(), |acc, elem| {
acc.union(&elem.bounding_box())
})
} }
} }
impl Intersect for Vec<Box<dyn Aggregate>> {
fn intersect(&self, ray: &Ray) -> Option<IntersectionInfo> {
self.iter()
.flat_map(|aggregate| aggregate.intersect(ray))
.min_by(
|a, b| match PartialOrd::partial_cmp(&a.distance, &b.distance) {
None => std::cmp::Ordering::Less,
Some(ordering) => ordering,
},
)
}
}
impl Aggregate for Vec<Box<dyn Aggregate>> {}

View File

@ -1,8 +1,8 @@
use crate::math::Vec3; use crate::math::Vec3;
use crate::raycasting::Primitive; use crate::raycasting::Aggregate;
pub struct Scene { pub struct Scene {
pub camera_location: Vec3<f64>, pub camera_location: Vec3<f64>,
pub objects: Vec<Box<dyn Primitive>>, pub objects: Vec<Box<dyn Aggregate>>,
} }