Compare commits
No commits in common. "4202cc8f2ee47e9b6a307cdaf95d82665e6bee55" and "80b2d87d22628e9736e9310b24fd97dd659c50a1" have entirely different histories.
4202cc8f2e
...
80b2d87d22
|
|
@ -20,7 +20,7 @@ use vanrijn::materials::LambertianMaterial;
|
|||
use vanrijn::math::Vec3;
|
||||
use vanrijn::mesh::load_obj;
|
||||
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::util::TileIterator;
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}),
|
||||
)?;
|
||||
println!("Building BVH...");
|
||||
let model_bvh: Box<dyn Primitive> =
|
||||
let model_bvh: Box<dyn Aggregate> =
|
||||
Box::new(BoundingVolumeHierarchy::build(model_object.as_mut_slice()));
|
||||
println!("Constructing Scene...");
|
||||
|
||||
|
|
@ -183,7 +183,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
//specular_strength: 1.0,
|
||||
}),
|
||||
)),
|
||||
]) as Box<dyn Primitive>,
|
||||
]) as Box<dyn Aggregate>,
|
||||
model_bvh,
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,3 @@ pub use mat3::*;
|
|||
|
||||
mod mat4;
|
||||
pub use mat4::*;
|
||||
|
||||
mod affine3;
|
||||
pub use affine3::*;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ pub trait Float:
|
|||
{
|
||||
fn abs(self) -> Self;
|
||||
fn sqrt(self) -> Self;
|
||||
fn sin(self) -> Self;
|
||||
fn cos(self) -> Self;
|
||||
}
|
||||
|
||||
impl HasZero for f64 {
|
||||
|
|
@ -57,16 +55,7 @@ impl Float for f64 {
|
|||
fn abs(self) -> Self {
|
||||
self.abs()
|
||||
}
|
||||
|
||||
fn sqrt(self) -> Self {
|
||||
self.sqrt()
|
||||
}
|
||||
|
||||
fn sin(self) -> Self {
|
||||
self.sin()
|
||||
}
|
||||
|
||||
fn cos(self) -> Self {
|
||||
self.cos()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use super::{Float, Vec3};
|
||||
use super::Float;
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Vec4<T: Float> {
|
||||
pub coords: [T; 4],
|
||||
}
|
||||
|
|
@ -32,12 +32,6 @@ impl<T: Float> Vec4<T> {
|
|||
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 {
|
||||
self.coords
|
||||
.iter()
|
||||
|
|
@ -144,14 +138,6 @@ mod tests {
|
|||
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]
|
||||
fn dot_product_returns_correct_result() {
|
||||
let a = Vec4::new(1.0, 2.0, 3.0, 4.0);
|
||||
|
|
|
|||
|
|
@ -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::sync::Arc;
|
||||
|
|
@ -123,11 +125,7 @@ impl HasBoundingBox for BoundingVolumeHierarchy {
|
|||
}
|
||||
}
|
||||
|
||||
impl Primitive for BoundingVolumeHierarchy {
|
||||
fn transform(&self, transformation: &Affine3<f64>) -> Box<dyn Primitive> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Aggregate for BoundingVolumeHierarchy {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::math::{Affine3,Vec3};
|
||||
use crate::math::Vec3;
|
||||
|
||||
use super::materials::Material;
|
||||
|
||||
|
|
@ -121,12 +121,23 @@ pub trait HasBoundingBox: Send + Sync {
|
|||
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
|
||||
pub trait Primitive: Intersect + HasBoundingBox {
|
||||
// / 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)]
|
||||
mod tests {
|
||||
use quickcheck_macros::quickcheck;
|
||||
|
|
|
|||
|
|
@ -79,9 +79,21 @@ impl HasBoundingBox for Plane {
|
|||
let p0 = self.normal * self.distance_from_origin;
|
||||
let f = |v: Vec3<f64>| {
|
||||
Vec3::new(
|
||||
if v.x() == 0.0 { 0.0 } else { f64::INFINITY },
|
||||
if v.y() == 0.0 { 0.0 } else { f64::INFINITY },
|
||||
if v.z() == 0.0 { 0.0 } else { f64::INFINITY },
|
||||
if v.x() == 0.0 {
|
||||
0.0
|
||||
} 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);
|
||||
|
|
@ -94,11 +106,7 @@ impl HasBoundingBox for Plane {
|
|||
}
|
||||
}
|
||||
|
||||
impl Primitive for Plane {
|
||||
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Primitive for Plane {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -99,11 +99,7 @@ impl HasBoundingBox for Sphere {
|
|||
}
|
||||
}
|
||||
|
||||
impl Primitive for Sphere {
|
||||
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Primitive for Sphere {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -103,11 +103,7 @@ impl HasBoundingBox for Triangle {
|
|||
}
|
||||
}
|
||||
|
||||
impl Primitive for Triangle {
|
||||
fn transform(&self, transformation: &crate::math::Affine3<f64>) -> Box<dyn Primitive> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Primitive for Triangle {}
|
||||
|
||||
fn indices_with_index_of_largest_element_last(v: &Vec3<f64>) -> [usize; 3] {
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
use crate::math::Affine3;
|
||||
use super::{Aggregate, BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
|
||||
impl HasBoundingBox for Vec<Box<dyn Primitive>> {
|
||||
fn bounding_box(&self) -> BoundingBox {
|
||||
|
|
@ -22,8 +21,27 @@ impl Intersect for Vec<Box<dyn Primitive>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Primitive for Vec<Box<dyn Primitive>> {
|
||||
fn transform(&self, transformation: &Affine3<f64>) -> Box<dyn Primitive> {
|
||||
todo!()
|
||||
impl Aggregate for Vec<Box<dyn Primitive>> {}
|
||||
|
||||
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>> {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::math::Vec3;
|
||||
|
||||
use crate::raycasting::Primitive;
|
||||
use crate::raycasting::Aggregate;
|
||||
|
||||
pub struct Scene {
|
||||
pub camera_location: Vec3<f64>,
|
||||
pub objects: Vec<Box<dyn Primitive>>,
|
||||
pub objects: Vec<Box<dyn Aggregate>>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue