From 3129ee98d365dff53f86e8afff757b43f42dfec6 Mon Sep 17 00:00:00 2001 From: Daniel Oom Date: Sat, 6 Jul 2024 16:30:46 +0200 Subject: [PATCH] Replace nalgebra with glam --- Cargo.lock | 116 ++------------- geometry/Cargo.toml | 2 +- geometry/src/aabb.rs | 40 +++--- geometry/src/aap.rs | 36 ++--- geometry/src/axial_triangle.rs | 56 ++++---- geometry/src/axis.rs | 24 ++-- geometry/src/bound.rs | 22 +-- geometry/src/clip.rs | 102 +++++++------- geometry/src/geometric.rs | 7 +- geometry/src/lib.rs | 6 +- geometry/src/ray.rs | 12 +- geometry/src/sphere.rs | 34 ++--- geometry/src/triangle.rs | 248 ++++++++++++++++----------------- kdtree-reducer-cli/Cargo.toml | 1 - kdtree-tester-cli/Cargo.toml | 2 +- kdtree-tester-cli/src/main.rs | 18 +-- kdtree/Cargo.toml | 2 +- kdtree/src/build_sah.rs | 16 +-- kdtree/src/lib.rs | 92 ++++++------ kdtree/src/split.rs | 11 +- pathtracer-gui/Cargo.toml | 2 +- pathtracer-gui/src/stage.rs | 15 +- pathtracer-gui/src/worker.rs | 20 ++- scene/Cargo.toml | 3 +- scene/src/camera.rs | 41 +++--- scene/src/lib.rs | 30 ++-- scene/src/light.rs | 17 +-- scene/src/material.rs | 10 +- tracing/Cargo.toml | 3 +- tracing/src/image_buffer.rs | 39 +++--- tracing/src/material.rs | 98 +++++++------ tracing/src/pathtracer.rs | 64 ++++----- tracing/src/raytracer.rs | 21 ++- tracing/src/sampling.rs | 38 ++--- 34 files changed, 552 insertions(+), 696 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc9bf4b3..36d4b153 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,15 +57,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - [[package]] name = "arrayvec" version = "0.7.4" @@ -227,7 +218,7 @@ name = "geometry" version = "1.0.0" dependencies = [ "arrayvec", - "nalgebra", + "glam", ] [[package]] @@ -241,6 +232,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + [[package]] name = "heck" version = "0.5.0" @@ -278,7 +275,7 @@ name = "kdtree" version = "1.0.0" dependencies = [ "geometry", - "nalgebra", + "glam", "rayon", "smallvec", "textwrap", @@ -302,7 +299,6 @@ dependencies = [ "clap", "geometry", "kdtree", - "nalgebra", "rand", "rayon", "wavefront", @@ -314,8 +310,8 @@ version = "1.0.0" dependencies = [ "clap", "geometry", + "glam", "kdtree", - "nalgebra", "rand", "rayon", "scene", @@ -371,20 +367,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "nalgebra" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c4b5f057b303842cf3262c27e465f4c303572e7f6b0648f60e16248ac3397f4" -dependencies = [ - "approx", - "num-complex", - "num-rational", - "num-traits", - "simba", - "typenum", -] - [[package]] name = "ndk-sys" version = "0.2.2" @@ -401,40 +383,12 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -453,12 +407,6 @@ dependencies = [ "malloc_buf", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pathtracer-cli" version = "1.0.0" @@ -477,9 +425,9 @@ name = "pathtracer-gui" version = "0.1.0" dependencies = [ "clap", + "glam", "kdtree", "miniquad", - "nalgebra", "rand", "rayon", "scene", @@ -590,23 +538,13 @@ dependencies = [ "tracing", ] -[[package]] -name = "safe_arch" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" -dependencies = [ - "bytemuck", -] - [[package]] name = "scene" version = "1.0.0" dependencies = [ "geometry", + "glam", "image", - "nalgebra", - "simba", "wavefront", ] @@ -630,19 +568,6 @@ dependencies = [ "syn", ] -[[package]] -name = "simba" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" -dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", - "wide", -] - [[package]] name = "simd-adler32" version = "0.3.7" @@ -726,19 +651,12 @@ version = "1.0.0" dependencies = [ "assert_approx_eq", "geometry", + "glam", "kdtree", - "nalgebra", "rand", "scene", - "simba", ] -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -783,16 +701,6 @@ dependencies = [ "wavefront", ] -[[package]] -name = "wide" -version = "0.7.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2caba658a80831539b30698ae9862a72db6697dfdd7151e46920f5f2755c3ce2" -dependencies = [ - "bytemuck", - "safe_arch", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/geometry/Cargo.toml b/geometry/Cargo.toml index 16679315..e8665b4f 100644 --- a/geometry/Cargo.toml +++ b/geometry/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] arrayvec = "0.7.4" -nalgebra = { version = "0.33.0", default-features = false } +glam = "0.28.0" diff --git a/geometry/src/aabb.rs b/geometry/src/aabb.rs index 2acf280d..82aadd84 100644 --- a/geometry/src/aabb.rs +++ b/geometry/src/aabb.rs @@ -1,30 +1,30 @@ -use nalgebra::Vector3; +use glam::Vec3; use super::aap::Aap; -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Aabb { - min: Vector3, - max: Vector3, + min: Vec3, + max: Vec3, } impl Aabb { - pub fn from_extents(min: Vector3, max: Vector3) -> Aabb { - debug_assert!(min <= max); + pub fn from_extents(min: Vec3, max: Vec3) -> Aabb { + debug_assert!(min.cmple(max).all()); Aabb { min, max } } pub fn empty() -> Aabb { Aabb { - min: Vector3::zeros(), - max: Vector3::zeros(), + min: Vec3::ZERO, + max: Vec3::ZERO, } } pub fn unit() -> Aabb { Aabb { - min: Vector3::new(0., 0., 0.), - max: Vector3::new(1., 1., 1.), + min: Vec3::new(0., 0., 0.), + max: Vec3::new(1., 1., 1.), } } @@ -32,23 +32,23 @@ impl Aabb { self.min == self.max } - pub fn center(&self) -> Vector3 { + pub fn center(&self) -> Vec3 { self.min + self.half_size() } - pub fn half_size(&self) -> Vector3 { + pub fn half_size(&self) -> Vec3 { self.size() / 2.0 } - pub fn size(&self) -> Vector3 { + pub fn size(&self) -> Vec3 { self.max - self.min } - pub fn min(&self) -> Vector3 { + pub fn min(&self) -> Vec3 { self.min } - pub fn max(&self) -> Vector3 { + pub fn max(&self) -> Vec3 { self.max } @@ -62,7 +62,7 @@ impl Aabb { size.x * size.y * size.z } - pub fn enlarge(&self, delta: &Vector3) -> Aabb { + pub fn enlarge(&self, delta: Vec3) -> Aabb { let half_delta = delta / 2.0; Aabb { min: self.min - half_delta, @@ -96,16 +96,16 @@ impl Aabb { (fst, snd) } - pub fn clamp(&self, point: Vector3) -> Vector3 { - Vector3::new( + pub fn clamp(&self, point: Vec3) -> Vec3 { + Vec3::new( point.x.clamp(self.min.x, self.max.x), point.y.clamp(self.min.y, self.max.y), point.z.clamp(self.min.z, self.max.z), ) } - pub fn contains(&self, point: &Vector3) -> bool { - *point >= self.min && *point <= self.max + pub fn contains(&self, point: Vec3) -> bool { + point.cmpge(self.min).all() && point.cmple(self.max).all() } } diff --git a/geometry/src/aap.rs b/geometry/src/aap.rs index 559b2552..0c000a1e 100644 --- a/geometry/src/aap.rs +++ b/geometry/src/aap.rs @@ -1,4 +1,4 @@ -use nalgebra::{Vector2, Vector3}; +use glam::{Vec2, Vec3}; use crate::ray::Ray; @@ -32,11 +32,11 @@ impl Aap { } } - pub fn add_to(&self, point: Vector2) -> Vector3 { + pub fn add_to(&self, point: Vec2) -> Vec3 { self.axis.add_to(point, self.distance) } - pub fn vector(&self) -> Vector3 { + pub fn vector(&self) -> Vec3 { self.axis.as_vector3(self.distance) } @@ -56,19 +56,19 @@ impl Aap { Some((self.distance - ray.origin[self.axis]) / denom) } - pub fn intersect_ray_point(&self, ray: &Ray) -> Option> { + pub fn intersect_ray_point(&self, ray: &Ray) -> Option { self.intersect_ray(ray).map(|t| match self.axis { - Axis::X => Vector3::new( + Axis::X => Vec3::new( self.distance, ray.origin.y + t * ray.direction.y, ray.origin.z + t * ray.direction.z, ), - Axis::Y => Vector3::new( + Axis::Y => Vec3::new( ray.origin.x + t * ray.direction.x, self.distance, ray.origin.z + t * ray.direction.z, ), - Axis::Z => Vector3::new( + Axis::Z => Vec3::new( ray.origin.x + t * ray.direction.x, ray.origin.y + t * ray.direction.y, self.distance, @@ -89,7 +89,7 @@ mod tests { axis: Axis::X, distance: 5.0, }; - let ray = Ray::between(&Vector3::zeros(), &Vector3::new(5.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::ZERO, Vec3::new(5.0, 0.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(1.0)); } @@ -100,7 +100,7 @@ mod tests { axis: Axis::X, distance: 5.0, }; - let ray = Ray::between(&Vector3::zeros(), &Vector3::new(10.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::ZERO, Vec3::new(10.0, 0.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -111,7 +111,7 @@ mod tests { axis: Axis::X, distance: 5.0, }; - let ray = Ray::between(&Vector3::zeros(), &Vector3::new(4.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::ZERO, Vec3::new(4.0, 0.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(1.25)); } @@ -122,7 +122,7 @@ mod tests { axis: Axis::X, distance: 5.0, }; - let ray = Ray::between(&Vector3::new(4.0, 0.0, 0.0), &Vector3::new(6.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::new(4.0, 0.0, 0.0), Vec3::new(6.0, 0.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -133,7 +133,7 @@ mod tests { axis: Axis::X, distance: 5.0, }; - let ray = Ray::between(&Vector3::new(6.0, 0.0, 0.0), &Vector3::new(4.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::new(6.0, 0.0, 0.0), Vec3::new(4.0, 0.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -144,7 +144,7 @@ mod tests { axis: Axis::X, distance: 2.0, }; - let ray = Ray::between(&Vector3::new(1.0, 1.0, 0.0), &(Vector3::new(3.0, 3.0, 0.0))); + let ray = Ray::between(Vec3::new(1.0, 1.0, 0.0), Vec3::new(3.0, 3.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -155,7 +155,7 @@ mod tests { axis: Axis::Y, distance: 2.0, }; - let ray = Ray::between(&Vector3::new(1.0, 1.0, 0.0), &Vector3::new(3.0, 3.0, 0.0)); + let ray = Ray::between(Vec3::new(1.0, 1.0, 0.0), Vec3::new(3.0, 3.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -166,7 +166,7 @@ mod tests { axis: Axis::Y, distance: 2.0, }; - let ray = Ray::between(&Vector3::new(3.0, 1.0, 0.0), &Vector3::new(1.0, 3.0, 0.0)); + let ray = Ray::between(Vec3::new(3.0, 1.0, 0.0), Vec3::new(1.0, 3.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), Some(0.5)); } @@ -177,7 +177,7 @@ mod tests { axis: Axis::X, distance: 2.0, }; - let ray = Ray::between(&Vector3::new(0.0, 0.0, 0.0), &(Vector3::new(0.0, 1.0, 0.0))); + let ray = Ray::between(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 1.0, 0.0)); assert_eq!(plane.intersect_ray(&ray), None); } @@ -188,11 +188,11 @@ mod tests { axis: Axis::Y, distance: 2.0, }; - let ray = Ray::between(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(2.0, 4.0, 6.0)); + let ray = Ray::between(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 4.0, 6.0)); assert_eq!( plane.intersect_ray_point(&ray), - Some(Vector3::new(1.0, 2.0, 3.0)) + Some(Vec3::new(1.0, 2.0, 3.0)) ); } } diff --git a/geometry/src/axial_triangle.rs b/geometry/src/axial_triangle.rs index 14ffe91e..ab197949 100644 --- a/geometry/src/axial_triangle.rs +++ b/geometry/src/axial_triangle.rs @@ -1,4 +1,4 @@ -use nalgebra::{Vector2, Vector3}; +use glam::{Vec2, Vec3}; use crate::{ aabb::Aabb, @@ -12,21 +12,21 @@ use crate::{ #[derive(Clone, Debug, PartialEq)] pub struct AxiallyAlignedTriangle { pub plane: Aap, - pub v0: Vector2, - pub v1: Vector2, - pub v2: Vector2, + pub v0: Vec2, + pub v1: Vec2, + pub v2: Vec2, } impl AxiallyAlignedTriangle { - pub fn base0(&self) -> Vector2 { + pub fn base0(&self) -> Vec2 { self.v1 - self.v0 } - pub fn base1(&self) -> Vector2 { + pub fn base1(&self) -> Vec2 { self.v2 - self.v0 } - pub fn param(&self, u: f32, v: f32) -> Vector2 { + pub fn param(&self, u: f32, v: f32) -> Vec2 { debug_assert!(u >= 0.0 && v >= 0.0 && u + v <= 1.0); self.v0 + u * self.base0() + v * self.base1() } @@ -39,7 +39,7 @@ impl AxiallyAlignedTriangle { ] } - pub fn intersect_point(&self, point: Vector2) -> Option { + pub fn intersect_point(&self, point: Vec2) -> Option { let base1 = self.v1 - self.v0; let base2 = self.v2 - self.v0; let s = point - self.v0; @@ -65,13 +65,13 @@ impl AxiallyAlignedTriangle { } impl Geometry for AxiallyAlignedTriangle { - fn min(&self) -> Vector3 { - let p = self.v0.inf(&self.v1.inf(&self.v2)); + fn min(&self) -> Vec3 { + let p = self.v0.min(self.v1.min(self.v2)); self.plane.axis.add_to(p, self.plane.distance) } - fn max(&self) -> Vector3 { - let p = self.v0.sup(&self.v1.sup(&self.v2)); + fn max(&self) -> Vec3 { + let p = self.v0.max(self.v1.max(self.v2)); self.plane.axis.add_to(p, self.plane.distance) } @@ -103,8 +103,8 @@ impl Geometry for AxiallyAlignedTriangle { } let start = (clipped[0], clipped[0]); let (min, max) = clipped[1..] - .iter() - .fold(start, |(min, max), b| (min.inf(b), max.sup(b))); + .into_iter() + .fold(start, |(min, max), b| (min.min(*b), max.max(*b))); Some(Aabb::from_extents(min, max)) } @@ -121,20 +121,20 @@ mod tests { axis: Axis::X, distance: 0.0, }, - v0: Vector2::new(0.0, 0.0), - v1: Vector2::new(1.0, 0.0), - v2: Vector2::new(0.0, 1.0), + v0: Vec2::new(0.0, 0.0), + v1: Vec2::new(1.0, 0.0), + v2: Vec2::new(0.0, 1.0), }; #[test] fn intersect_point_outside_triangle() { - assert_eq!(TEST_TRIANGLE.intersect_point(Vector2::new(2.0, 2.0)), None); + assert_eq!(TEST_TRIANGLE.intersect_point(Vec2::new(2.0, 2.0)), None); } #[test] fn intersect_point_at_v1() { assert_eq!( - TEST_TRIANGLE.intersect_point(Vector2::new(1.0, 0.0)), + TEST_TRIANGLE.intersect_point(Vec2::new(1.0, 0.0)), Some(Intersection::new(1.0, 0.0)) ); } @@ -142,7 +142,7 @@ mod tests { #[test] fn intersect_point_at_v2() { assert_eq!( - TEST_TRIANGLE.intersect_point(Vector2::new(0.0, 1.0)), + TEST_TRIANGLE.intersect_point(Vec2::new(0.0, 1.0)), Some(Intersection::new(0.0, 1.0)) ); } @@ -150,7 +150,7 @@ mod tests { #[test] fn intersect_point_at_middle_of_edge3() { assert_eq!( - TEST_TRIANGLE.intersect_point(Vector2::new(0.5, 0.5)), + TEST_TRIANGLE.intersect_point(Vec2::new(0.5, 0.5)), Some(Intersection::new(0.5, 0.5)) ); } @@ -162,20 +162,20 @@ mod tests { axis: Axis::X, distance: 0.0, }, - v0: Vector2::new(0.0, 0.0), - v1: Vector2::new(1.0, 0.0), - v2: Vector2::new(0.0, 1.0), + v0: Vec2::new(0.0, 0.0), + v1: Vec2::new(1.0, 0.0), + v2: Vec2::new(0.0, 1.0), }; let negative = AxiallyAlignedTriangle { plane: Aap { axis: Axis::X, distance: 0.0, }, - v0: Vector2::new(0.0, 0.0), - v1: Vector2::new(0.0, 1.0), - v2: Vector2::new(1.0, 0.0), + v0: Vec2::new(0.0, 0.0), + v1: Vec2::new(0.0, 1.0), + v2: Vec2::new(1.0, 0.0), }; - let point = Vector2::new(0.5, 0.0); + let point = Vec2::new(0.5, 0.0); assert_eq!( positive.intersect_point(point), diff --git a/geometry/src/axis.rs b/geometry/src/axis.rs index 400bec1e..053efdb4 100644 --- a/geometry/src/axis.rs +++ b/geometry/src/axis.rs @@ -1,4 +1,4 @@ -use nalgebra::{Vector2, Vector3}; +use glam::{Vec2, Vec3, Vec3Swizzles}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Axis { @@ -17,23 +17,23 @@ impl Axis { } } - pub fn as_vector3(&self, v: f32) -> Vector3 { + pub fn as_vector3(&self, v: f32) -> Vec3 { match self { - Axis::X => Vector3::new(v, 0.0, 0.0), - Axis::Y => Vector3::new(0.0, v, 0.0), - Axis::Z => Vector3::new(0.0, 0.0, v), + Axis::X => Vec3::new(v, 0.0, 0.0), + Axis::Y => Vec3::new(0.0, v, 0.0), + Axis::Z => Vec3::new(0.0, 0.0, v), } } - pub fn add_to(&self, v: Vector2, s: f32) -> Vector3 { + pub fn add_to(&self, v: Vec2, s: f32) -> Vec3 { match self { - Axis::X => Vector3::new(s, v.x, v.y), - Axis::Y => Vector3::new(v.x, s, v.y), - Axis::Z => Vector3::new(v.x, v.y, s), + Axis::X => Vec3::new(s, v.x, v.y), + Axis::Y => Vec3::new(v.x, s, v.y), + Axis::Z => Vec3::new(v.x, v.y, s), } } - pub fn remove_from(&self, v: Vector3) -> Vector2 { + pub fn remove_from(&self, v: Vec3) -> Vec2 { match self { Axis::X => v.yz(), Axis::Y => v.xz(), @@ -42,7 +42,7 @@ impl Axis { } } -impl std::ops::Index for Vector3 { +impl std::ops::Index for Vec3 { type Output = f32; #[inline] fn index(&self, idx: Axis) -> &f32 { @@ -50,7 +50,7 @@ impl std::ops::Index for Vector3 { } } -impl std::ops::IndexMut for Vector3 { +impl std::ops::IndexMut for Vec3 { #[inline] fn index_mut(&mut self, idx: Axis) -> &mut f32 { &mut self[idx as usize] diff --git a/geometry/src/bound.rs b/geometry/src/bound.rs index b95e4920..e92ecd0b 100644 --- a/geometry/src/bound.rs +++ b/geometry/src/bound.rs @@ -1,7 +1,7 @@ use crate::{aabb::Aabb, Geometry}; pub fn combine_bounding_boxes(a: &Aabb, b: &Aabb) -> Aabb { - Aabb::from_extents(a.min().inf(&b.min()), a.max().sup(&b.max())) + Aabb::from_extents(a.min().min(b.min()), a.max().max(b.max())) } pub fn geometries_bounding_box(geometries: &[G]) -> Aabb @@ -14,15 +14,15 @@ where let mut a = geometries[0].min(); let mut b = geometries[0].max(); for triangle in geometries { - a = a.inf(&triangle.min()); - b = b.sup(&triangle.max()); + a = a.min(triangle.min()); + b = b.max(triangle.max()); } Aabb::from_extents(a, b) } #[cfg(test)] mod tests { - use nalgebra::Vector3; + use glam::Vec3; use crate::triangle::Triangle; @@ -32,20 +32,20 @@ mod tests { fn two_triangles_give_expected_min_max() { let triangles = [ Triangle { - v0: Vector3::new(1., 1., 0.), - v1: Vector3::new(1., 1., 1.), - v2: Vector3::new(0., 0., 0.), + v0: Vec3::new(1., 1., 0.), + v1: Vec3::new(1., 1., 1.), + v2: Vec3::new(0., 0., 0.), }, Triangle { - v0: Vector3::new(-1., -1., 0.), - v1: Vector3::new(-1., -1., -1.), - v2: Vector3::new(0., 0., 0.), + v0: Vec3::new(-1., -1., 0.), + v1: Vec3::new(-1., -1., -1.), + v2: Vec3::new(0., 0., 0.), }, ]; let actual = geometries_bounding_box(&triangles); - let expected = Aabb::from_extents(Vector3::new(-1., -1., -1.), Vector3::new(1., 1., 1.)); + let expected = Aabb::from_extents(Vec3::new(-1., -1., -1.), Vec3::new(1., 1., 1.)); assert_eq!(actual, expected); } } diff --git a/geometry/src/clip.rs b/geometry/src/clip.rs index 18ea085d..b4695285 100644 --- a/geometry/src/clip.rs +++ b/geometry/src/clip.rs @@ -1,17 +1,12 @@ use arrayvec::ArrayVec; -use nalgebra::Vector3; +use glam::Vec3; use crate::{aabb::Aabb, aap::Aap, ray::Ray}; /// Clip Triangle against AABB. /// /// Implements the Sutherland-Hodgman algorithm. -pub fn clip_triangle_aabb( - v0: &Vector3, - v1: &Vector3, - v2: &Vector3, - aabb: &Aabb, -) -> ArrayVec, 6> { +pub fn clip_triangle_aabb(v0: &Vec3, v1: &Vec3, v2: &Vec3, aabb: &Aabb) -> ArrayVec { let aabb_min = aabb.min(); let aabb_max = aabb.max(); let clip_planes = [ @@ -23,7 +18,7 @@ pub fn clip_triangle_aabb( (true, Aap::new_z(aabb_max.z)), ]; - let is_inside = |clip_plane: &(bool, Aap), point: &Vector3| { + let is_inside = |clip_plane: (bool, Aap), point: Vec3| { if clip_plane.0 { point[clip_plane.1.axis] <= clip_plane.1.distance } else { @@ -31,7 +26,7 @@ pub fn clip_triangle_aabb( } }; - let mut output = ArrayVec::, 6>::new(); + let mut output = ArrayVec::::new(); output.push(*v1); output.push(*v2); output.push(*v0); @@ -41,14 +36,14 @@ pub fn clip_triangle_aabb( output.clear(); for (i, b) in input.iter().enumerate() { let a = input[if i == 0 { input.len() - 1 } else { i - 1 }]; - let ray = Ray::between(&a, b); + let ray = Ray::between(a, *b); let intersecting = plane.intersect_ray_point(&ray); - if is_inside(&clip_plane, b) { - if !is_inside(&clip_plane, &a) { + if is_inside(clip_plane, *b) { + if !is_inside(clip_plane, a) { output.push(aabb.clamp(intersecting.unwrap())); } output.push(*b); - } else if is_inside(&clip_plane, &a) { + } else if is_inside(clip_plane, a) { output.push(aabb.clamp(intersecting.unwrap())); } } @@ -63,10 +58,10 @@ mod tests { #[test] fn clip_triangle_completely_enclosed_in_box() { - let v0 = Vector3::new(1.0, 1.0, 1.0); - let v1 = Vector3::new(2.0, 1.0, 1.0); - let v2 = Vector3::new(2.0, 2.0, 1.0); - let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(3.0, 3.0, 3.0)); + let v0 = Vec3::new(1.0, 1.0, 1.0); + let v1 = Vec3::new(2.0, 1.0, 1.0); + let v2 = Vec3::new(2.0, 2.0, 1.0); + let aabb = Aabb::from_extents(Vec3::new(0.0, 0.0, 0.0), Vec3::new(3.0, 3.0, 3.0)); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); @@ -76,87 +71,84 @@ mod tests { #[test] fn clip_triangle_above_box() { - let v0 = Vector3::new(0.0, 2.0, 0.0); - let v1 = Vector3::new(1.0, 2.0, 0.0); - let v2 = Vector3::new(1.0, 2.0, 1.0); - let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let v0 = Vec3::new(0.0, 2.0, 0.0); + let v1 = Vec3::new(1.0, 2.0, 0.0); + let v2 = Vec3::new(1.0, 2.0, 1.0); + let aabb = Aabb::from_extents(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0)); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); - let expected: &[Vector3] = &[]; + let expected: &[Vec3] = &[]; assert_eq!(actual.as_slice(), expected); } #[test] fn clip_triangle_below_box() { - let v0 = Vector3::new(0.0, -1.0, 0.0); - let v1 = Vector3::new(1.0, -1.0, 0.0); - let v2 = Vector3::new(1.0, -1.0, 1.0); - let aabb = Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); + let v0 = Vec3::new(0.0, -1.0, 0.0); + let v1 = Vec3::new(1.0, -1.0, 0.0); + let v2 = Vec3::new(1.0, -1.0, 1.0); + let aabb = Aabb::from_extents(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0)); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); - let expected: &[Vector3] = &[]; + let expected: &[Vec3] = &[]; assert_eq!(actual.as_slice(), expected); } #[test] fn clip_triangle_in_zplane_with_all_edges_intersecting_box_sides() { - let v0 = Vector3::new(0.0, 0.0, 0.0); - let v1 = Vector3::new(12.0, 0.0, 0.0); - let v2 = Vector3::new(6.0, 6.0, 0.0); - let aabb = Aabb::from_extents(Vector3::new(2.0, -1.0, 0.0), Vector3::new(10.0, 4.0, 0.0)); + let v0 = Vec3::new(0.0, 0.0, 0.0); + let v1 = Vec3::new(12.0, 0.0, 0.0); + let v2 = Vec3::new(6.0, 6.0, 0.0); + let aabb = Aabb::from_extents(Vec3::new(2.0, -1.0, 0.0), Vec3::new(10.0, 4.0, 0.0)); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); let expected = [ - Vector3::new(2.0, 0.0, 0.0), - Vector3::new(10.0, 0.0, 0.0), - Vector3::new(10.0, 2.0, 0.0), - Vector3::new(8.0, 4.0, 0.0), - Vector3::new(4.0, 4.0, 0.0), - Vector3::new(2.0, 2.0, 0.0), + Vec3::new(2.0, 0.0, 0.0), + Vec3::new(10.0, 0.0, 0.0), + Vec3::new(10.0, 2.0, 0.0), + Vec3::new(8.0, 4.0, 0.0), + Vec3::new(4.0, 4.0, 0.0), + Vec3::new(2.0, 2.0, 0.0), ]; assert_eq!(actual.as_slice(), expected); } #[test] fn clip_rounding_error_in_ray_param_calculation_example_1() { - let v0 = Vector3::new(-1.0, -1.0, -1.0); - let v1 = Vector3::new(-1.0, -1.0, 1.0); - let v2 = Vector3::new(1.0, -1.0, -1.0); - let aabb = Aabb::from_extents( - Vector3::new(-1.5, -1.5012, -1.5), - Vector3::new(-0.076, 1.5, 1.0), - ); + let v0 = Vec3::new(-1.0, -1.0, -1.0); + let v1 = Vec3::new(-1.0, -1.0, 1.0); + let v2 = Vec3::new(1.0, -1.0, -1.0); + let aabb = Aabb::from_extents(Vec3::new(-1.5, -1.5012, -1.5), Vec3::new(-0.076, 1.5, 1.0)); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); - let expected: &[Vector3] = &[]; + let expected: &[Vec3] = &[]; let outside = actual .into_iter() - .filter(|p| !aabb.contains(p)) - .collect::, 1>>(); + .filter(|p| !aabb.contains(*p)) + .collect::>(); assert_eq!(outside.as_slice(), expected); } #[test] fn clip_rounding_error_in_ray_param_calculation_example_2() { - let v0 = Vector3::new(-1.0, -1.0, -1.0); - let v1 = Vector3::new(-1.0, -1.0, 1.0); - let v2 = Vector3::new(1.0, -1.0, -1.0); + let v0 = Vec3::new(-1.0, -1.0, -1.0); + let v1 = Vec3::new(-1.0, -1.0, 1.0); + let v2 = Vec3::new(1.0, -1.0, -1.0); let aabb = Aabb::from_extents( - Vector3::new(-1.5, -1.5012, -1.5), - Vector3::new(-0.076, 0.075999975, 0.075999975), + Vec3::new(-1.5, -1.5012, -1.5), + Vec3::new(-0.076, 0.075999975, 0.075999975), ); let actual = clip_triangle_aabb(&v0, &v1, &v2, &aabb); - let expected: &[Vector3] = &[]; + let expected: &[Vec3] = &[]; let outside = actual .into_iter() - .filter(|p| !aabb.contains(p)) - .collect::, 1>>(); + .filter(|p| !aabb.contains(*p)) + .collect::>(); assert_eq!(outside.as_slice(), expected); } } diff --git a/geometry/src/geometric.rs b/geometry/src/geometric.rs index 1e30c687..b540e4cc 100644 --- a/geometry/src/geometric.rs +++ b/geometry/src/geometric.rs @@ -1,8 +1,9 @@ +use glam::Vec3; + use crate::{ aabb::Aabb, axial_triangle::AxiallyAlignedTriangle, intersection::RayIntersection, ray::Ray, triangle::Triangle, Geometry, }; -use nalgebra::Vector3; #[derive(Clone, Debug, PartialEq)] pub enum Geometric { @@ -12,7 +13,7 @@ pub enum Geometric { impl Geometry for Geometric { #[inline] - fn min(&self) -> Vector3 { + fn min(&self) -> Vec3 { match self { Geometric::Triangle(t) => t.min(), Geometric::AxiallyAlignedTriangle(t) => t.min(), @@ -20,7 +21,7 @@ impl Geometry for Geometric { } #[inline] - fn max(&self) -> Vector3 { + fn max(&self) -> Vec3 { match self { Geometric::Triangle(t) => t.max(), Geometric::AxiallyAlignedTriangle(t) => t.max(), diff --git a/geometry/src/lib.rs b/geometry/src/lib.rs index ed71d657..36a4de33 100644 --- a/geometry/src/lib.rs +++ b/geometry/src/lib.rs @@ -1,6 +1,6 @@ use aabb::Aabb; +use glam::Vec3; use intersection::RayIntersection; -use nalgebra::Vector3; use ray::Ray; pub mod aabb; @@ -16,8 +16,8 @@ pub mod sphere; pub mod triangle; pub trait Geometry { - fn min(&self) -> Vector3; - fn max(&self) -> Vector3; + fn min(&self) -> Vec3; + fn max(&self) -> Vec3; fn intersect_ray(&self, ray: &Ray) -> Option; fn clip_aabb(&self, aabb: &Aabb) -> Option; diff --git a/geometry/src/ray.rs b/geometry/src/ray.rs index da16195f..b6b8f8df 100644 --- a/geometry/src/ray.rs +++ b/geometry/src/ray.rs @@ -1,15 +1,15 @@ -use nalgebra::Vector3; +use glam::Vec3; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Ray { - pub origin: Vector3, - pub direction: Vector3, + pub origin: Vec3, + pub direction: Vec3, } impl Ray { - pub fn between(a: &Vector3, b: &Vector3) -> Ray { + pub fn between(a: Vec3, b: Vec3) -> Ray { Ray { - origin: *a, + origin: a, direction: b - a, } } @@ -21,7 +21,7 @@ impl Ray { } } - pub fn param(&self, t: f32) -> Vector3 { + pub fn param(&self, t: f32) -> Vec3 { self.origin + t * self.direction } diff --git a/geometry/src/sphere.rs b/geometry/src/sphere.rs index 08b74a86..5afbe939 100644 --- a/geometry/src/sphere.rs +++ b/geometry/src/sphere.rs @@ -1,24 +1,24 @@ -use nalgebra::Vector3; +use glam::Vec3; use crate::{aabb::Aabb, intersection::RayIntersection, ray::Ray, Geometry}; #[derive(Clone, Debug, PartialEq)] pub struct Sphere { - pub center: Vector3, + pub center: Vec3, pub radius: f32, } impl Geometry for Sphere { - fn min(&self) -> Vector3 { - Vector3::new( + fn min(&self) -> Vec3 { + Vec3::new( self.center.x - self.radius, self.center.y - self.radius, self.center.z - self.radius, ) } - fn max(&self) -> Vector3 { - Vector3::new( + fn max(&self) -> Vec3 { + Vec3::new( self.center.x + self.radius, self.center.y + self.radius, self.center.z + self.radius, @@ -27,9 +27,9 @@ impl Geometry for Sphere { fn intersect_ray(&self, ray: &Ray) -> Option { let p = ray.origin - self.center; - let a = ray.direction.dot(&ray.direction); - let b = 2.0 * ray.direction.dot(&p); - let c = p.dot(&p) - self.radius * self.radius; + let a = ray.direction.dot(ray.direction); + let b = 2.0 * ray.direction.dot(p); + let c = p.dot(p) - self.radius * self.radius; let discriminant = b * b - 4.0 * a * c; if discriminant < 0.0 { return None; @@ -53,10 +53,10 @@ mod tests { #[test] fn intersect_ray_axially_through_center() { let sphere = Sphere { - center: Vector3::new(1.0, 0.0, 0.0), + center: Vec3::new(1.0, 0.0, 0.0), radius: 1.0, }; - let ray = Ray::between(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(2.0, 0.0, 0.0)); + let ray = Ray::between(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 0.0, 0.0)); let actual = sphere.intersect_ray(&ray); @@ -73,10 +73,10 @@ mod tests { #[test] fn intersect_ray_diagonally_through_center() { let sphere = Sphere { - center: Vector3::new(1.0, 1.0, 1.0), + center: Vec3::new(1.0, 1.0, 1.0), radius: 1.0, }; - let ray = Ray::between(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(2.0, 2.0, 2.0)); + let ray = Ray::between(Vec3::new(0.0, 0.0, 0.0), Vec3::new(2.0, 2.0, 2.0)); let actual = sphere.intersect_ray(&ray); @@ -93,10 +93,10 @@ mod tests { #[test] fn intersect_ray_touching_in_a_point() { let sphere = Sphere { - center: Vector3::new(1.0, 0.0, 0.0), + center: Vec3::new(1.0, 0.0, 0.0), radius: 1.0, }; - let ray = Ray::between(&Vector3::new(0.0, 1.0, 0.0), &Vector3::new(2.0, 1.0, 0.0)); + let ray = Ray::between(Vec3::new(0.0, 1.0, 0.0), Vec3::new(2.0, 1.0, 0.0)); let actual = sphere.intersect_ray(&ray); @@ -113,10 +113,10 @@ mod tests { #[test] fn intersect_ray_not_intersecting() { let sphere = Sphere { - center: Vector3::new(1.0, 0.0, 0.0), + center: Vec3::new(1.0, 0.0, 0.0), radius: 1.0, }; - let ray = Ray::between(&Vector3::new(0.0, 2.0, 0.0), &Vector3::new(2.0, 2.0, 0.0)); + let ray = Ray::between(Vec3::new(0.0, 2.0, 0.0), Vec3::new(2.0, 2.0, 0.0)); let actual = sphere.intersect_ray(&ray); diff --git a/geometry/src/triangle.rs b/geometry/src/triangle.rs index af872ea9..6a21ba1b 100644 --- a/geometry/src/triangle.rs +++ b/geometry/src/triangle.rs @@ -1,4 +1,4 @@ -use nalgebra::Vector3; +use glam::Vec3; use crate::{ aabb::Aabb, aap::Aap, axial_triangle::AxiallyAlignedTriangle, axis::Axis, @@ -7,37 +7,37 @@ use crate::{ #[derive(Clone, Copy, Debug, PartialEq)] pub struct Triangle { - pub v0: Vector3, - pub v1: Vector3, - pub v2: Vector3, + pub v0: Vec3, + pub v1: Vec3, + pub v2: Vec3, } impl Triangle { - pub fn base0(&self) -> Vector3 { + pub fn base0(&self) -> Vec3 { self.v1 - self.v0 } - pub fn base1(&self) -> Vector3 { + pub fn base1(&self) -> Vec3 { self.v2 - self.v0 } - pub fn base_center(&self) -> Vector3 { + pub fn base_center(&self) -> Vec3 { self.v0 + 0.5 * self.base0() + 0.5 * self.base1() } - pub fn edge0(&self) -> Vector3 { + pub fn edge0(&self) -> Vec3 { self.v1 - self.v0 } - pub fn edge1(&self) -> Vector3 { + pub fn edge1(&self) -> Vec3 { self.v2 - self.v1 } - pub fn edge2(&self) -> Vector3 { + pub fn edge2(&self) -> Vec3 { self.v0 - self.v2 } - pub fn param(&self, u: f32, v: f32) -> Vector3 { + pub fn param(&self, u: f32, v: f32) -> Vec3 { assert!(u >= 0.0 && v >= 0.0 && u + v <= 1.0); self.v0 + u * self.base0() + v * self.base1() } @@ -70,36 +70,32 @@ impl Triangle { pub fn intersect_ray(&self, ray: &Ray) -> Option { let base1 = self.base0(); let base2 = self.base1(); - let ray_cross_base2 = ray.direction.cross(&base2); + let ray_cross_base2 = ray.direction.cross(base2); - let det = base1.dot(&ray_cross_base2); + let det = base1.dot(ray_cross_base2); if det == 0.0 { return None; } let inv_det = 1.0 / det; let s = ray.origin - self.v0; - let u = inv_det * s.dot(&ray_cross_base2); + let u = inv_det * s.dot(ray_cross_base2); if !(0.0..=1.0).contains(&u) { return None; } - let s_cross_base1 = s.cross(&base1); - let v = inv_det * ray.direction.dot(&s_cross_base1); + let s_cross_base1 = s.cross(base1); + let v = inv_det * ray.direction.dot(s_cross_base1); if v < 0.0 || (u + v) > 1.0 { return None; } - let t = inv_det * base2.dot(&s_cross_base1); + let t = inv_det * base2.dot(s_cross_base1); Some(RayIntersection { t, u, v }) } /// Check for overlap using the Separating Axis Theorem. pub fn overlaps_aabb(&self, aabb: &Aabb) -> bool { - const U0: Vector3 = Vector3::new(1., 0., 0.); - const U1: Vector3 = Vector3::new(0., 1., 0.); - const U2: Vector3 = Vector3::new(0., 0., 1.); - let center = aabb.center(); let half_size = aabb.half_size(); @@ -111,55 +107,55 @@ impl Triangle { let f1 = v2 - v1; let f2 = v0 - v2; - let test_axis = |axis: Vector3| { - let p0 = v0.dot(&axis); - let p1 = v1.dot(&axis); - let p2 = v2.dot(&axis); - let r = half_size.x * U0.dot(&axis).abs() - + half_size.y * U1.dot(&axis).abs() - + half_size.z * U2.dot(&axis).abs(); + let test_axis = |axis: Vec3| { + let p0 = v0.dot(axis); + let p1 = v1.dot(axis); + let p2 = v2.dot(axis); + let r = half_size.x * Vec3::X.dot(axis).abs() + + half_size.y * Vec3::Y.dot(axis).abs() + + half_size.z * Vec3::Z.dot(axis).abs(); (-p0.max(p1.max(p2))).max(p0.min(p1.min(p2))) > r }; - if test_axis(U0.cross(&f0)) { + if test_axis(Vec3::X.cross(f0)) { return false; } - if test_axis(U0.cross(&f1)) { + if test_axis(Vec3::X.cross(f1)) { return false; } - if test_axis(U0.cross(&f2)) { + if test_axis(Vec3::X.cross(f2)) { return false; } - if test_axis(U1.cross(&f0)) { + if test_axis(Vec3::Y.cross(f0)) { return false; } - if test_axis(U1.cross(&f1)) { + if test_axis(Vec3::Y.cross(f1)) { return false; } - if test_axis(U1.cross(&f2)) { + if test_axis(Vec3::Y.cross(f2)) { return false; } - if test_axis(U2.cross(&f0)) { + if test_axis(Vec3::Z.cross(f0)) { return false; } - if test_axis(U2.cross(&f1)) { + if test_axis(Vec3::Z.cross(f1)) { return false; } - if test_axis(U2.cross(&f2)) { + if test_axis(Vec3::Z.cross(f2)) { return false; } - if test_axis(U0) { + if test_axis(Vec3::X) { return false; } - if test_axis(U1) { + if test_axis(Vec3::Y) { return false; } - if test_axis(U2) { + if test_axis(Vec3::Z) { return false; } - let triangle_normal = f0.cross(&f1); + let triangle_normal = f0.cross(f1); if test_axis(triangle_normal) { return false; } @@ -170,7 +166,7 @@ impl Triangle { impl From<[T; 3]> for Triangle where - T: Into> + Copy, + T: Into + Copy, { fn from(value: [T; 3]) -> Self { Triangle { @@ -182,12 +178,12 @@ where } impl Geometry for Triangle { - fn min(&self) -> Vector3 { - self.v0.inf(&self.v1.inf(&self.v2)) + fn min(&self) -> Vec3 { + self.v0.min(self.v1.min(self.v2)) } - fn max(&self) -> Vector3 { - self.v0.sup(&self.v1.sup(&self.v2)) + fn max(&self) -> Vec3 { + self.v0.max(self.v1.max(self.v2)) } fn intersect_ray(&self, ray: &Ray) -> Option { @@ -201,8 +197,8 @@ impl Geometry for Triangle { } let start = (clipped[0], clipped[0]); let (min, max) = clipped[1..] - .iter() - .fold(start, |(min, max), b| (min.inf(b), max.sup(b))); + .into_iter() + .fold(start, |(min, max), b| (min.min(*b), max.max(*b))); Some(Aabb::from_extents(min, max)) } @@ -215,34 +211,34 @@ mod tests { #[test] fn min_max() { let triangle = Triangle { - v0: Vector3::new(1., 2., 3.), - v1: Vector3::new(4., 5., 6.), - v2: Vector3::new(7., 8., 9.), + v0: Vec3::new(1., 2., 3.), + v1: Vec3::new(4., 5., 6.), + v2: Vec3::new(7., 8., 9.), }; - assert_eq!(triangle.min(), Vector3::new(1., 2., 3.)); - assert_eq!(triangle.max(), Vector3::new(7., 8., 9.)); + assert_eq!(triangle.min(), Vec3::new(1., 2., 3.)); + assert_eq!(triangle.max(), Vec3::new(7., 8., 9.)); } #[test] fn center() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 1., 1.), - v2: Vector3::new(-1., -1., -1.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 1., 1.), + v2: Vec3::new(-1., -1., -1.), }; - assert_eq!(triangle.base_center(), Vector3::new(0., 0., 0.)); + assert_eq!(triangle.base_center(), Vec3::new(0., 0., 0.)); } #[test] fn intersect_ray_through_base_center() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.base_center().x, triangle.base_center().y, -1.), - &Vector3::new(triangle.base_center().x, triangle.base_center().y, 1.), + Vec3::new(triangle.base_center().x, triangle.base_center().y, -1.), + Vec3::new(triangle.base_center().x, triangle.base_center().y, 1.), ); assert_eq!( @@ -258,13 +254,13 @@ mod tests { #[test] fn intersect_ray_through_v0() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v0.x, triangle.v0.y, -1.), - &Vector3::new(triangle.v0.x, triangle.v0.y, 1.), + Vec3::new(triangle.v0.x, triangle.v0.y, -1.), + Vec3::new(triangle.v0.x, triangle.v0.y, 1.), ); assert_eq!( @@ -280,13 +276,13 @@ mod tests { #[test] fn intersect_ray_through_v1() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v1.x, triangle.v1.y, -1.), - &Vector3::new(triangle.v1.x, triangle.v1.y, 1.), + Vec3::new(triangle.v1.x, triangle.v1.y, -1.), + Vec3::new(triangle.v1.x, triangle.v1.y, 1.), ); assert_eq!( @@ -302,13 +298,13 @@ mod tests { #[test] fn intersect_ray_through_v2() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v2.x, triangle.v2.y, -1.), - &Vector3::new(triangle.v2.x, triangle.v2.y, 1.), + Vec3::new(triangle.v2.x, triangle.v2.y, -1.), + Vec3::new(triangle.v2.x, triangle.v2.y, 1.), ); assert_eq!( @@ -324,14 +320,14 @@ mod tests { #[test] fn intersect_ray_through_edge0() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let intersection_point = triangle.v0 + triangle.edge0() / 2.; let ray = Ray::between( - &Vector3::new(intersection_point.x, intersection_point.y, -1.), - &Vector3::new(intersection_point.x, intersection_point.y, 1.), + Vec3::new(intersection_point.x, intersection_point.y, -1.), + Vec3::new(intersection_point.x, intersection_point.y, 1.), ); assert_eq!( @@ -347,14 +343,14 @@ mod tests { #[test] fn intersect_ray_through_edge1() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let intersection_point = triangle.v1 + triangle.edge1() / 2.; let ray = Ray::between( - &Vector3::new(intersection_point.x, intersection_point.y, -1.), - &Vector3::new(intersection_point.x, intersection_point.y, 1.), + Vec3::new(intersection_point.x, intersection_point.y, -1.), + Vec3::new(intersection_point.x, intersection_point.y, 1.), ); assert_eq!( @@ -370,14 +366,14 @@ mod tests { #[test] fn intersect_ray_through_edge2() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let intersection_point = triangle.v2 + triangle.edge2() / 2.; let ray = Ray::between( - &Vector3::new(intersection_point.x, intersection_point.y, -1.), - &Vector3::new(intersection_point.x, intersection_point.y, 1.), + Vec3::new(intersection_point.x, intersection_point.y, -1.), + Vec3::new(intersection_point.x, intersection_point.y, 1.), ); assert_eq!( @@ -393,13 +389,13 @@ mod tests { #[test] fn intersect_ray_parallel_touching() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v0.x, triangle.v0.y, 0.), - &Vector3::new(triangle.v1.x, triangle.v1.y, 0.), + Vec3::new(triangle.v0.x, triangle.v0.y, 0.), + Vec3::new(triangle.v1.x, triangle.v1.y, 0.), ); assert_eq!(triangle.intersect_ray(&ray), None); @@ -408,13 +404,13 @@ mod tests { #[test] fn intersect_ray_parallel_not_touching() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v0.x, triangle.v0.y, 1.), - &Vector3::new(triangle.v1.x, triangle.v1.y, 1.), + Vec3::new(triangle.v0.x, triangle.v0.y, 1.), + Vec3::new(triangle.v1.x, triangle.v1.y, 1.), ); assert_eq!(triangle.intersect_ray(&ray), None); @@ -423,13 +419,13 @@ mod tests { #[test] fn intersect_ray_almost_parallel_touching() { let triangle = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let ray = Ray::between( - &Vector3::new(triangle.v0.x, triangle.v0.y, -0.000001), - &Vector3::new(triangle.v1.x, triangle.v1.y, 0.000001), + Vec3::new(triangle.v0.x, triangle.v0.y, -0.000001), + Vec3::new(triangle.v1.x, triangle.v1.y, 0.000001), ); assert_eq!( @@ -445,16 +441,16 @@ mod tests { #[test] fn intersect_ray_positive_vs_negative_orientation() { let positive = Triangle { - v0: Vector3::new(0.0, 0.0, 0.0), - v1: Vector3::new(1.0, 0.0, 0.0), - v2: Vector3::new(0.0, 1.0, 0.0), + v0: Vec3::new(0.0, 0.0, 0.0), + v1: Vec3::new(1.0, 0.0, 0.0), + v2: Vec3::new(0.0, 1.0, 0.0), }; let negative = Triangle { - v0: Vector3::new(0.0, 0.0, 0.0), - v1: Vector3::new(0.0, 1.0, 0.0), - v2: Vector3::new(1.0, 0.0, 0.0), + v0: Vec3::new(0.0, 0.0, 0.0), + v1: Vec3::new(0.0, 1.0, 0.0), + v2: Vec3::new(1.0, 0.0, 0.0), }; - let ray = Ray::between(&Vector3::new(0.5, 0.0, -1.0), &Vector3::new(0.5, 0.0, 1.0)); + let ray = Ray::between(Vec3::new(0.5, 0.0, -1.0), Vec3::new(0.5, 0.0, 1.0)); assert_eq!( positive.intersect_ray(&ray), @@ -477,11 +473,11 @@ mod tests { #[test] fn overlaps_aabb_triangle_completely_inside() { let triangle = Triangle { - v0: Vector3::new(1., 1., 1.), - v1: Vector3::new(2., 1., 1.), - v2: Vector3::new(1., 2., 1.), + v0: Vec3::new(1., 1., 1.), + v1: Vec3::new(2., 1., 1.), + v2: Vec3::new(1., 2., 1.), }; - let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vec3::new(0., 0., 0.), Vec3::new(2., 2., 2.)); assert!(triangle.overlaps_aabb(&aabb)); } @@ -489,11 +485,11 @@ mod tests { #[test] fn overlaps_aabb_triangle_contained_in_one_face() { let triangle = Triangle { - v0: Vector3::new(1., 1., 2.), - v1: Vector3::new(2., 1., 2.), - v2: Vector3::new(1., 2., 2.), + v0: Vec3::new(1., 1., 2.), + v1: Vec3::new(2., 1., 2.), + v2: Vec3::new(1., 2., 2.), }; - let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vec3::new(0., 0., 0.), Vec3::new(2., 2., 2.)); assert!(triangle.overlaps_aabb(&aabb)); } @@ -501,11 +497,11 @@ mod tests { #[test] fn overlaps_aabb_triangle_outside() { let triangle = Triangle { - v0: Vector3::new(10., 10., 10.), - v1: Vector3::new(11., 10., 10.), - v2: Vector3::new(10., 11., 10.), + v0: Vec3::new(10., 10., 10.), + v1: Vec3::new(11., 10., 10.), + v2: Vec3::new(10., 11., 10.), }; - let aabb = Aabb::from_extents(Vector3::new(0., 0., 0.), Vector3::new(2., 2., 2.)); + let aabb = Aabb::from_extents(Vec3::new(0., 0., 0.), Vec3::new(2., 2., 2.)); assert!(!triangle.overlaps_aabb(&aabb)); } diff --git a/kdtree-reducer-cli/Cargo.toml b/kdtree-reducer-cli/Cargo.toml index 7f6990c5..61dbb5e7 100644 --- a/kdtree-reducer-cli/Cargo.toml +++ b/kdtree-reducer-cli/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" clap = { version = "4.5.4", features = ["derive"] } geometry = { version = "1.0.0", path = "../geometry" } kdtree = { version = "1.0.0", path = "../kdtree" } -nalgebra = { version = "0.33.0", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["std", "small_rng"] } rayon = "1.10.0" wavefront = { version = "1.0.0", path = "../wavefront" } diff --git a/kdtree-tester-cli/Cargo.toml b/kdtree-tester-cli/Cargo.toml index 7968a090..5838b3e4 100644 --- a/kdtree-tester-cli/Cargo.toml +++ b/kdtree-tester-cli/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] clap = { version = "4.5.4", features = ["derive"] } geometry = { version = "1.0.0", path = "../geometry" } +glam = "0.28.0" kdtree = { version = "1.0.0", path = "../kdtree" } -nalgebra = { version = "0.33.0", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["std"] } rayon = "1.10.0" scene = { version = "1.0.0", path = "../scene" } diff --git a/kdtree-tester-cli/src/main.rs b/kdtree-tester-cli/src/main.rs index a501a02f..897a85a0 100644 --- a/kdtree-tester-cli/src/main.rs +++ b/kdtree-tester-cli/src/main.rs @@ -1,11 +1,11 @@ use clap::Parser; use geometry::{intersection::RayIntersection, ray::Ray, Geometry}; +use glam::Vec2; use kdtree::{ build::build_kdtree, build_sah::{self, SahKdTreeBuilder}, KdTree, }; -use nalgebra::Vector2; use rand::{rngs::SmallRng, SeedableRng}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use scene::{camera::Pinhole, Scene}; @@ -141,7 +141,7 @@ impl RayBouncer { let material = triangle.material.as_ref(); // TODO: How to chose offset? - let offset = 0.00001 * n.into_inner(); + let offset = 0.00001 * n; let point = ray.param(intersection.t); let point_above = point + offset; let point_below = point - offset; @@ -151,7 +151,7 @@ impl RayBouncer { .lights .iter() .filter_map(|light| { - let shadow_ray = Ray::between(&point_above, &sample_light(light, rng)); + let shadow_ray = Ray::between(point_above, sample_light(light, rng)); let shadow = self.checked_ray_intersect(&shadow_ray, 0.0..=1.0); (!shadow.is_valid()).then_some(shadow) }) @@ -162,12 +162,12 @@ impl RayBouncer { let sample = material.sample(&IncomingRay { wi, n, uv }, rng); let next_ray = Ray { - origin: if sample.wo.dot(&n) >= 0.0 { + origin: if sample.wo.dot(n) >= 0.0 { point_above } else { point_below }, - direction: *sample.wo, + direction: sample.wo, }; self.bounce(rng, &next_ray, accumulated_bounces + 1) @@ -176,8 +176,8 @@ impl RayBouncer { fn bounce_pixel(&self, pixel: (u32, u32)) -> Option { let (x, y) = pixel; let mut rng = SmallRng::seed_from_u64((y * self.size.height + x) as u64); - let pixel_center = Vector2::new(x as f32, y as f32) + uniform_sample_unit_square(&mut rng); - let scene_direction = pixel_center.component_div(&self.size.as_vec2()); + let pixel_center = Vec2::new(x as f32, y as f32) + uniform_sample_unit_square(&mut rng); + let scene_direction = pixel_center / self.size.as_vec2(); let ray = self.camera.ray(scene_direction.x, scene_direction.y); self.bounce(&mut rng, &ray, 0) } @@ -194,8 +194,8 @@ impl Size { Size { width, height } } - fn as_vec2(self) -> Vector2 { - Vector2::new(self.width as f32, self.height as f32) + fn as_vec2(self) -> Vec2 { + Vec2::new(self.width as f32, self.height as f32) } } diff --git a/kdtree/Cargo.toml b/kdtree/Cargo.toml index e323e71a..4a72d205 100644 --- a/kdtree/Cargo.toml +++ b/kdtree/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] geometry = { version = "1.0.0", path = "../geometry" } -nalgebra = { version = "0.33.0", default-features = false } +glam = "0.28.0" rayon = { version = "1.10.0", default-features = false } smallvec = "1.13.2" textwrap = "0.16.1" diff --git a/kdtree/src/build_sah.rs b/kdtree/src/build_sah.rs index 61f734e8..0d5a5b29 100644 --- a/kdtree/src/build_sah.rs +++ b/kdtree/src/build_sah.rs @@ -1,4 +1,4 @@ -use nalgebra::Vector3; +use glam::Vec3; use rayon::prelude::*; use geometry::{aabb::Aabb, aap::Aap, bound::geometries_bounding_box, geometric::Geometric}; @@ -69,7 +69,7 @@ impl SahKdTreeBuilder { impl KdTreeBuilder for SahKdTreeBuilder { fn starting_box(&self) -> KdCell { KdCell::new( - geometries_bounding_box(&self.geometries).enlarge(&Vector3::new(1.0, 1.0, 1.0)), + geometries_bounding_box(&self.geometries).enlarge(Vec3::new(1.0, 1.0, 1.0)), (0u32..self.geometries.len() as u32).collect(), ) } @@ -123,9 +123,9 @@ mod tests { #[test] fn non_axially_aligned_triangle() { let triangle = Triangle { - v0: Vector3::new(0.0, 0.0, 0.0), - v1: Vector3::new(1.0, 0.0, 0.0), - v2: Vector3::new(1.0, 1.0, 1.0), + v0: Vec3::new(0.0, 0.0, 0.0), + v1: Vec3::new(1.0, 0.0, 0.0), + v2: Vec3::new(1.0, 1.0, 1.0), }; let builder = SahKdTreeBuilder { traverse_cost: 0.1, @@ -170,9 +170,9 @@ mod tests { #[test] fn axially_aligned_triangle() { let triangle = Triangle { - v0: Vector3::new(0.0, 0.0, 0.0), - v1: Vector3::new(1.0, 0.0, 0.0), - v2: Vector3::new(1.0, 1.0, 0.0), + v0: Vec3::new(0.0, 0.0, 0.0), + v1: Vec3::new(1.0, 0.0, 0.0), + v2: Vec3::new(1.0, 1.0, 0.0), }; let builder = SahKdTreeBuilder { traverse_cost: 1.0, diff --git a/kdtree/src/lib.rs b/kdtree/src/lib.rs index cc20b0f5..c54a0570 100644 --- a/kdtree/src/lib.rs +++ b/kdtree/src/lib.rs @@ -214,7 +214,7 @@ impl KdTree { #[cfg(test)] mod tests { use geometry::{axis::Axis, triangle::Triangle}; - use nalgebra::Vector3; + use glam::Vec3; use super::*; @@ -224,7 +224,7 @@ mod tests { root: Box::new(KdNode::Leaf(vec![])), geometries: vec![], }; - let ray = Ray::between(&Vector3::new(0., 0., 0.), &Vector3::new(1., 1., 1.)); + let ray = Ray::between(Vec3::new(0., 0., 0.), Vec3::new(1., 1., 1.)); assert_eq!(tree.intersect(&ray, 0.0..=1.0), None); } @@ -232,14 +232,14 @@ mod tests { #[test] fn intersect_ray_intersecting_split_plane_and_both_triangles() { let triangle0 = Triangle { - v0: Vector3::new(0., 0., -1.), - v1: Vector3::new(2., 0., -1.), - v2: Vector3::new(2., 2., -1.), + v0: Vec3::new(0., 0., -1.), + v1: Vec3::new(2., 0., -1.), + v2: Vec3::new(2., 2., -1.), }; let triangle1 = Triangle { - v0: Vector3::new(0., 0., 1.), - v1: Vector3::new(2., 0., 1.), - v2: Vector3::new(2., 2., 1.), + v0: Vec3::new(0., 0., 1.), + v1: Vec3::new(2., 0., 1.), + v2: Vec3::new(2., 2., 1.), }; let tree = KdTree { root: Box::new(KdNode::Node { @@ -252,7 +252,7 @@ mod tests { }), geometries: vec![triangle0.into(), triangle1.into()], }; - let ray = Ray::between(&Vector3::new(1., 1., -2.), &Vector3::new(1., 1., 2.)); + let ray = Ray::between(Vec3::new(1., 1., -2.), Vec3::new(1., 1., 2.)); assert_eq!( tree.intersect(&ray, 0.0..=1.0), @@ -267,14 +267,14 @@ mod tests { #[test] fn intersect_ray_parallel_to_split_plane_and_intersecting_one_triangle() { let triangle0 = Triangle { - v0: Vector3::new(0., 0., 0.), - v1: Vector3::new(1., 0., 0.), - v2: Vector3::new(0., 1., 0.), + v0: Vec3::new(0., 0., 0.), + v1: Vec3::new(1., 0., 0.), + v2: Vec3::new(0., 1., 0.), }; let triangle1 = Triangle { - v0: Vector3::new(1., 0., 0.), - v1: Vector3::new(2., 0., 0.), - v2: Vector3::new(2., 1., 0.), + v0: Vec3::new(1., 0., 0.), + v1: Vec3::new(2., 0., 0.), + v2: Vec3::new(2., 1., 0.), }; let tree = KdTree { root: KdNode::new_node( @@ -284,8 +284,8 @@ mod tests { ), geometries: vec![triangle0.into(), triangle1.into()], }; - let ray_triangle0_v0 = Ray::between(&Vector3::new(0., 0., -1.), &Vector3::new(0., 0., 1.)); - let ray_triangle1_v1 = Ray::between(&Vector3::new(2., 0., -1.), &Vector3::new(2., 0., 1.)); + let ray_triangle0_v0 = Ray::between(Vec3::new(0., 0., -1.), Vec3::new(0., 0., 1.)); + let ray_triangle1_v1 = Ray::between(Vec3::new(2., 0., -1.), Vec3::new(2., 0., 1.)); assert_eq!( tree.intersect(&ray_triangle0_v0, 0.0..=1.0), @@ -300,14 +300,14 @@ mod tests { #[test] fn intersect_ray_orthogonal_to_split_plane_and_intersecting_both_triangles() { let triangle0 = Triangle { - v0: Vector3::new(0., -1., -1.), - v1: Vector3::new(0., 1., -1.), - v2: Vector3::new(0., 1., 1.), + v0: Vec3::new(0., -1., -1.), + v1: Vec3::new(0., 1., -1.), + v2: Vec3::new(0., 1., 1.), }; let triangle1 = Triangle { - v0: Vector3::new(2., -1., -1.), - v1: Vector3::new(2., 1., -1.), - v2: Vector3::new(2., 1., 1.), + v0: Vec3::new(2., -1., -1.), + v1: Vec3::new(2., 1., -1.), + v2: Vec3::new(2., 1., 1.), }; let tree = KdTree { root: KdNode::new_node( @@ -317,7 +317,7 @@ mod tests { ), geometries: vec![triangle0.into(), triangle1.into()], }; - let ray = Ray::between(&Vector3::new(-1., 0., 0.), &Vector3::new(3., 0., 0.)); + let ray = Ray::between(Vec3::new(-1., 0., 0.), Vec3::new(3., 0., 0.)); assert_eq!( tree.intersect(&ray, 0.0..=1.0), @@ -332,9 +332,9 @@ mod tests { #[test] fn intersect_split_at_axially_aligned_triangle() { let triangle = Triangle { - v0: Vector3::new(0., 0., 1.), - v1: Vector3::new(1., 0., 1.), - v2: Vector3::new(0., 1., 1.), + v0: Vec3::new(0., 0., 1.), + v1: Vec3::new(1., 0., 1.), + v2: Vec3::new(0., 1., 1.), }; let tree_left = KdTree { root: KdNode::new_node(Aap::new_z(1.0), KdNode::new_leaf(vec![0]), KdNode::empty()), @@ -344,7 +344,7 @@ mod tests { root: KdNode::new_node(Aap::new_z(1.0), KdNode::empty(), KdNode::new_leaf(vec![0])), geometries: vec![triangle.into()], }; - let ray = Ray::between(&Vector3::new(0., 0., 0.), &Vector3::new(0., 0., 2.)); + let ray = Ray::between(Vec3::new(0., 0., 0.), Vec3::new(0., 0., 2.)); assert_eq!( tree_left.intersect(&ray, 0.0..=1.0), @@ -359,9 +359,9 @@ mod tests { #[test] fn intersect_flat_cell_left_left() { let triangle = Triangle { - v0: Vector3::new(0., 0., 1.), - v1: Vector3::new(1., 0., 1.), - v2: Vector3::new(0., 1., 1.), + v0: Vec3::new(0., 0., 1.), + v1: Vec3::new(1., 0., 1.), + v2: Vec3::new(0., 1., 1.), }; let tree = KdTree { root: KdNode::new_node( @@ -371,7 +371,7 @@ mod tests { ), geometries: vec![triangle.into()], }; - let ray = Ray::between(&Vector3::new(0., 0., 0.), &Vector3::new(0., 0., 2.)); + let ray = Ray::between(Vec3::new(0., 0., 0.), Vec3::new(0., 0., 2.)); assert_eq!( tree.intersect(&ray, 0.0..=1.0), @@ -386,9 +386,9 @@ mod tests { #[test] fn intersect_flat_cell_right_left() { let triangle = Triangle { - v0: Vector3::new(0., 0., 1.), - v1: Vector3::new(1., 0., 1.), - v2: Vector3::new(0., 1., 1.), + v0: Vec3::new(0., 0., 1.), + v1: Vec3::new(1., 0., 1.), + v2: Vec3::new(0., 1., 1.), }; let tree = KdTree { root: KdNode::new_node( @@ -398,7 +398,7 @@ mod tests { ), geometries: vec![triangle.into()], }; - let ray = Ray::between(&Vector3::new(0., 0., 0.), &Vector3::new(0., 0., 2.)); + let ray = Ray::between(Vec3::new(0., 0., 0.), Vec3::new(0., 0., 2.)); assert_eq!( tree.intersect(&ray, 0.0..=1.0), @@ -413,9 +413,9 @@ mod tests { #[test] fn intersect_flat_cell_minimized_example() { let triangle = Triangle { - v0: Vector3::new(1.0, 1.0, -1.0), - v1: Vector3::new(-1.0, 1.0, -1.0), - v2: Vector3::new(1.0, -1.0, -1.0), + v0: Vec3::new(1.0, 1.0, -1.0), + v1: Vec3::new(-1.0, 1.0, -1.0), + v2: Vec3::new(1.0, -1.0, -1.0), }; let root = KdNode::new_node( Aap::new_z(-1.0), @@ -427,8 +427,8 @@ mod tests { root, }; let ray = Ray { - origin: Vector3::new(0.0, 0.0, 3.0), - direction: Vector3::new(0.06646079, 0.08247295, -0.9238795), + origin: Vec3::new(0.0, 0.0, 3.0), + direction: Vec3::new(0.06646079, 0.08247295, -0.9238795), }; let actual = tree.intersect(&ray, 0.0..=f32::MAX); @@ -449,17 +449,17 @@ mod tests { #[test] fn intersect_rounding_error_example() { let triangle = Triangle { - v0: Vector3::new(-1.0, -1.0, 1.0), - v1: Vector3::new(-1.0, -1.0, -1.0), - v2: Vector3::new(-1.0, 1.0, 1.0), + v0: Vec3::new(-1.0, -1.0, 1.0), + v1: Vec3::new(-1.0, -1.0, -1.0), + v2: Vec3::new(-1.0, 1.0, 1.0), }; let tree = KdTree { root: KdNode::new_node(Aap::new_x(-1.0), KdNode::empty(), KdNode::new_leaf(vec![0])), geometries: vec![triangle.into()], }; let ray = Ray { - origin: Vector3::new(-0.5170438, -0.4394186, -0.045965273), - direction: Vector3::new(-0.8491798, -0.1408107, -0.5089852), + origin: Vec3::new(-0.5170438, -0.4394186, -0.045965273), + direction: Vec3::new(-0.8491798, -0.1408107, -0.5089852), }; let actual = tree.intersect(&ray, 0.0..=f32::MAX); diff --git a/kdtree/src/split.rs b/kdtree/src/split.rs index 4e828429..23ddb05a 100644 --- a/kdtree/src/split.rs +++ b/kdtree/src/split.rs @@ -71,18 +71,15 @@ pub fn split_and_partition(clipped: &[(u32, Aabb)], aabb: &Aabb, plane: Aap) -> #[cfg(test)] mod partition_triangles_tests { use geometry::axis::Axis; - use nalgebra::Vector3; + use glam::Vec3; use super::*; #[test] fn test() { - let triangle0 = - Aabb::from_extents(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 0.0)); - let triangle1 = - Aabb::from_extents(Vector3::new(1.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0)); - let triangle2 = - Aabb::from_extents(Vector3::new(1.0, 0.0, 0.0), Vector3::new(2.0, 1.0, 0.0)); + let triangle0 = Aabb::from_extents(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 0.0)); + let triangle1 = Aabb::from_extents(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0)); + let triangle2 = Aabb::from_extents(Vec3::new(1.0, 0.0, 0.0), Vec3::new(2.0, 1.0, 0.0)); let clipped = [(0, triangle0), (1, triangle1), (2, triangle2)]; let plane = Aap { axis: Axis::X, diff --git a/pathtracer-gui/Cargo.toml b/pathtracer-gui/Cargo.toml index 823c530f..3f04b7ca 100644 --- a/pathtracer-gui/Cargo.toml +++ b/pathtracer-gui/Cargo.toml @@ -5,9 +5,9 @@ edition = "2021" [dependencies] clap = { version = "4.5.8", features = ["derive"] } +glam = "0.28.0" kdtree = { version = "1.0.0", path = "../kdtree" } miniquad = "0.4.2" -nalgebra = { version = "0.33.0", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } rayon = { version = "1.10.0", default-features = false } scene = { version = "1.0.0", path = "../scene" } diff --git a/pathtracer-gui/src/stage.rs b/pathtracer-gui/src/stage.rs index 115ad434..665af805 100644 --- a/pathtracer-gui/src/stage.rs +++ b/pathtracer-gui/src/stage.rs @@ -1,11 +1,11 @@ use std::time::Instant; +use glam::{Mat3, Vec3}; use miniquad::{ window, Bindings, BufferLayout, BufferSource, BufferType, BufferUsage, EventHandler, KeyCode, Pipeline, PipelineParams, RenderingBackend, ShaderSource, TextureId, VertexAttribute, VertexFormat, }; -use nalgebra::{Matrix3, Vector3}; use scene::camera::{Camera, Pinhole}; use crate::worker::Worker; @@ -28,13 +28,13 @@ struct InputState { } impl InputState { - fn translation(&self) -> Vector3 { + fn translation(&self) -> Vec3 { let f = |(a, b)| match (a, b) { (true, false) => -1.0, (false, true) => 1.0, _ => 0.0, }; - Vector3::new(f(self.move_x), f(self.move_y), f(self.move_z)) + Vec3::new(f(self.move_x), f(self.move_y), f(self.move_z)) } } @@ -176,14 +176,11 @@ impl EventHandler for Stage { let delta = (now - self.last_update).as_secs_f32(); if let Some(worker) = &self.worker { let translation = self.input.translation(); - if translation != Vector3::zeros() { + if translation != Vec3::ZERO { const TRANSLATION_SPEED: f32 = 2.0; let distance = delta * TRANSLATION_SPEED; - let translation_matrix = Matrix3::from_rows(&[ - self.camera.right.into_inner().transpose(), - self.camera.up.into_inner().transpose(), - self.camera.direction.into_inner().transpose(), - ]); + let translation_matrix = + Mat3::from_cols(self.camera.right, self.camera.up, self.camera.direction); let position = self.camera.position + translation_matrix * translation * distance; self.camera = self.camera.with_position(position); let texture_size = self.ctx.texture_size(self.texture); diff --git a/pathtracer-gui/src/worker.rs b/pathtracer-gui/src/worker.rs index d66b8d46..50a3a4fa 100644 --- a/pathtracer-gui/src/worker.rs +++ b/pathtracer-gui/src/worker.rs @@ -8,7 +8,7 @@ use std::{ time, }; -use nalgebra::Vector2; +use glam::UVec2; use rand::{rngs::SmallRng, SeedableRng}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use scene::camera::Pinhole; @@ -35,17 +35,13 @@ impl RenderResult { } } -fn render_subdivided( - pathtracer: &Pathtracer, - pinhole: &Pinhole, - sub_size: Vector2, -) -> ImageBuffer { +fn render_subdivided(pathtracer: &Pathtracer, pinhole: &Pinhole, sub_size: UVec2) -> ImageBuffer { let count_x = pinhole.width / sub_size.x; let count_y = pinhole.height / sub_size.y; eprintln!( "Rendering size={:?} sub_size={:?} count={:?}", - pinhole.size().as_slice(), - sub_size.as_slice(), + pinhole.size(), + sub_size, [count_x, count_y] ); (0..count_x * count_y) @@ -58,7 +54,7 @@ fn render_subdivided( ) }, |(mut rng, mut buffer), i| { - let pixel = Vector2::new(i % count_x * sub_size.x, i / count_x * sub_size.y); + let pixel = UVec2::new(i % count_x * sub_size.x, i / count_x * sub_size.y); let mut ray_logger = RayLoggerWithIteration { writer: &mut RayLoggerWriter::None(), iteration: 0, @@ -94,9 +90,9 @@ fn worker_loop( Ok(new_pinhole) => { eprintln!( "New pinhole position={:?} direction={:?} size={:?}", - new_pinhole.camera.position.as_slice(), - new_pinhole.camera.direction.as_slice(), - new_pinhole.size().as_slice(), + new_pinhole.camera.position, + new_pinhole.camera.direction, + new_pinhole.size(), ); pinhole = new_pinhole; combined_buffer = ImageBuffer::new(pinhole.width, pinhole.height); diff --git a/scene/Cargo.toml b/scene/Cargo.toml index cefc21f4..b3b315b5 100644 --- a/scene/Cargo.toml +++ b/scene/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] geometry = { version = "1.0.0", path = "../geometry" } +glam = "0.28.0" image = { version = "0.25.1", default-features = false, features = ["jpeg", "png"] } -nalgebra = { version = "0.33.0", default-features = false } -simba = { version = "0.9.0", default-features = false, features = ["std"] } wavefront = { version = "1.0.0", path = "../wavefront" } diff --git a/scene/src/camera.rs b/scene/src/camera.rs index 66a01c71..21fc58a1 100644 --- a/scene/src/camera.rs +++ b/scene/src/camera.rs @@ -1,33 +1,28 @@ use geometry::ray::Ray; -use nalgebra::{UnitVector3, Vector2, Vector3}; +use glam::{UVec2, Vec3}; #[derive(Clone, Debug)] pub struct Camera { - pub position: Vector3, - pub direction: UnitVector3, - pub up: UnitVector3, - pub right: UnitVector3, + pub position: Vec3, + pub direction: Vec3, + pub up: Vec3, + pub right: Vec3, pub fov_degrees: f32, } impl Camera { - pub fn new( - position: Vector3, - target: &Vector3, - up: &Vector3, - fov_degrees: f32, - ) -> Camera { - let direction = UnitVector3::new_normalize(target - position); + pub fn new(position: Vec3, target: Vec3, up: Vec3, fov_degrees: f32) -> Camera { + let direction = (target - position).normalize(); Camera { position, direction, - up: UnitVector3::new_normalize(*up), - right: UnitVector3::new_normalize(direction.cross(up)), + up: up.normalize(), + right: direction.cross(up).normalize(), fov_degrees, } } - pub fn with_position(&self, position: Vector3) -> Self { + pub fn with_position(&self, position: Vec3) -> Self { Camera { position, direction: self.direction, @@ -43,18 +38,18 @@ pub struct Pinhole { pub camera: Camera, pub width: u32, pub height: u32, - pub plane: Vector3, - pub dx: Vector3, - pub dy: Vector3, + pub plane: Vec3, + pub dx: Vec3, + pub dy: Vec3, } impl Pinhole { pub fn new(camera: Camera, width: u32, height: u32) -> Pinhole { let aspect_ratio = width as f32 / height as f32; let half_fov_radians = camera.fov_degrees * std::f32::consts::PI / 360.0; - let x = camera.right.into_inner() * (half_fov_radians.sin() * aspect_ratio); - let y = camera.up.into_inner() * half_fov_radians.sin(); - let z = camera.direction.into_inner() * half_fov_radians.cos(); + let x = camera.right * (half_fov_radians.sin() * aspect_ratio); + let y = camera.up * half_fov_radians.sin(); + let z = camera.direction * half_fov_radians.cos(); Pinhole { camera, @@ -67,8 +62,8 @@ impl Pinhole { } #[inline] - pub fn size(&self) -> Vector2 { - Vector2::new(self.width, self.height) + pub fn size(&self) -> UVec2 { + UVec2::new(self.width, self.height) } #[inline] diff --git a/scene/src/lib.rs b/scene/src/lib.rs index ee8c1421..91a851ed 100644 --- a/scene/src/lib.rs +++ b/scene/src/lib.rs @@ -1,5 +1,5 @@ use geometry::triangle::Triangle; -use nalgebra::{UnitVector3, Vector2, Vector3}; +use glam::{Vec2, Vec3}; use std::{collections::BTreeMap, fs::File, io::BufReader, path::Path, sync::Arc}; use wavefront::{mtl, obj}; @@ -18,26 +18,26 @@ use crate::{ #[derive(Clone, Copy, Debug, PartialEq)] pub struct TriangleNormals { - pub n0: Vector3, - pub n1: Vector3, - pub n2: Vector3, + pub n0: Vec3, + pub n1: Vec3, + pub n2: Vec3, } impl TriangleNormals { - pub fn lerp(&self, u: f32, v: f32) -> UnitVector3 { - UnitVector3::new_normalize((1.0 - (u + v)) * self.n0 + u * self.n1 + v * self.n2) + pub fn lerp(&self, u: f32, v: f32) -> Vec3 { + ((1.0 - (u + v)) * self.n0 + u * self.n1 + v * self.n2).normalize() } } #[derive(Clone, Copy, Debug, PartialEq)] pub struct TriangleTexcoords { - pub uv0: Vector2, - pub uv1: Vector2, - pub uv2: Vector2, + pub uv0: Vec2, + pub uv1: Vec2, + pub uv2: Vec2, } impl TriangleTexcoords { - pub fn lerp(&self, u: f32, v: f32) -> Vector2 { + pub fn lerp(&self, u: f32, v: f32) -> Vec2 { (1.0 - (u + v)) * self.uv0 + u * self.uv1 + v * self.uv2 } } @@ -53,7 +53,7 @@ pub struct Scene { pub triangle_data: Vec, pub cameras: Vec, pub lights: Vec, - pub environment: Vector3, + pub environment: Vec3, } fn collect_triangle_data( @@ -148,8 +148,8 @@ fn collect_cameras(mtl: &mtl::Mtl) -> Vec { .map(|camera| { Camera::new( camera.position.into(), - &camera.target.into(), - &camera.up.into(), + camera.target.into(), + camera.up.into(), camera.fov, ) }) @@ -163,7 +163,7 @@ fn collect_lights(mtl: &mtl::Mtl) -> Vec { SphericalLight::new( light.position.into(), light.radius, - &light.color.into(), + light.color.into(), light.intensity, ) }) @@ -176,7 +176,7 @@ impl Scene { triangle_data: collect_triangle_data(image_directory, obj, mtl), cameras: collect_cameras(mtl), lights: collect_lights(mtl), - environment: Vector3::new(0.8, 0.8, 0.8), + environment: Vec3::new(0.8, 0.8, 0.8), } } diff --git a/scene/src/light.rs b/scene/src/light.rs index 5ec47a3f..a952ece1 100644 --- a/scene/src/light.rs +++ b/scene/src/light.rs @@ -1,19 +1,14 @@ -use nalgebra::Vector3; +use glam::Vec3; #[derive(Clone, Debug)] pub struct SphericalLight { - pub center: Vector3, - pub intensity: Vector3, + pub center: Vec3, + pub intensity: Vec3, pub radius: f32, } impl SphericalLight { - pub fn new( - center: Vector3, - radius: f32, - color: &Vector3, - intensity: f32, - ) -> SphericalLight { + pub fn new(center: Vec3, radius: f32, color: Vec3, intensity: f32) -> SphericalLight { SphericalLight { center, intensity: color * intensity, @@ -21,7 +16,7 @@ impl SphericalLight { } } - pub fn emitted(&self, point: Vector3) -> Vector3 { - self.intensity / (self.center - point).norm_squared() + pub fn emitted(&self, point: Vec3) -> Vec3 { + self.intensity / (self.center - point).length_squared() } } diff --git a/scene/src/material.rs b/scene/src/material.rs index ce7e8720..c4c63b77 100644 --- a/scene/src/material.rs +++ b/scene/src/material.rs @@ -1,22 +1,22 @@ +use glam::Vec3; use image::Rgb32FImage; -use nalgebra::{UnitVector3, Vector3}; #[derive(Debug, PartialEq)] pub struct MaterialSample { pub pdf: f32, - pub brdf: Vector3, - pub wo: UnitVector3, + pub brdf: Vec3, + pub wo: Vec3, } #[derive(Clone, Debug)] pub struct DiffuseReflectiveMaterial { - pub reflectance: Vector3, + pub reflectance: Vec3, pub texture: Option, } #[derive(Clone, Debug)] pub struct SpecularReflectiveMaterial { - pub reflectance: Vector3, + pub reflectance: Vec3, } #[derive(Clone, Debug)] diff --git a/tracing/Cargo.toml b/tracing/Cargo.toml index 0288e180..cf30de77 100644 --- a/tracing/Cargo.toml +++ b/tracing/Cargo.toml @@ -9,8 +9,7 @@ ray_logging = [] [dependencies] assert_approx_eq = "1.1.0" geometry = { version = "1.0.0", path = "../geometry" } +glam = "0.28.0" kdtree = { version = "1.0.0", path = "../kdtree" } -nalgebra = { version = "0.33.0", default-features = false, features = ["alloc"] } rand = { version = "0.8.5", default-features = false, features = ["small_rng", "std"] } scene = { version = "1.0.0", path = "../scene" } -simba = { version = "0.9.0", default-features = false, features = ["std"] } diff --git a/tracing/src/image_buffer.rs b/tracing/src/image_buffer.rs index eac9828a..2217c1c2 100644 --- a/tracing/src/image_buffer.rs +++ b/tracing/src/image_buffer.rs @@ -1,18 +1,16 @@ use std::ops::{Add, AddAssign, Index, IndexMut}; -use nalgebra::{Vector2, Vector3}; +use glam::{UVec2, Vec3}; #[derive(Clone)] pub struct ImageBuffer { pub width: u32, pub height: u32, - pub pixels: Vec>, + pub pixels: Vec, } -fn gamma_correct(x: Vector3) -> Vector3 { - const GAMMA_POWER: f32 = 1.0 / 2.2; - x.zip_map(&Vector3::from_element(GAMMA_POWER), |b, e| b.powf(e)) - .inf(&Vector3::from_element(1.0)) +fn gamma_correct(x: Vec3) -> Vec3 { + x.powf(1.0 / 2.2).min(Vec3::ONE) } impl ImageBuffer { @@ -21,7 +19,7 @@ impl ImageBuffer { Self { width, height, - pixels: [Vector3::zeros()].repeat((width * height) as usize), + pixels: [Vec3::ZERO].repeat((width * height) as usize), } } @@ -31,16 +29,16 @@ impl ImageBuffer { } #[inline] - fn index(&self, idx: Vector2) -> usize { + fn index(&self, idx: UVec2) -> usize { (self.width * idx.y + idx.x) as usize } #[inline] - pub fn add_at(mut self, at: Vector2, rhs: &Self) -> Self { + pub fn add_at(mut self, at: UVec2, rhs: &Self) -> Self { debug_assert!(at.x + rhs.width <= self.width && at.y + rhs.height <= self.height); for y in 0..rhs.height { for x in 0..rhs.width { - self[Vector2::new(at.x + x, at.y + y)] += rhs[Vector2::new(x, y)]; + self[UVec2::new(at.x + x, at.y + y)] += rhs[UVec2::new(x, y)]; } } self @@ -51,9 +49,8 @@ impl ImageBuffer { self.pixels .into_iter() .flat_map(|p| -> [u8; 3] { - (gamma_correct(p * iterations_inv) * 255.0) - .map(|c| c.round() as u8) - .into() + let color = (gamma_correct(p * iterations_inv) * 255.0).round(); + [color.x as u8, color.y as u8, color.z as u8] }) .collect() } @@ -62,24 +59,24 @@ impl ImageBuffer { pub fn into_rgba_iter(self, iterations: u16) -> impl Iterator { let iterations_inv = 1.0 / iterations as f32; self.pixels.into_iter().map(move |p| -> [u8; 4] { - let p = (gamma_correct(p * iterations_inv) * 255.0).map(|c| c.round() as u8); - [p.x, p.y, p.z, u8::MAX] + let p = (gamma_correct(p * iterations_inv) * 255.0).round(); + [p.x as u8, p.y as u8, p.z as u8, u8::MAX] }) } } -impl Index> for ImageBuffer { - type Output = Vector3; +impl Index for ImageBuffer { + type Output = Vec3; #[inline] - fn index(&self, index: Vector2) -> &Self::Output { + fn index(&self, index: UVec2) -> &Self::Output { &self.pixels[self.index(index)] } } -impl IndexMut> for ImageBuffer { +impl IndexMut for ImageBuffer { #[inline] - fn index_mut(&mut self, index: Vector2) -> &mut Self::Output { + fn index_mut(&mut self, index: UVec2) -> &mut Self::Output { let index = self.index(index); &mut self.pixels[index] } @@ -97,7 +94,7 @@ impl Add for ImageBuffer { pixels: self .pixels .into_iter() - .zip(rhs.pixels.iter()) + .zip(rhs.pixels.into_iter()) .map(|(a, b)| a + b) .collect::>(), } diff --git a/tracing/src/material.rs b/tracing/src/material.rs index 2589d02a..6204a3c0 100644 --- a/tracing/src/material.rs +++ b/tracing/src/material.rs @@ -1,4 +1,4 @@ -use nalgebra::{RealField, UnitVector3, Vector2, Vector3}; +use glam::{Vec2, Vec3}; use rand::{rngs::SmallRng, Rng}; use scene::material::{ BlendMaterial, DiffuseReflectiveMaterial, FresnelBlendMaterial, MaterialSample, @@ -7,11 +7,11 @@ use scene::material::{ use crate::sampling::cosine_sample_hemisphere; -fn perpendicular(v: &Vector3) -> Vector3 { +fn perpendicular(v: &Vec3) -> Vec3 { if v.x.abs() < v.y.abs() { - Vector3::new(0., -v.z, v.y) + Vec3::new(0., -v.z, v.y) } else { - Vector3::new(-v.z, 0., v.x) + Vec3::new(-v.z, 0., v.x) } } @@ -21,13 +21,13 @@ fn is_same_sign(a: f32, b: f32) -> bool { #[derive(Debug)] pub struct IncomingRay { - pub wi: Vector3, - pub n: UnitVector3, - pub uv: Vector2, + pub wi: Vec3, + pub n: Vec3, + pub uv: Vec2, } impl IncomingRay { - fn with_normal(&self, n: UnitVector3) -> IncomingRay { + fn with_normal(&self, n: Vec3) -> IncomingRay { IncomingRay { wi: self.wi, n, @@ -35,7 +35,7 @@ impl IncomingRay { } } - fn with_wo(&self, wo: Vector3) -> OutgoingRay { + fn with_wo(&self, wo: Vec3) -> OutgoingRay { OutgoingRay { wi: self.wi, n: self.n, @@ -45,21 +45,21 @@ impl IncomingRay { } fn reflectance(&self, r0: f32) -> f32 { - r0 + (1.0 - r0) * (1.0 - self.wi.dot(&self.n).abs()).powf(5.0) + r0 + (1.0 - r0) * (1.0 - self.wi.dot(self.n).abs()).powf(5.0) } } #[derive(Debug)] pub struct OutgoingRay { - pub wi: Vector3, - pub n: UnitVector3, - pub uv: Vector2, - pub wo: Vector3, + pub wi: Vec3, + pub n: Vec3, + pub uv: Vec2, + pub wo: Vec3, } impl OutgoingRay { fn is_same_hemisphere(&self) -> bool { - is_same_sign(self.wi.dot(&self.n), self.wo.dot(&self.n)) + is_same_sign(self.wi.dot(self.n), self.wo.dot(self.n)) } fn as_incoming(&self) -> IncomingRay { @@ -72,49 +72,47 @@ impl OutgoingRay { } pub trait Material { - fn brdf(&self, outgoing: &OutgoingRay) -> Vector3; + fn brdf(&self, outgoing: &OutgoingRay) -> Vec3; fn sample(&self, incoming: &IncomingRay, rng: &mut SmallRng) -> MaterialSample; } impl Material for DiffuseReflectiveMaterial { - fn brdf(&self, outgoing: &OutgoingRay) -> Vector3 { + fn brdf(&self, outgoing: &OutgoingRay) -> Vec3 { if let Some(texture) = &self.texture { let px = (texture.width() as f32 * outgoing.uv.x).floor(); let py = (texture.height() as f32 * outgoing.uv.y).floor(); - let reflectance: Vector3 = texture[(px as u32, py as u32)].0.into(); - reflectance * f32::frac_1_pi() + let reflectance: Vec3 = texture[(px as u32, py as u32)].0.into(); + reflectance * std::f32::consts::FRAC_1_PI } else { - self.reflectance * f32::frac_1_pi() + self.reflectance * std::f32::consts::FRAC_1_PI } } fn sample(&self, incoming: &IncomingRay, rng: &mut SmallRng) -> MaterialSample { let tangent = perpendicular(&incoming.n).normalize(); - let bitangent = incoming.n.cross(&tangent); + let bitangent = incoming.n.cross(tangent); let s = cosine_sample_hemisphere(rng); - let wo = UnitVector3::new_normalize(s.x * tangent + s.y * bitangent + s.z * *incoming.n); + let wo = (s.x * tangent + s.y * bitangent + s.z * incoming.n).normalize(); MaterialSample { pdf: 1.0, - brdf: self.brdf(&incoming.with_wo(*wo)), + brdf: self.brdf(&incoming.with_wo(wo)), wo, } } } impl Material for SpecularReflectiveMaterial { - fn brdf(&self, _: &OutgoingRay) -> Vector3 { - Vector3::zeros() + fn brdf(&self, _: &OutgoingRay) -> Vec3 { + Vec3::ZERO } fn sample(&self, incoming: &IncomingRay, _: &mut SmallRng) -> MaterialSample { - let wo = UnitVector3::new_normalize( - 2.0 * incoming.wi.dot(&incoming.n).abs() * *incoming.n - incoming.wi, - ); - let outgoing = incoming.with_wo(*wo); + let wo = (2.0 * incoming.wi.dot(incoming.n).abs() * incoming.n - incoming.wi).normalize(); + let outgoing = incoming.with_wo(wo); let pdf = if outgoing.is_same_hemisphere() { - wo.dot(&outgoing.n).abs() + wo.dot(outgoing.n).abs() } else { 0.0 }; @@ -127,38 +125,38 @@ impl Material for SpecularReflectiveMaterial { } impl Material for SpecularRefractiveMaterial { - fn brdf(&self, _: &OutgoingRay) -> Vector3 { - Vector3::zeros() + fn brdf(&self, _: &OutgoingRay) -> Vec3 { + Vec3::ZERO } fn sample(&self, incoming: &IncomingRay, rng: &mut SmallRng) -> MaterialSample { - let (eta, n_refracted) = if (-incoming.wi).dot(&incoming.n) < 0.0 { + let (eta, n_refracted) = if (-incoming.wi).dot(incoming.n) < 0.0 { (1.0 / self.index_of_refraction, incoming.n) } else { (self.index_of_refraction, -incoming.n) }; - let w = -(-incoming.wi).dot(&n_refracted) * eta; + let w = -(-incoming.wi).dot(n_refracted) * eta; let k = 1.0 + (w - eta) * (w + eta); if k < 0.0 { const TOTAL_INTERNAL_REFLECTION: SpecularReflectiveMaterial = SpecularReflectiveMaterial { - reflectance: Vector3::new(1.0, 1.0, 1.0), + reflectance: Vec3::new(1.0, 1.0, 1.0), }; return TOTAL_INTERNAL_REFLECTION.sample(&incoming.with_normal(n_refracted), rng); } let k = k.sqrt(); - let wo = UnitVector3::new_normalize(-eta * incoming.wi + (w - k) * *n_refracted); + let wo = (-eta * incoming.wi + (w - k) * n_refracted).normalize(); MaterialSample { pdf: 1.0, - brdf: Vector3::new(1.0, 1.0, 1.0), + brdf: Vec3::new(1.0, 1.0, 1.0), wo, } } } -fn mix(x: Vector3, y: Vector3, a: f32) -> Vector3 { +fn mix(x: Vec3, y: Vec3, a: f32) -> Vec3 { x * (1.0 - a) + y * a } @@ -167,7 +165,7 @@ where M1: Material, M2: Material, { - fn brdf(&self, outgoing: &OutgoingRay) -> Vector3 { + fn brdf(&self, outgoing: &OutgoingRay) -> Vec3 { mix( self.refraction.brdf(outgoing), self.reflection.brdf(outgoing), @@ -189,7 +187,7 @@ where M1: Material, M2: Material, { - fn brdf(&self, outgoing: &OutgoingRay) -> Vector3 { + fn brdf(&self, outgoing: &OutgoingRay) -> Vec3 { mix( self.second.brdf(outgoing), self.first.brdf(outgoing), @@ -218,9 +216,9 @@ mod specular_refractive_material_tests { let material = SpecularRefractiveMaterial { index_of_refraction: 1.5, }; - let wi = Vector3::new(-1.0, 2.0, 0.0).normalize(); - let n = UnitVector3::new_normalize(Vector3::new(0.0, 1.0, 0.0)); - let uv = Vector2::zeros(); + let wi = Vec3::new(-1.0, 2.0, 0.0).normalize(); + let n = Vec3::new(0.0, 1.0, 0.0); + let uv = Vec2::ZERO; let incoming = IncomingRay { wi, n, uv }; let mut rng = SmallRng::seed_from_u64(0); @@ -228,8 +226,8 @@ mod specular_refractive_material_tests { let n1 = 1.0; let n2 = material.index_of_refraction; - let theta1 = wi.dot(&n).acos(); - let theta2 = actual.wo.dot(&-n).acos(); + let theta1 = wi.dot(n).acos(); + let theta2 = actual.wo.dot(-n).acos(); assert_approx_eq!(n1 * theta1.sin(), n2 * theta2.sin(), 2e-7); assert!(actual.wo.y < 0.0); } @@ -239,9 +237,9 @@ mod specular_refractive_material_tests { let material = SpecularRefractiveMaterial { index_of_refraction: 1.5, }; - let wi = Vector3::new(-1.0, -2.0, 0.0).normalize(); - let n = UnitVector3::new_normalize(Vector3::new(0.0, 1.0, 0.0)); - let uv = Vector2::zeros(); + let wi = Vec3::new(-1.0, -2.0, 0.0).normalize(); + let n = Vec3::new(0.0, 1.0, 0.0); + let uv = Vec2::ZERO; let incoming = IncomingRay { wi, n, uv }; let mut rng = SmallRng::seed_from_u64(0); @@ -249,8 +247,8 @@ mod specular_refractive_material_tests { let n1 = material.index_of_refraction; let n2 = 1.0; - let theta1 = wi.dot(&n).acos(); - let theta2 = actual.wo.dot(&n).acos(); + let theta1 = wi.dot(n).acos(); + let theta2 = actual.wo.dot(n).acos(); assert_approx_eq!(n1 * theta1.sin(), n2 * theta2.sin(), 2e-7); assert!(actual.wo.y > 0.0); } diff --git a/tracing/src/pathtracer.rs b/tracing/src/pathtracer.rs index 4e901989..512badf6 100644 --- a/tracing/src/pathtracer.rs +++ b/tracing/src/pathtracer.rs @@ -7,8 +7,8 @@ use crate::{ sampling::{sample_light, uniform_sample_unit_square}, }; use geometry::{intersection::RayIntersection, ray::Ray}; +use glam::{UVec2, Vec3}; use kdtree::KdTree; -use nalgebra::{Vector2, Vector3}; use rand::rngs::SmallRng; use scene::{camera::Pinhole, Scene}; @@ -31,11 +31,11 @@ impl Pathtracer { &self, ray_logger: &mut RayLoggerWithIterationAndPixel, rng: &mut SmallRng, - accumulated_radiance: Vector3, - accumulated_transport: Vector3, + accumulated_radiance: Vec3, + accumulated_transport: Vec3, accumulated_bounces: u8, ray: &Ray, - ) -> Vector3 { + ) -> Vec3 { if accumulated_bounces >= self.max_bounces { return accumulated_radiance; } @@ -43,8 +43,7 @@ impl Pathtracer { let intersection = self.intersect(ray, 0.0..=f32::MAX); if intersection.is_none() { ray_logger.log_infinite(ray, accumulated_bounces).unwrap(); - return accumulated_radiance - + accumulated_transport.component_mul(&self.scene.environment); + return accumulated_radiance + accumulated_transport * self.scene.environment; } let (triangle_index, intersection) = intersection.unwrap(); let triangle = &self.scene.triangle_data[triangle_index as usize]; @@ -59,51 +58,47 @@ impl Pathtracer { let material = triangle.material.as_ref(); // TODO: How to chose offset? - let offset = 0.00001 * n.into_inner(); + let offset = 0.00001 * n; let point = ray.param(intersection.t); let point_above = point + offset; let point_below = point - offset; - let incoming_radiance: Vector3 = self + let incoming_radiance: Vec3 = self .scene .lights .iter() .map(|light| { - let shadow_ray = Ray::between(&point_above, &sample_light(light, rng)); + let shadow_ray = Ray::between(point_above, sample_light(light, rng)); if self.intersect_any(&shadow_ray, 0.0..=1.0) { - return Vector3::zeros(); + return Vec3::ZERO; } let wo = shadow_ray.direction.normalize(); let radiance = light.emitted(point); - material - .brdf(&OutgoingRay { wi, n, wo, uv }) - .component_mul(&radiance) - * wo.dot(&n).abs() + material.brdf(&OutgoingRay { wi, n, wo, uv }) * radiance * wo.dot(n).abs() }) .sum(); - let accumulated_radiance = - accumulated_radiance + accumulated_transport.component_mul(&incoming_radiance); + let accumulated_radiance = accumulated_radiance + accumulated_transport * incoming_radiance; let sample = material.sample(&IncomingRay { wi, n, uv }, rng); let next_ray = Ray { - origin: if sample.wo.dot(&n) >= 0.0 { + origin: if sample.wo.dot(n) >= 0.0 { point_above } else { point_below }, - direction: *sample.wo, + direction: sample.wo, }; if sample.pdf <= 0.01 { return accumulated_radiance; } - let cosine_term = sample.wo.dot(&n).abs(); + let cosine_term = sample.wo.dot(n).abs(); let accumulated_transport = - accumulated_transport.component_mul(&(sample.brdf * (cosine_term / sample.pdf))); + accumulated_transport * sample.brdf * (cosine_term / sample.pdf); - if accumulated_transport.norm() <= 0.01 { + if accumulated_transport.length() <= 0.01 { return accumulated_radiance; } @@ -122,25 +117,20 @@ impl Pathtracer { ray_logger: &mut RayLoggerWithIterationAndPixel, rng: &mut SmallRng, ray: &Ray, - ) -> Vector3 { + ) -> Vec3 { self.trace_ray( ray_logger, rng, - Vector3::zeros(), - Vector3::new(1.0, 1.0, 1.0), + Vec3::ZERO, + Vec3::new(1.0, 1.0, 1.0), 0, ray, ) } - fn sample_ray_for_pixel( - &self, - pinhole: &Pinhole, - rng: &mut SmallRng, - pixel: Vector2, - ) -> Ray { + fn sample_ray_for_pixel(&self, pinhole: &Pinhole, rng: &mut SmallRng, pixel: UVec2) -> Ray { debug_assert!(pixel.x < pinhole.width && pixel.y < pinhole.height); - let pixel_center = pixel.cast() + uniform_sample_unit_square(rng); + let pixel_center = pixel.as_vec2() + uniform_sample_unit_square(rng); pinhole.ray( pixel_center.x / pinhole.width as f32, pixel_center.y / pinhole.height as f32, @@ -150,10 +140,10 @@ impl Pathtracer { fn render_pixel( &self, pinhole: &Pinhole, - pixel: Vector2, + pixel: UVec2, ray_logger: &mut RayLoggerWithIteration, rng: &mut SmallRng, - ) -> Vector3 { + ) -> Vec3 { let mut ray_logger = ray_logger.with_pixel(pixel.x as u16, pixel.y as u16); let ray = self.sample_ray_for_pixel(pinhole, rng, pixel); self.trace_ray_defaults(&mut ray_logger, rng, &ray) @@ -168,7 +158,7 @@ impl Pathtracer { ) { for y in 0..buffer.height { for x in 0..buffer.width { - let pixel = Vector2::new(x, y); + let pixel = UVec2::new(x, y); buffer[pixel] += self.render_pixel(pinhole, pixel, ray_logger, rng); } } @@ -180,12 +170,12 @@ impl Pathtracer { ray_logger: &mut RayLoggerWithIteration, rng: &mut SmallRng, buffer: &mut ImageBuffer, - sub_start: Vector2, - sub_size: Vector2, + sub_start: UVec2, + sub_size: UVec2, ) { for sub_y in 0..sub_size.y { for sub_x in 0..sub_size.x { - let pixel = sub_start + Vector2::new(sub_x, sub_y); + let pixel = sub_start + UVec2::new(sub_x, sub_y); buffer[pixel] += self.render_pixel(pinhole, pixel, ray_logger, rng); } } diff --git a/tracing/src/raytracer.rs b/tracing/src/raytracer.rs index c6bea1de..e23b1aec 100644 --- a/tracing/src/raytracer.rs +++ b/tracing/src/raytracer.rs @@ -5,8 +5,8 @@ use crate::{ material::{Material, OutgoingRay}, }; use geometry::{intersection::RayIntersection, ray::Ray}; +use glam::{UVec2, Vec2, Vec3}; use kdtree::KdTree; -use nalgebra::{Vector2, Vector3}; use scene::{camera::Pinhole, material::MaterialModel, Scene}; pub struct Raytracer { @@ -24,7 +24,7 @@ impl Raytracer { self.intersect(ray, t_range).is_some() } - fn trace_ray(&self, ray: &Ray) -> Vector3 { + fn trace_ray(&self, ray: &Ray) -> Vec3 { let intersection = self.intersect(ray, 0.0..=f32::MAX); if intersection.is_none() { return self.scene.environment; @@ -38,7 +38,7 @@ impl Raytracer { let uv = triangle.texcoords.lerp(intersection.u, intersection.v); // TODO: How to chose offset? - let offset_point = point + 0.0001 * n.into_inner(); + let offset_point = point + 0.0001 * n; self.scene .lights @@ -52,25 +52,22 @@ impl Raytracer { direction, }; if this.intersect_any(&shadow_ray, 0.0..=1.0) { - return Vector3::zeros(); + return Vec3::ZERO; } let wo = direction.normalize(); let radiance = light.emitted(point); - material - .brdf(&OutgoingRay { wi, n, wo, uv }) - .component_mul(&radiance) - * wo.dot(&n).abs() + material.brdf(&OutgoingRay { wi, n, wo, uv }) * radiance * wo.dot(n).abs() }) .sum() } pub fn render(&self, buffer: &mut ImageBuffer) { - let buffer_size = Vector2::new(buffer.width as f32, buffer.height as f32); + let buffer_size = Vec2::new(buffer.width as f32, buffer.height as f32); for y in 0..buffer.height { for x in 0..buffer.width { - let pixel = Vector2::new(x, y); - let pixel_center = Vector2::new(pixel.x as f32 + 0.5, pixel.y as f32 + 0.5); - let scene_direction = pixel_center.component_div(&buffer_size); + let pixel = UVec2::new(x, y); + let pixel_center = Vec2::new(pixel.x as f32 + 0.5, pixel.y as f32 + 0.5); + let scene_direction = pixel_center / buffer_size; let ray = self.camera.ray(scene_direction.x, scene_direction.y); buffer[pixel] += self.trace_ray(&ray); } diff --git a/tracing/src/sampling.rs b/tracing/src/sampling.rs index 26e2646b..2645181b 100644 --- a/tracing/src/sampling.rs +++ b/tracing/src/sampling.rs @@ -1,33 +1,33 @@ -use nalgebra::{UnitVector3, Vector2, Vector3}; +use glam::{Vec2, Vec3}; use rand::{rngs::SmallRng, Rng}; use scene::light::SphericalLight; -pub fn uniform_sample_unit_square(rng: &mut SmallRng) -> Vector2 { - Vector2::new(rng.gen(), rng.gen()) +pub fn uniform_sample_unit_square(rng: &mut SmallRng) -> Vec2 { + Vec2::new(rng.gen(), rng.gen()) } -pub fn uniform_sample_unit_sphere(rng: &mut SmallRng) -> UnitVector3 { +pub fn uniform_sample_unit_sphere(rng: &mut SmallRng) -> Vec3 { let z = rng.gen_range(-1.0..1.0); let a = rng.gen_range(0.0..std::f32::consts::TAU); let r = (1.0f32 - z * z).sqrt(); let x = r * a.cos(); let y = r * a.sin(); - UnitVector3::new_unchecked(Vector3::new(x, y, z)) + Vec3::new(x, y, z) } -// fn uniform_sample_hemisphere(rng: &mut SmallRng) -> Vector3 { +// fn uniform_sample_hemisphere(rng: &mut SmallRng) -> Vec3 { // let r = uniform_sample_unit_square(rng); // let a = 2.0 * (r.y * (1.0 - r.y)).sqrt(); // let b = std::f32::consts::TAU * r.x; -// Vector3::new(a * b.cos(), a * b.sin(), (1.0 - 2.0 * r.y).abs()) +// Vec3::new(a * b.cos(), a * b.sin(), (1.0 - 2.0 * r.y).abs()) // } -fn concentric_sample_unit_disk(rng: &mut SmallRng) -> Vector2 { +fn concentric_sample_unit_disk(rng: &mut SmallRng) -> Vec2 { let x = rng.gen_range(-1.0..=1.0); let y = rng.gen_range(-1.0..=1.0); if x == 0.0 && y == 0.0 { - return Vector2::zeros(); + return Vec2::ZERO; } let (r, theta) = match (x, y) { @@ -38,17 +38,17 @@ fn concentric_sample_unit_disk(rng: &mut SmallRng) -> Vector2 { }; let theta = theta * std::f32::consts::FRAC_PI_4; - Vector2::new(r * theta.cos(), r * theta.sin()) + Vec2::new(r * theta.cos(), r * theta.sin()) } -pub fn cosine_sample_hemisphere(rng: &mut SmallRng) -> Vector3 { +pub fn cosine_sample_hemisphere(rng: &mut SmallRng) -> Vec3 { let ret = concentric_sample_unit_disk(rng); let z = (0.0f32.max(1.0 - ret.x * ret.x - ret.y * ret.y)).sqrt(); - Vector3::new(ret.x, ret.y, z) + Vec3::new(ret.x, ret.y, z) } -pub fn sample_light(light: &SphericalLight, rng: &mut SmallRng) -> Vector3 { - light.center + *uniform_sample_unit_sphere(rng) * light.radius +pub fn sample_light(light: &SphericalLight, rng: &mut SmallRng) -> Vec3 { + light.center + uniform_sample_unit_sphere(rng) * light.radius } #[cfg(test)] @@ -61,8 +61,8 @@ mod tests { let mut rng = SmallRng::from_entropy(); for _ in 0..1000 { let point = uniform_sample_unit_square(&mut rng); - assert!(point >= Vector2::new(0.0, 0.0)); - assert!(point <= Vector2::new(1.0, 1.0)); + assert!(point.cmpge(Vec2::new(0.0, 0.0)).all()); + assert!(point.cmple(Vec2::new(1.0, 1.0)).all()); } } @@ -71,7 +71,7 @@ mod tests { let mut rng = SmallRng::from_entropy(); for _ in 0..1000 { let point = uniform_sample_unit_sphere(&mut rng); - let error = point.norm(); + let error = point.length(); assert!((0.9999999..=1.0000001).contains(&error), "{}", error); } } @@ -92,7 +92,7 @@ mod tests { let mut rng = SmallRng::from_entropy(); for _ in 0..1000 { let point = concentric_sample_unit_disk(&mut rng); - assert!(point.norm_squared() <= 1.0, "{}", point.norm_squared()); + assert!(point.length_squared() <= 1.0, "{}", point.length_squared()); } } @@ -101,7 +101,7 @@ mod tests { let mut rng = SmallRng::from_entropy(); for _ in 0..1000 { let point = cosine_sample_hemisphere(&mut rng); - let error = (point.norm_squared() - 1.0).abs(); + let error = (point.length_squared() - 1.0).abs(); assert!(point.z >= 0.0 && point.z <= 1.0); assert!(error <= 1e-6, "{}", error); }