Switched from in-tree float4 lib to glam.
This commit is contained in:
parent
5c5a01ecee
commit
88e7365bc4
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -8,6 +8,14 @@ dependencies = [
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
|
@ -110,10 +118,6 @@ name = "crossbeam"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "float4"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -124,6 +128,14 @@ name = "fuchsia-cprng"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glam"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "git+https://github.com/bitshifter/glam-rs.git?rev=0f314f99#0f314f990710ff9357e5896de2b55ec82fe88e0d"
|
||||||
|
dependencies = [
|
||||||
|
"approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -147,7 +159,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
name = "math3d"
|
name = "math3d"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"float4 0.1.0",
|
"approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"glam 0.7.1 (git+https://github.com/bitshifter/glam-rs.git?rev=0f314f99)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -246,7 +259,7 @@ dependencies = [
|
||||||
"color 0.1.0",
|
"color 0.1.0",
|
||||||
"copy_in_place 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"copy_in_place 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"float4 0.1.0",
|
"glam 0.7.1 (git+https://github.com/bitshifter/glam-rs.git?rev=0f314f99)",
|
||||||
"half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"halton 0.1.0",
|
"halton 0.1.0",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -449,7 +462,7 @@ version = "0.1.0"
|
||||||
name = "spectral_upsampling"
|
name = "spectral_upsampling"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"float4 0.1.0",
|
"glam 0.7.1 (git+https://github.com/bitshifter/glam-rs.git?rev=0f314f99)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -551,6 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
|
||||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||||
|
@ -567,6 +581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
||||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
"checksum glam 0.7.1 (git+https://github.com/bitshifter/glam-rs.git?rev=0f314f99)" = "<none>"
|
||||||
"checksum half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9353c2a89d550b58fa0061d8ed8d002a7d8cdf2494eb0e432859bd3a9e543836"
|
"checksum half 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9353c2a89d550b58fa0061d8ed8d002a7d8cdf2494eb0e432859bd3a9e543836"
|
||||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||||
"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880"
|
"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880"
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
members = [
|
members = [
|
||||||
"sub_crates/bvh_order",
|
"sub_crates/bvh_order",
|
||||||
"sub_crates/color",
|
"sub_crates/color",
|
||||||
"sub_crates/float4",
|
|
||||||
"sub_crates/halton",
|
"sub_crates/halton",
|
||||||
"sub_crates/math3d",
|
"sub_crates/math3d",
|
||||||
"sub_crates/mem_arena",
|
"sub_crates/mem_arena",
|
||||||
|
@ -36,6 +35,7 @@ png_encode_mini = "0.1.2"
|
||||||
rustc-serialize = "0.3"
|
rustc-serialize = "0.3"
|
||||||
scoped_threadpool = "0.1"
|
scoped_threadpool = "0.1"
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
|
glam = {git="https://github.com/bitshifter/glam-rs.git", rev="0f314f99", default-features=false, features=["approx"]}
|
||||||
|
|
||||||
# Local crate dependencies
|
# Local crate dependencies
|
||||||
[dependencies.bvh_order]
|
[dependencies.bvh_order]
|
||||||
|
@ -44,9 +44,6 @@ path = "sub_crates/bvh_order"
|
||||||
[dependencies.color]
|
[dependencies.color]
|
||||||
path = "sub_crates/color"
|
path = "sub_crates/color"
|
||||||
|
|
||||||
[dependencies.float4]
|
|
||||||
path = "sub_crates/float4"
|
|
||||||
|
|
||||||
[dependencies.halton]
|
[dependencies.halton]
|
||||||
path = "sub_crates/halton"
|
path = "sub_crates/halton"
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
use std::mem::{transmute, MaybeUninit};
|
use std::mem::{transmute, MaybeUninit};
|
||||||
|
|
||||||
|
use glam::Vec4Mask;
|
||||||
|
|
||||||
use mem_arena::MemArena;
|
use mem_arena::MemArena;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -23,7 +25,6 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use bvh_order::{calc_traversal_code, SplitAxes, TRAVERSAL_TABLE};
|
use bvh_order::{calc_traversal_code, SplitAxes, TRAVERSAL_TABLE};
|
||||||
use float4::Bool4;
|
|
||||||
|
|
||||||
pub fn ray_code(dir: Vector) -> usize {
|
pub fn ray_code(dir: Vector) -> usize {
|
||||||
let ray_sign_is_neg = [dir.x() < 0.0, dir.y() < 0.0, dir.z() < 0.0];
|
let ray_sign_is_neg = [dir.x() < 0.0, dir.y() < 0.0, dir.z() < 0.0];
|
||||||
|
@ -122,12 +123,12 @@ impl<'a> BVH4<'a> {
|
||||||
traversal_code,
|
traversal_code,
|
||||||
} => {
|
} => {
|
||||||
node_tests += ray_stack.ray_count_in_next_task() as u64;
|
node_tests += ray_stack.ray_count_in_next_task() as u64;
|
||||||
let mut all_hits = Bool4::new_false();
|
let mut all_hits = Vec4Mask::default();
|
||||||
|
|
||||||
// Ray testing
|
// Ray testing
|
||||||
ray_stack.pop_do_next_task_and_push_rays(children.len(), |ray_idx| {
|
ray_stack.pop_do_next_task_and_push_rays(children.len(), |ray_idx| {
|
||||||
if rays.is_done(ray_idx) {
|
if rays.is_done(ray_idx) {
|
||||||
Bool4::new_false()
|
Vec4Mask::default()
|
||||||
} else {
|
} else {
|
||||||
let hits = if bounds.len() == 1 {
|
let hits = if bounds.len() == 1 {
|
||||||
bounds[0].intersect_ray(
|
bounds[0].intersect_ray(
|
||||||
|
@ -148,7 +149,7 @@ impl<'a> BVH4<'a> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// If there were any intersections, create tasks.
|
// If there were any intersections, create tasks.
|
||||||
if !all_hits.is_all_false() {
|
if all_hits.any() {
|
||||||
let order_code = traversal_table[traversal_code as usize];
|
let order_code = traversal_table[traversal_code as usize];
|
||||||
let mut lane_count = 0;
|
let mut lane_count = 0;
|
||||||
let mut i = children.len() as u8;
|
let mut i = children.len() as u8;
|
||||||
|
|
20
src/bbox.rs
20
src/bbox.rs
|
@ -45,12 +45,12 @@ impl BBox {
|
||||||
let t2 = (self.max.co - orig.co) * dir_inv.co;
|
let t2 = (self.max.co - orig.co) * dir_inv.co;
|
||||||
|
|
||||||
// Find the far and near intersection
|
// Find the far and near intersection
|
||||||
let mut far_t = t1.v_max(t2);
|
let mut far_t = t1.max(t2);
|
||||||
let mut near_t = t1.v_min(t2);
|
let mut near_t = t1.min(t2);
|
||||||
far_t.set_3(std::f32::INFINITY);
|
far_t.set_w(std::f32::INFINITY);
|
||||||
near_t.set_3(0.0);
|
near_t.set_w(0.0);
|
||||||
let far_hit_t = fast_minf32(far_t.h_min() * BBOX_MAXT_ADJUST, max_t);
|
let far_hit_t = fast_minf32(far_t.min_element() * BBOX_MAXT_ADJUST, max_t);
|
||||||
let near_hit_t = near_t.h_max();
|
let near_hit_t = near_t.max_element();
|
||||||
|
|
||||||
// Did we hit?
|
// Did we hit?
|
||||||
near_hit_t <= far_hit_t
|
near_hit_t <= far_hit_t
|
||||||
|
@ -106,10 +106,10 @@ impl BitOr for BBox {
|
||||||
fn bitor(self, rhs: BBox) -> BBox {
|
fn bitor(self, rhs: BBox) -> BBox {
|
||||||
BBox::from_points(
|
BBox::from_points(
|
||||||
Point {
|
Point {
|
||||||
co: self.min.co.v_min(rhs.min.co),
|
co: self.min.co.min(rhs.min.co),
|
||||||
},
|
},
|
||||||
Point {
|
Point {
|
||||||
co: self.max.co.v_max(rhs.max.co),
|
co: self.max.co.max(rhs.max.co),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -128,10 +128,10 @@ impl BitOr<Point> for BBox {
|
||||||
fn bitor(self, rhs: Point) -> BBox {
|
fn bitor(self, rhs: Point) -> BBox {
|
||||||
BBox::from_points(
|
BBox::from_points(
|
||||||
Point {
|
Point {
|
||||||
co: self.min.co.v_min(rhs.co),
|
co: self.min.co.min(rhs.co),
|
||||||
},
|
},
|
||||||
Point {
|
Point {
|
||||||
co: self.max.co.v_max(rhs.co),
|
co: self.max.co.max(rhs.co),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
75
src/bbox4.rs
75
src/bbox4.rs
|
@ -9,16 +9,16 @@ use crate::{
|
||||||
math::{Point, Vector},
|
math::{Point, Vector},
|
||||||
};
|
};
|
||||||
|
|
||||||
use float4::{Bool4, Float4};
|
use glam::{Vec4, Vec4Mask};
|
||||||
|
|
||||||
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
const BBOX_MAXT_ADJUST: f32 = 1.00000024;
|
||||||
|
|
||||||
/// A SIMD set of 4 3D axis-aligned bounding boxes.
|
/// A SIMD set of 4 3D axis-aligned bounding boxes.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct BBox4 {
|
pub struct BBox4 {
|
||||||
pub x: (Float4, Float4), // (min, max)
|
pub x: (Vec4, Vec4), // (min, max)
|
||||||
pub y: (Float4, Float4), // (min, max)
|
pub y: (Vec4, Vec4), // (min, max)
|
||||||
pub z: (Float4, Float4), // (min, max)
|
pub z: (Vec4, Vec4), // (min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BBox4 {
|
impl BBox4 {
|
||||||
|
@ -26,16 +26,16 @@ impl BBox4 {
|
||||||
pub fn new() -> BBox4 {
|
pub fn new() -> BBox4 {
|
||||||
BBox4 {
|
BBox4 {
|
||||||
x: (
|
x: (
|
||||||
Float4::splat(std::f32::INFINITY),
|
Vec4::splat(std::f32::INFINITY),
|
||||||
Float4::splat(std::f32::NEG_INFINITY),
|
Vec4::splat(std::f32::NEG_INFINITY),
|
||||||
),
|
),
|
||||||
y: (
|
y: (
|
||||||
Float4::splat(std::f32::INFINITY),
|
Vec4::splat(std::f32::INFINITY),
|
||||||
Float4::splat(std::f32::NEG_INFINITY),
|
Vec4::splat(std::f32::NEG_INFINITY),
|
||||||
),
|
),
|
||||||
z: (
|
z: (
|
||||||
Float4::splat(std::f32::INFINITY),
|
Vec4::splat(std::f32::INFINITY),
|
||||||
Float4::splat(std::f32::NEG_INFINITY),
|
Vec4::splat(std::f32::NEG_INFINITY),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,30 +45,30 @@ impl BBox4 {
|
||||||
pub fn from_bboxes(b1: BBox, b2: BBox, b3: BBox, b4: BBox) -> BBox4 {
|
pub fn from_bboxes(b1: BBox, b2: BBox, b3: BBox, b4: BBox) -> BBox4 {
|
||||||
BBox4 {
|
BBox4 {
|
||||||
x: (
|
x: (
|
||||||
Float4::new(b1.min.x(), b2.min.x(), b3.min.x(), b4.min.x()),
|
Vec4::new(b1.min.x(), b2.min.x(), b3.min.x(), b4.min.x()),
|
||||||
Float4::new(b1.max.x(), b2.max.x(), b3.max.x(), b4.max.x()),
|
Vec4::new(b1.max.x(), b2.max.x(), b3.max.x(), b4.max.x()),
|
||||||
),
|
),
|
||||||
y: (
|
y: (
|
||||||
Float4::new(b1.min.y(), b2.min.y(), b3.min.y(), b4.min.y()),
|
Vec4::new(b1.min.y(), b2.min.y(), b3.min.y(), b4.min.y()),
|
||||||
Float4::new(b1.max.y(), b2.max.y(), b3.max.y(), b4.max.y()),
|
Vec4::new(b1.max.y(), b2.max.y(), b3.max.y(), b4.max.y()),
|
||||||
),
|
),
|
||||||
z: (
|
z: (
|
||||||
Float4::new(b1.min.z(), b2.min.z(), b3.min.z(), b4.min.z()),
|
Vec4::new(b1.min.z(), b2.min.z(), b3.min.z(), b4.min.z()),
|
||||||
Float4::new(b1.max.z(), b2.max.z(), b3.max.z(), b4.max.z()),
|
Vec4::new(b1.max.z(), b2.max.z(), b3.max.z(), b4.max.z()),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns whether the given ray intersects with the bboxes.
|
// Returns whether the given ray intersects with the bboxes.
|
||||||
pub fn intersect_ray(&self, orig: Point, dir_inv: Vector, max_t: f32) -> Bool4 {
|
pub fn intersect_ray(&self, orig: Point, dir_inv: Vector, max_t: f32) -> Vec4Mask {
|
||||||
// Get the ray data into SIMD format.
|
// Get the ray data into SIMD format.
|
||||||
let ro_x = orig.co.all_0();
|
let ro_x = Vec4::splat(orig.co.x());
|
||||||
let ro_y = orig.co.all_1();
|
let ro_y = Vec4::splat(orig.co.y());
|
||||||
let ro_z = orig.co.all_2();
|
let ro_z = Vec4::splat(orig.co.z());
|
||||||
let rdi_x = dir_inv.co.all_0();
|
let rdi_x = Vec4::splat(dir_inv.co.x());
|
||||||
let rdi_y = dir_inv.co.all_1();
|
let rdi_y = Vec4::splat(dir_inv.co.y());
|
||||||
let rdi_z = dir_inv.co.all_2();
|
let rdi_z = Vec4::splat(dir_inv.co.z());
|
||||||
let max_t = Float4::splat(max_t);
|
let max_t = Vec4::splat(max_t);
|
||||||
|
|
||||||
// Slab tests
|
// Slab tests
|
||||||
let t1_x = (self.x.0 - ro_x) * rdi_x;
|
let t1_x = (self.x.0 - ro_x) * rdi_x;
|
||||||
|
@ -79,24 +79,21 @@ impl BBox4 {
|
||||||
let t2_z = (self.z.1 - ro_z) * rdi_z;
|
let t2_z = (self.z.1 - ro_z) * rdi_z;
|
||||||
|
|
||||||
// Get the far and near t hits for each axis.
|
// Get the far and near t hits for each axis.
|
||||||
let t_far_x = t1_x.v_max(t2_x);
|
let t_far_x = t1_x.max(t2_x);
|
||||||
let t_far_y = t1_y.v_max(t2_y);
|
let t_far_y = t1_y.max(t2_y);
|
||||||
let t_far_z = t1_z.v_max(t2_z);
|
let t_far_z = t1_z.max(t2_z);
|
||||||
let t_near_x = t1_x.v_min(t2_x);
|
let t_near_x = t1_x.min(t2_x);
|
||||||
let t_near_y = t1_y.v_min(t2_y);
|
let t_near_y = t1_y.min(t2_y);
|
||||||
let t_near_z = t1_z.v_min(t2_z);
|
let t_near_z = t1_z.min(t2_z);
|
||||||
|
|
||||||
// Calculate over-all far t hit.
|
// Calculate over-all far t hit.
|
||||||
let far_t =
|
let far_t = (t_far_x.min(t_far_y.min(t_far_z)) * Vec4::splat(BBOX_MAXT_ADJUST)).min(max_t);
|
||||||
(t_far_x.v_min(t_far_y.v_min(t_far_z)) * Float4::splat(BBOX_MAXT_ADJUST)).v_min(max_t);
|
|
||||||
|
|
||||||
// Calculate over-all near t hit.
|
// Calculate over-all near t hit.
|
||||||
let near_t = t_near_x
|
let near_t = t_near_x.max(t_near_y).max(t_near_z.max(Vec4::splat(0.0)));
|
||||||
.v_max(t_near_y)
|
|
||||||
.v_max(t_near_z.v_max(Float4::splat(0.0)));
|
|
||||||
|
|
||||||
// Hit results
|
// Hit results
|
||||||
near_t.lt(far_t)
|
near_t.cmplt(far_t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,9 +103,9 @@ impl BitOr for BBox4 {
|
||||||
|
|
||||||
fn bitor(self, rhs: BBox4) -> BBox4 {
|
fn bitor(self, rhs: BBox4) -> BBox4 {
|
||||||
BBox4 {
|
BBox4 {
|
||||||
x: (self.x.0.v_min(rhs.x.0), self.x.1.v_max(rhs.x.1)),
|
x: (self.x.0.min(rhs.x.0), self.x.1.max(rhs.x.1)),
|
||||||
y: (self.y.0.v_min(rhs.y.0), self.y.1.v_max(rhs.y.1)),
|
y: (self.y.0.min(rhs.y.0), self.y.1.max(rhs.y.1)),
|
||||||
z: (self.z.0.v_min(rhs.z.0), self.z.1.v_max(rhs.z.1)),
|
z: (self.z.0.min(rhs.z.0), self.z.1.max(rhs.z.1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
src/color.rs
48
src/color.rs
|
@ -4,7 +4,7 @@ pub use color::{
|
||||||
rec709_e_to_xyz, rec709_to_xyz, xyz_to_aces_ap0, xyz_to_aces_ap0_e, xyz_to_rec709,
|
rec709_e_to_xyz, rec709_to_xyz, xyz_to_aces_ap0, xyz_to_aces_ap0_e, xyz_to_rec709,
|
||||||
xyz_to_rec709_e,
|
xyz_to_rec709_e,
|
||||||
};
|
};
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
use half::f16;
|
use half::f16;
|
||||||
use spectral_upsampling::meng::{spectrum_xyz_to_p_4, EQUAL_ENERGY_REFLECTANCE};
|
use spectral_upsampling::meng::{spectrum_xyz_to_p_4, EQUAL_ENERGY_REFLECTANCE};
|
||||||
use trifloat::signed48;
|
use trifloat::signed48;
|
||||||
|
@ -31,10 +31,10 @@ fn nth_wavelength(hero_wavelength: f32, n: usize) -> f32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all wavelengths of a hero wavelength set as a Float4
|
/// Returns all wavelengths of a hero wavelength set as a Vec4
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn wavelengths(hero_wavelength: f32) -> Float4 {
|
fn wavelengths(hero_wavelength: f32) -> Vec4 {
|
||||||
Float4::new(
|
Vec4::new(
|
||||||
nth_wavelength(hero_wavelength, 0),
|
nth_wavelength(hero_wavelength, 0),
|
||||||
nth_wavelength(hero_wavelength, 1),
|
nth_wavelength(hero_wavelength, 1),
|
||||||
nth_wavelength(hero_wavelength, 2),
|
nth_wavelength(hero_wavelength, 2),
|
||||||
|
@ -94,11 +94,11 @@ impl Color {
|
||||||
} => {
|
} => {
|
||||||
SpectralSample::from_parts(
|
SpectralSample::from_parts(
|
||||||
// TODO: make this SIMD
|
// TODO: make this SIMD
|
||||||
Float4::new(
|
Vec4::new(
|
||||||
plancks_law(temperature, wls.get_0()) * factor,
|
plancks_law(temperature, wls.x()) * factor,
|
||||||
plancks_law(temperature, wls.get_1()) * factor,
|
plancks_law(temperature, wls.y()) * factor,
|
||||||
plancks_law(temperature, wls.get_2()) * factor,
|
plancks_law(temperature, wls.z()) * factor,
|
||||||
plancks_law(temperature, wls.get_3()) * factor,
|
plancks_law(temperature, wls.w()) * factor,
|
||||||
),
|
),
|
||||||
hero_wavelength,
|
hero_wavelength,
|
||||||
)
|
)
|
||||||
|
@ -109,11 +109,11 @@ impl Color {
|
||||||
} => {
|
} => {
|
||||||
SpectralSample::from_parts(
|
SpectralSample::from_parts(
|
||||||
// TODO: make this SIMD
|
// TODO: make this SIMD
|
||||||
Float4::new(
|
Vec4::new(
|
||||||
plancks_law_normalized(temperature, wls.get_0()) * factor,
|
plancks_law_normalized(temperature, wls.x()) * factor,
|
||||||
plancks_law_normalized(temperature, wls.get_1()) * factor,
|
plancks_law_normalized(temperature, wls.y()) * factor,
|
||||||
plancks_law_normalized(temperature, wls.get_2()) * factor,
|
plancks_law_normalized(temperature, wls.z()) * factor,
|
||||||
plancks_law_normalized(temperature, wls.get_3()) * factor,
|
plancks_law_normalized(temperature, wls.w()) * factor,
|
||||||
),
|
),
|
||||||
hero_wavelength,
|
hero_wavelength,
|
||||||
)
|
)
|
||||||
|
@ -388,7 +388,7 @@ fn plancks_law_normalized(temperature: f32, wavelength: f32) -> f32 {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SpectralSample {
|
pub struct SpectralSample {
|
||||||
pub e: Float4,
|
pub e: Vec4,
|
||||||
hero_wavelength: f32,
|
hero_wavelength: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ impl SpectralSample {
|
||||||
pub fn new(wavelength: f32) -> SpectralSample {
|
pub fn new(wavelength: f32) -> SpectralSample {
|
||||||
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
||||||
SpectralSample {
|
SpectralSample {
|
||||||
e: Float4::splat(0.0),
|
e: Vec4::splat(0.0),
|
||||||
hero_wavelength: wavelength,
|
hero_wavelength: wavelength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,12 +405,12 @@ impl SpectralSample {
|
||||||
pub fn from_value(value: f32, wavelength: f32) -> SpectralSample {
|
pub fn from_value(value: f32, wavelength: f32) -> SpectralSample {
|
||||||
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
||||||
SpectralSample {
|
SpectralSample {
|
||||||
e: Float4::splat(value),
|
e: Vec4::splat(value),
|
||||||
hero_wavelength: wavelength,
|
hero_wavelength: wavelength,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_parts(e: Float4, wavelength: f32) -> SpectralSample {
|
pub fn from_parts(e: Vec4, wavelength: f32) -> SpectralSample {
|
||||||
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
|
||||||
SpectralSample {
|
SpectralSample {
|
||||||
e: e,
|
e: e,
|
||||||
|
@ -520,10 +520,10 @@ impl XYZ {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_spectral_sample(ss: &SpectralSample) -> XYZ {
|
pub fn from_spectral_sample(ss: &SpectralSample) -> XYZ {
|
||||||
let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e.get_0());
|
let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e.x());
|
||||||
let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e.get_1());
|
let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e.y());
|
||||||
let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e.get_2());
|
let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e.z());
|
||||||
let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e.get_3());
|
let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e.w());
|
||||||
(xyz0 + xyz1 + xyz2 + xyz3) * 0.75
|
(xyz0 + xyz1 + xyz2 + xyz3) * 0.75
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,8 +601,8 @@ impl DivAssign<f32> for XYZ {
|
||||||
/// the method in the paper "Physically Meaningful Rendering using Tristimulus
|
/// the method in the paper "Physically Meaningful Rendering using Tristimulus
|
||||||
/// Colours" by Meng et al.
|
/// Colours" by Meng et al.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn xyz_to_spectrum_4(xyz: (f32, f32, f32), wavelengths: Float4) -> Float4 {
|
fn xyz_to_spectrum_4(xyz: (f32, f32, f32), wavelengths: Vec4) -> Vec4 {
|
||||||
spectrum_xyz_to_p_4(wavelengths, xyz) * Float4::splat(1.0 / EQUAL_ENERGY_REFLECTANCE)
|
spectrum_xyz_to_p_4(wavelengths, xyz) * Vec4::splat(1.0 / EQUAL_ENERGY_REFLECTANCE)
|
||||||
// aces_to_spectrum_p4(wavelengths, xyz_to_aces_ap0_e(xyz))
|
// aces_to_spectrum_p4(wavelengths, xyz_to_aces_ap0_e(xyz))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
src/lerp.rs
14
src/lerp.rs
|
@ -73,23 +73,15 @@ impl<T: Lerp> Lerp for (T, T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lerp for float4::Float4 {
|
impl Lerp for glam::Vec4 {
|
||||||
fn lerp(self, other: float4::Float4, alpha: f32) -> float4::Float4 {
|
fn lerp(self, other: glam::Vec4, alpha: f32) -> glam::Vec4 {
|
||||||
(self * (1.0 - alpha)) + (other * alpha)
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lerp for Matrix4x4 {
|
impl Lerp for Matrix4x4 {
|
||||||
fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 {
|
fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 {
|
||||||
let alpha_minus = 1.0 - alpha;
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
Matrix4x4 {
|
|
||||||
values: [
|
|
||||||
(self[0] * alpha_minus) + (other[0] * alpha),
|
|
||||||
(self[1] * alpha_minus) + (other[1] * alpha),
|
|
||||||
(self[2] * alpha_minus) + (other[2] * alpha),
|
|
||||||
(self[3] * alpha_minus) + (other[3] * alpha),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/ray.rs
12
src/ray.rs
|
@ -1,6 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use float4::{Bool4, Float4};
|
use glam::{Vec4, Vec4Mask};
|
||||||
|
|
||||||
use crate::math::{Matrix4x4, Point, Vector};
|
use crate::math::{Matrix4x4, Point, Vector};
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ impl RayBatch {
|
||||||
pub fn set_from_ray(&mut self, ray: &Ray, is_occlusion: bool, idx: usize) {
|
pub fn set_from_ray(&mut self, ray: &Ray, is_occlusion: bool, idx: usize) {
|
||||||
self.hot[idx].orig_local = ray.orig;
|
self.hot[idx].orig_local = ray.orig;
|
||||||
self.hot[idx].dir_inv_local = Vector {
|
self.hot[idx].dir_inv_local = Vector {
|
||||||
co: Float4::splat(1.0) / ray.dir.co,
|
co: Vec4::splat(1.0) / ray.dir.co,
|
||||||
};
|
};
|
||||||
self.hot[idx].max_t = ray.max_t;
|
self.hot[idx].max_t = ray.max_t;
|
||||||
self.hot[idx].time = ray.time;
|
self.hot[idx].time = ray.time;
|
||||||
|
@ -122,7 +122,7 @@ impl RayBatch {
|
||||||
pub fn update_local(&mut self, idx: usize, xform: &Matrix4x4) {
|
pub fn update_local(&mut self, idx: usize, xform: &Matrix4x4) {
|
||||||
self.hot[idx].orig_local = self.cold[idx].orig * *xform;
|
self.hot[idx].orig_local = self.cold[idx].orig * *xform;
|
||||||
self.hot[idx].dir_inv_local = Vector {
|
self.hot[idx].dir_inv_local = Vector {
|
||||||
co: Float4::splat(1.0) / (self.cold[idx].dir * *xform).co,
|
co: Vec4::splat(1.0) / (self.cold[idx].dir * *xform).co,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ impl RayStack {
|
||||||
/// indicated lanes.
|
/// indicated lanes.
|
||||||
pub fn pop_do_next_task_and_push_rays<F>(&mut self, output_lane_count: usize, mut handle_ray: F)
|
pub fn pop_do_next_task_and_push_rays<F>(&mut self, output_lane_count: usize, mut handle_ray: F)
|
||||||
where
|
where
|
||||||
F: FnMut(usize) -> Bool4,
|
F: FnMut(usize) -> Vec4Mask,
|
||||||
{
|
{
|
||||||
// Pop the task and do necessary bookkeeping.
|
// Pop the task and do necessary bookkeeping.
|
||||||
let task = self.tasks.pop().unwrap();
|
let task = self.tasks.pop().unwrap();
|
||||||
|
@ -372,9 +372,9 @@ impl RayStack {
|
||||||
// Execute task.
|
// Execute task.
|
||||||
for i in task_range.0..task_range.1 {
|
for i in task_range.0..task_range.1 {
|
||||||
let ray_idx = *unsafe { self.lanes[task.lane].idxs.get_unchecked(i) };
|
let ray_idx = *unsafe { self.lanes[task.lane].idxs.get_unchecked(i) };
|
||||||
let push_mask = handle_ray(ray_idx as usize);
|
let push_mask = handle_ray(ray_idx as usize).bitmask();
|
||||||
for l in 0..output_lane_count {
|
for l in 0..output_lane_count {
|
||||||
if push_mask.get_n(l) {
|
if (push_mask & (1 << l)) != 0 {
|
||||||
self.lanes[l as usize].idxs.push(ray_idx);
|
self.lanes[l as usize].idxs.push(ray_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
use crossbeam::sync::MsQueue;
|
use crossbeam::sync::MsQueue;
|
||||||
use scoped_threadpool::Pool;
|
use scoped_threadpool::Pool;
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accel::ACCEL_NODE_RAY_TESTS,
|
accel::ACCEL_NODE_RAY_TESTS,
|
||||||
|
@ -374,12 +374,12 @@ pub struct LightPath {
|
||||||
wavelength: f32,
|
wavelength: f32,
|
||||||
|
|
||||||
next_bounce_ray: Option<Ray>,
|
next_bounce_ray: Option<Ray>,
|
||||||
next_attenuation_fac: Float4,
|
next_attenuation_fac: Vec4,
|
||||||
|
|
||||||
closure_sample_pdf: f32,
|
closure_sample_pdf: f32,
|
||||||
light_attenuation: Float4,
|
light_attenuation: Vec4,
|
||||||
pending_color_addition: Float4,
|
pending_color_addition: Vec4,
|
||||||
color: Float4,
|
color: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
@ -405,12 +405,12 @@ impl LightPath {
|
||||||
wavelength: wavelength,
|
wavelength: wavelength,
|
||||||
|
|
||||||
next_bounce_ray: None,
|
next_bounce_ray: None,
|
||||||
next_attenuation_fac: Float4::splat(1.0),
|
next_attenuation_fac: Vec4::splat(1.0),
|
||||||
|
|
||||||
closure_sample_pdf: 1.0,
|
closure_sample_pdf: 1.0,
|
||||||
light_attenuation: Float4::splat(1.0),
|
light_attenuation: Vec4::splat(1.0),
|
||||||
pending_color_addition: Float4::splat(0.0),
|
pending_color_addition: Vec4::splat(0.0),
|
||||||
color: Float4::splat(0.0),
|
color: Vec4::splat(0.0),
|
||||||
},
|
},
|
||||||
scene.camera.generate_ray(
|
scene.camera.generate_ray(
|
||||||
image_plane_co.0,
|
image_plane_co.0,
|
||||||
|
@ -565,7 +565,7 @@ impl LightPath {
|
||||||
|
|
||||||
// If there's any possible contribution, set up for a
|
// If there's any possible contribution, set up for a
|
||||||
// light ray.
|
// light ray.
|
||||||
if attenuation.e.h_max() <= 0.0 {
|
if attenuation.e.max_element() <= 0.0 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
// Calculate and store the light that will be contributed
|
// Calculate and store the light that will be contributed
|
||||||
|
@ -599,7 +599,7 @@ impl LightPath {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if pdf is zero, to avoid NaN's.
|
// Check if pdf is zero, to avoid NaN's.
|
||||||
if (pdf > 0.0) && (filter.e.h_max() > 0.0) {
|
if (pdf > 0.0) && (filter.e.max_element() > 0.0) {
|
||||||
// Account for the additional light attenuation from
|
// Account for the additional light attenuation from
|
||||||
// this bounce
|
// this bounce
|
||||||
self.next_attenuation_fac = filter.e;
|
self.next_attenuation_fac = filter.e;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::f32::consts::PI as PI_32;
|
use std::f32::consts::PI as PI_32;
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::{Color, SpectralSample},
|
color::{Color, SpectralSample},
|
||||||
|
@ -492,27 +492,27 @@ mod ggx_closure {
|
||||||
let spectrum_sample = col.to_spectral_sample(wavelength);
|
let spectrum_sample = col.to_spectral_sample(wavelength);
|
||||||
let rev_fresnel = 1.0 - fresnel;
|
let rev_fresnel = 1.0 - fresnel;
|
||||||
let c0 = lerp(
|
let c0 = lerp(
|
||||||
schlick_fresnel_from_fac(spectrum_sample.e.get_0(), hb),
|
schlick_fresnel_from_fac(spectrum_sample.e.x(), hb),
|
||||||
spectrum_sample.e.get_0(),
|
spectrum_sample.e.x(),
|
||||||
rev_fresnel,
|
rev_fresnel,
|
||||||
);
|
);
|
||||||
let c1 = lerp(
|
let c1 = lerp(
|
||||||
schlick_fresnel_from_fac(spectrum_sample.e.get_1(), hb),
|
schlick_fresnel_from_fac(spectrum_sample.e.y(), hb),
|
||||||
spectrum_sample.e.get_1(),
|
spectrum_sample.e.y(),
|
||||||
rev_fresnel,
|
rev_fresnel,
|
||||||
);
|
);
|
||||||
let c2 = lerp(
|
let c2 = lerp(
|
||||||
schlick_fresnel_from_fac(spectrum_sample.e.get_2(), hb),
|
schlick_fresnel_from_fac(spectrum_sample.e.z(), hb),
|
||||||
spectrum_sample.e.get_2(),
|
spectrum_sample.e.z(),
|
||||||
rev_fresnel,
|
rev_fresnel,
|
||||||
);
|
);
|
||||||
let c3 = lerp(
|
let c3 = lerp(
|
||||||
schlick_fresnel_from_fac(spectrum_sample.e.get_3(), hb),
|
schlick_fresnel_from_fac(spectrum_sample.e.w(), hb),
|
||||||
spectrum_sample.e.get_3(),
|
spectrum_sample.e.w(),
|
||||||
rev_fresnel,
|
rev_fresnel,
|
||||||
);
|
);
|
||||||
|
|
||||||
SpectralSample::from_parts(Float4::new(c0, c1, c2, c3), wavelength)
|
SpectralSample::from_parts(Vec4::new(c0, c1, c2, c3), wavelength)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate everything else
|
// Calculate everything else
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub fn surface_point(tri: (Point, Point, Point), bary: (f32, f32, f32)) -> (Poin
|
||||||
+ (tri.2.into_vector().abs() * bary.2))
|
+ (tri.2.into_vector().abs() * bary.2))
|
||||||
* fp_gamma(7))
|
* fp_gamma(7))
|
||||||
.co
|
.co
|
||||||
.h_max();
|
.max_element();
|
||||||
|
|
||||||
(pos, pos_err)
|
(pos, pos_err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "float4"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Nathan Vegdahl <cessen@cessen.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
license = "MIT"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "float4"
|
|
||||||
path = "src/lib.rs"
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,5 +10,6 @@ name = "math3d"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
# Local crate dependencies
|
# Local crate dependencies
|
||||||
[dependencies.float4]
|
[dependencies]
|
||||||
path = "../float4"
|
glam = {git="https://github.com/bitshifter/glam-rs.git", rev="0f314f99", default-features=false, features=["approx"]}
|
||||||
|
approx = "0.3"
|
||||||
|
|
|
@ -1,29 +1,21 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut, Mul};
|
use std::ops::{Add, Mul};
|
||||||
|
|
||||||
use float4::{invert, transpose, Float4};
|
use approx::RelativeEq;
|
||||||
|
use glam::{Mat4, Vec4};
|
||||||
|
|
||||||
use super::Point;
|
use super::Point;
|
||||||
|
|
||||||
/// A 4x4 matrix, used for transforms
|
/// A 4x4 matrix, used for transforms
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct Matrix4x4 {
|
pub struct Matrix4x4(pub Mat4);
|
||||||
pub values: [Float4; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Matrix4x4 {
|
impl Matrix4x4 {
|
||||||
/// Creates a new identity matrix
|
/// Creates a new identity matrix
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Matrix4x4 {
|
pub fn new() -> Matrix4x4 {
|
||||||
Matrix4x4 {
|
Matrix4x4(Mat4::identity())
|
||||||
values: [
|
|
||||||
Float4::new(1.0, 0.0, 0.0, 0.0),
|
|
||||||
Float4::new(0.0, 1.0, 0.0, 0.0),
|
|
||||||
Float4::new(0.0, 0.0, 1.0, 0.0),
|
|
||||||
Float4::new(0.0, 0.0, 0.0, 1.0),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new matrix with the specified values:
|
/// Creates a new matrix with the specified values:
|
||||||
|
@ -52,108 +44,37 @@ impl Matrix4x4 {
|
||||||
o: f32,
|
o: f32,
|
||||||
p: f32,
|
p: f32,
|
||||||
) -> Matrix4x4 {
|
) -> Matrix4x4 {
|
||||||
Matrix4x4 {
|
Matrix4x4(Mat4::new(
|
||||||
values: [
|
Vec4::new(a, e, i, m),
|
||||||
Float4::new(a, b, c, d),
|
Vec4::new(b, f, j, n),
|
||||||
Float4::new(e, f, g, h),
|
Vec4::new(c, g, k, o),
|
||||||
Float4::new(i, j, k, l),
|
Vec4::new(d, h, l, p),
|
||||||
Float4::new(m, n, o, p),
|
))
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_location(loc: Point) -> Matrix4x4 {
|
pub fn from_location(loc: Point) -> Matrix4x4 {
|
||||||
Matrix4x4 {
|
Matrix4x4(Mat4::from_translation(loc.co.truncate()))
|
||||||
values: [
|
|
||||||
Float4::new(1.0, 0.0, 0.0, loc.x()),
|
|
||||||
Float4::new(0.0, 1.0, 0.0, loc.y()),
|
|
||||||
Float4::new(0.0, 0.0, 1.0, loc.z()),
|
|
||||||
Float4::new(0.0, 0.0, 0.0, 1.0),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the matrices are approximately equal to each other.
|
/// Returns whether the matrices are approximately equal to each other.
|
||||||
/// Each corresponding element in the matrices cannot have a relative error
|
/// Each corresponding element in the matrices cannot have a relative
|
||||||
/// exceeding `epsilon`.
|
/// error exceeding epsilon.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn aprx_eq(&self, other: Matrix4x4, epsilon: f32) -> bool {
|
pub fn aprx_eq(&self, other: Matrix4x4, epsilon: f32) -> bool {
|
||||||
let mut result = true;
|
self.0.relative_eq(&other.0, std::f32::EPSILON, epsilon)
|
||||||
|
|
||||||
for y in 0..4 {
|
|
||||||
for x in 0..4 {
|
|
||||||
// All of this stuff is just an approximate comparison
|
|
||||||
// of floating point numbers. See:
|
|
||||||
// http://floating-point-gui.de/errors/comparison/
|
|
||||||
// It might be worth breaking this out into a separate funcion,
|
|
||||||
// but I'm not entirely sure where to put it.
|
|
||||||
let a = self[y].get_n(x);
|
|
||||||
let b = other[y].get_n(x);
|
|
||||||
let aabs = a.abs();
|
|
||||||
let babs = b.abs();
|
|
||||||
let diff = (a - b).abs();
|
|
||||||
if a == b {
|
|
||||||
} else if (aabs <= std::f32::EPSILON) || (babs <= std::f32::EPSILON) {
|
|
||||||
result = result && (diff < std::f32::EPSILON);
|
|
||||||
} else {
|
|
||||||
let rel = 2.0 * diff / (aabs + babs);
|
|
||||||
println!("{}", rel);
|
|
||||||
result = result && (rel < epsilon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the transpose of the matrix
|
/// Returns the transpose of the matrix
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transposed(&self) -> Matrix4x4 {
|
pub fn transposed(&self) -> Matrix4x4 {
|
||||||
let mut m = *self;
|
Matrix4x4(self.0.transpose())
|
||||||
transpose(&mut m.values);
|
|
||||||
m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inverse of the Matrix
|
/// Returns the inverse of the Matrix
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::float_cmp)]
|
|
||||||
pub fn inverse(&self) -> Matrix4x4 {
|
pub fn inverse(&self) -> Matrix4x4 {
|
||||||
let mut m = *self;
|
Matrix4x4(self.0.inverse())
|
||||||
let det = invert(&mut m.values);
|
|
||||||
debug_assert_ne!(det, 0.0);
|
|
||||||
m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Matrix4x4 {
|
|
||||||
type Output = Float4;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn index(&self, _index: usize) -> &Float4 {
|
|
||||||
&self.values[_index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Matrix4x4 {
|
|
||||||
#[inline(always)]
|
|
||||||
fn index_mut(&mut self, _index: usize) -> &mut Float4 {
|
|
||||||
&mut self.values[_index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Matrix4x4 {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Matrix4x4) -> bool {
|
|
||||||
let mut result = true;
|
|
||||||
|
|
||||||
for y in 0..4 {
|
|
||||||
for x in 0..4 {
|
|
||||||
result = result && (self[y].get_n(x) == other[y].get_n(x));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,40 +85,32 @@ impl Default for Matrix4x4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply two matrices together
|
/// Multiply two matrices together
|
||||||
impl Mul<Matrix4x4> for Matrix4x4 {
|
impl Mul for Matrix4x4 {
|
||||||
type Output = Matrix4x4;
|
type Output = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, other: Matrix4x4) -> Matrix4x4 {
|
fn mul(self, other: Self) -> Self {
|
||||||
let m = self.transposed();
|
Self(other.0.mul_mat4(&self.0))
|
||||||
Matrix4x4 {
|
|
||||||
values: [
|
|
||||||
Float4::new(
|
|
||||||
(m[0] * other[0]).h_sum(),
|
|
||||||
(m[1] * other[0]).h_sum(),
|
|
||||||
(m[2] * other[0]).h_sum(),
|
|
||||||
(m[3] * other[0]).h_sum(),
|
|
||||||
),
|
|
||||||
Float4::new(
|
|
||||||
(m[0] * other[1]).h_sum(),
|
|
||||||
(m[1] * other[1]).h_sum(),
|
|
||||||
(m[2] * other[1]).h_sum(),
|
|
||||||
(m[3] * other[1]).h_sum(),
|
|
||||||
),
|
|
||||||
Float4::new(
|
|
||||||
(m[0] * other[2]).h_sum(),
|
|
||||||
(m[1] * other[2]).h_sum(),
|
|
||||||
(m[2] * other[2]).h_sum(),
|
|
||||||
(m[3] * other[2]).h_sum(),
|
|
||||||
),
|
|
||||||
Float4::new(
|
|
||||||
(m[0] * other[3]).h_sum(),
|
|
||||||
(m[1] * other[3]).h_sum(),
|
|
||||||
(m[2] * other[3]).h_sum(),
|
|
||||||
(m[3] * other[3]).h_sum(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiply a matrix by a f32
|
||||||
|
impl Mul<f32> for Matrix4x4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn mul(self, other: f32) -> Self {
|
||||||
|
Self(self.0 * other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add two matrices together
|
||||||
|
impl Add for Matrix4x4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: Self) -> Self {
|
||||||
|
Self(self.0 + other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,22 +131,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aproximate_equality_test() {
|
fn approximate_equality_test() {
|
||||||
let a = Matrix4x4::new();
|
let a = Matrix4x4::new();
|
||||||
let b = Matrix4x4::new_from_values(
|
let b = Matrix4x4::new_from_values(
|
||||||
1.001, 0.0, 0.0, 0.0, 0.0, 1.001, 0.0, 0.0, 0.0, 0.0, 1.001, 0.0, 0.0, 0.0, 0.0, 1.001,
|
1.000001, 0.0, 0.0, 0.0, 0.0, 1.000001, 0.0, 0.0, 0.0, 0.0, 1.000001, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.000001,
|
||||||
);
|
);
|
||||||
let c = Matrix4x4::new_from_values(
|
let c = Matrix4x4::new_from_values(
|
||||||
1.003, 0.0, 0.0, 0.0, 0.0, 1.003, 0.0, 0.0, 0.0, 0.0, 1.003, 0.0, 0.0, 0.0, 0.0, 1.003,
|
1.000003, 0.0, 0.0, 0.0, 0.0, 1.000003, 0.0, 0.0, 0.0, 0.0, 1.000003, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.000003,
|
||||||
);
|
);
|
||||||
let d = Matrix4x4::new_from_values(
|
let d = Matrix4x4::new_from_values(
|
||||||
-1.001, 0.0, 0.0, 0.0, 0.0, -1.001, 0.0, 0.0, 0.0, 0.0, -1.001, 0.0, 0.0, 0.0, 0.0,
|
-1.000001, 0.0, 0.0, 0.0, 0.0, -1.000001, 0.0, 0.0, 0.0, 0.0, -1.000001, 0.0, 0.0, 0.0,
|
||||||
-1.001,
|
0.0, -1.000001,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(a.aprx_eq(b, 0.002));
|
assert!(a.aprx_eq(b, 0.000001));
|
||||||
assert!(!a.aprx_eq(c, 0.002));
|
assert!(!a.aprx_eq(c, 0.000001));
|
||||||
assert!(!a.aprx_eq(d, 0.002));
|
assert!(!a.aprx_eq(d, 0.000001));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -260,7 +175,7 @@ mod tests {
|
||||||
let b = a.inverse();
|
let b = a.inverse();
|
||||||
let c = Matrix4x4::new();
|
let c = Matrix4x4::new();
|
||||||
|
|
||||||
assert!((a * b).aprx_eq(c, 0.00001));
|
assert!((dbg!(a * b)).aprx_eq(dbg!(c), 0.0000001));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -5,42 +5,44 @@ use std::{
|
||||||
ops::{Add, Div, Mul, Neg, Sub},
|
ops::{Add, Div, Mul, Neg, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
use super::{CrossProduct, DotProduct, Matrix4x4, Vector};
|
use super::{CrossProduct, DotProduct, Matrix4x4, Vector};
|
||||||
|
|
||||||
/// A surface normal in 3d homogeneous space.
|
/// A surface normal in 3d homogeneous space.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Normal {
|
pub struct Normal {
|
||||||
pub co: Float4,
|
pub co: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Normal {
|
impl Normal {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Normal {
|
pub fn new(x: f32, y: f32, z: f32) -> Normal {
|
||||||
Normal {
|
Normal {
|
||||||
co: Float4::new(x, y, z, 0.0),
|
co: Vec4::new(x, y, z, 0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn length(&self) -> f32 {
|
pub fn length(&self) -> f32 {
|
||||||
(self.co * self.co).h_sum().sqrt()
|
self.co.length()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn length2(&self) -> f32 {
|
pub fn length2(&self) -> f32 {
|
||||||
(self.co * self.co).h_sum()
|
self.co.length_squared()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn normalized(&self) -> Normal {
|
pub fn normalized(&self) -> Normal {
|
||||||
*self / self.length()
|
Normal {
|
||||||
|
co: self.co.normalize(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_vector(self) -> Vector {
|
pub fn into_vector(self) -> Vector {
|
||||||
Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2())
|
Vector { co: self.co }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -55,32 +57,32 @@ impl Normal {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(&self) -> f32 {
|
||||||
self.co.get_0()
|
self.co.x()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn y(&self) -> f32 {
|
pub fn y(&self) -> f32 {
|
||||||
self.co.get_1()
|
self.co.y()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn z(&self) -> f32 {
|
pub fn z(&self) -> f32 {
|
||||||
self.co.get_2()
|
self.co.z()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_x(&mut self, x: f32) {
|
pub fn set_x(&mut self, x: f32) {
|
||||||
self.co.set_0(x);
|
self.co.set_x(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_y(&mut self, y: f32) {
|
pub fn set_y(&mut self, y: f32) {
|
||||||
self.co.set_1(y);
|
self.co.set_y(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_z(&mut self, z: f32) {
|
pub fn set_z(&mut self, z: f32) {
|
||||||
self.co.set_2(z);
|
self.co.set_z(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,15 +131,10 @@ impl Mul<Matrix4x4> for Normal {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, other: Matrix4x4) -> Normal {
|
fn mul(self, other: Matrix4x4) -> Normal {
|
||||||
let mat = other.inverse().transposed();
|
let mat = other.0.inverse().transpose();
|
||||||
Normal {
|
let mut co = mat.mul_vec4(self.co);
|
||||||
co: Float4::new(
|
co.set_w(0.0);
|
||||||
(self.co * mat.values[0]).h_sum(),
|
Normal { co: co }
|
||||||
(self.co * mat.values[1]).h_sum(),
|
|
||||||
(self.co * mat.values[2]).h_sum(),
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +161,7 @@ impl Neg for Normal {
|
||||||
impl DotProduct for Normal {
|
impl DotProduct for Normal {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn dot(self, other: Normal) -> f32 {
|
fn dot(self, other: Normal) -> f32 {
|
||||||
(self.co * other.co).h_sum()
|
self.co.dot(other.co)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +169,7 @@ impl CrossProduct for Normal {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cross(self, other: Normal) -> Normal {
|
fn cross(self, other: Normal) -> Normal {
|
||||||
Normal {
|
Normal {
|
||||||
co: Float4::new(
|
co: self.co.truncate().cross(other.co.truncate()).extend(0.0),
|
||||||
(self.co.get_1() * other.co.get_2()) - (self.co.get_2() * other.co.get_1()),
|
|
||||||
(self.co.get_2() * other.co.get_0()) - (self.co.get_0() * other.co.get_2()),
|
|
||||||
(self.co.get_0() * other.co.get_1()) - (self.co.get_1() * other.co.get_0()),
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +178,7 @@ impl CrossProduct for Normal {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::{CrossProduct, DotProduct, Matrix4x4};
|
use super::super::{CrossProduct, DotProduct, Matrix4x4};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use approx::UlpsEq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add() {
|
fn add() {
|
||||||
|
@ -220,8 +213,10 @@ mod tests {
|
||||||
let m = Matrix4x4::new_from_values(
|
let m = Matrix4x4::new_from_values(
|
||||||
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 13.0, 7.0, 15.0, 3.0,
|
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 13.0, 7.0, 15.0, 3.0,
|
||||||
);
|
);
|
||||||
let nm = Normal::new(-19.258825, 5.717648, -1.770588);
|
let mut nm = n * m;
|
||||||
assert!(((n * m) - nm).length2() < 0.00001);
|
nm.co.set_w(0.0);
|
||||||
|
let nm2 = Normal::new(-19.258825, 5.717648, -1.770588);
|
||||||
|
assert!(nm.co.ulps_eq(&nm2.co, 0.0, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -5,21 +5,21 @@ use std::{
|
||||||
ops::{Add, Mul, Sub},
|
ops::{Add, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
use super::{Matrix4x4, Vector};
|
use super::{Matrix4x4, Vector};
|
||||||
|
|
||||||
/// A position in 3d homogeneous space.
|
/// A position in 3d homogeneous space.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub co: Float4,
|
pub co: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Point {
|
impl Point {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Point {
|
pub fn new(x: f32, y: f32, z: f32) -> Point {
|
||||||
Point {
|
Point {
|
||||||
co: Float4::new(x, y, z, 1.0),
|
co: Vec4::new(x, y, z, 1.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ impl Point {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn norm(&self) -> Point {
|
pub fn norm(&self) -> Point {
|
||||||
Point {
|
Point {
|
||||||
co: self.co / self.co.get_3(),
|
co: self.co / self.co.w(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ impl Point {
|
||||||
let n2 = other.norm();
|
let n2 = other.norm();
|
||||||
|
|
||||||
Point {
|
Point {
|
||||||
co: n1.co.v_min(n2.co),
|
co: n1.co.min(n2.co),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,13 +48,15 @@ impl Point {
|
||||||
let n2 = other.norm();
|
let n2 = other.norm();
|
||||||
|
|
||||||
Point {
|
Point {
|
||||||
co: n1.co.v_max(n2.co),
|
co: n1.co.max(n2.co),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_vector(self) -> Vector {
|
pub fn into_vector(self) -> Vector {
|
||||||
Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2())
|
let mut v = Vector { co: self.co };
|
||||||
|
v.co.set_w(0.0);
|
||||||
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -69,32 +71,32 @@ impl Point {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(&self) -> f32 {
|
||||||
self.co.get_0()
|
self.co.x()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn y(&self) -> f32 {
|
pub fn y(&self) -> f32 {
|
||||||
self.co.get_1()
|
self.co.y()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn z(&self) -> f32 {
|
pub fn z(&self) -> f32 {
|
||||||
self.co.get_2()
|
self.co.z()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_x(&mut self, x: f32) {
|
pub fn set_x(&mut self, x: f32) {
|
||||||
self.co.set_0(x);
|
self.co.set_x(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_y(&mut self, y: f32) {
|
pub fn set_y(&mut self, y: f32) {
|
||||||
self.co.set_1(y);
|
self.co.set_y(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_z(&mut self, z: f32) {
|
pub fn set_z(&mut self, z: f32) {
|
||||||
self.co.set_2(z);
|
self.co.set_z(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,12 +146,7 @@ impl Mul<Matrix4x4> for Point {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, other: Matrix4x4) -> Point {
|
fn mul(self, other: Matrix4x4) -> Point {
|
||||||
Point {
|
Point {
|
||||||
co: Float4::new(
|
co: other.0.mul_vec4(self.co),
|
||||||
(self.co * other.values[0]).h_sum(),
|
|
||||||
(self.co * other.values[1]).h_sum(),
|
|
||||||
(self.co * other.values[2]).h_sum(),
|
|
||||||
(self.co * other.values[3]).h_sum(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +160,7 @@ mod tests {
|
||||||
fn norm() {
|
fn norm() {
|
||||||
let mut p1 = Point::new(1.0, 2.0, 3.0);
|
let mut p1 = Point::new(1.0, 2.0, 3.0);
|
||||||
let p2 = Point::new(2.0, 4.0, 6.0);
|
let p2 = Point::new(2.0, 4.0, 6.0);
|
||||||
p1.co.set_3(0.5);
|
p1.co.set_w(0.5);
|
||||||
|
|
||||||
assert_eq!(p2, p1.norm());
|
assert_eq!(p2, p1.norm());
|
||||||
}
|
}
|
||||||
|
@ -203,7 +200,7 @@ mod tests {
|
||||||
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 2.0, 3.0, 1.0, 5.0,
|
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 2.0, 3.0, 1.0, 5.0,
|
||||||
);
|
);
|
||||||
let mut pm = Point::new(15.5, 54.0, 70.0);
|
let mut pm = Point::new(15.5, 54.0, 70.0);
|
||||||
pm.co.set_3(18.5);
|
pm.co.set_w(18.5);
|
||||||
assert_eq!(p * m, pm);
|
assert_eq!(p * m, pm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,37 +5,39 @@ use std::{
|
||||||
ops::{Add, Div, Mul, Neg, Sub},
|
ops::{Add, Div, Mul, Neg, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
use super::{CrossProduct, DotProduct, Matrix4x4, Normal, Point};
|
use super::{CrossProduct, DotProduct, Matrix4x4, Normal, Point};
|
||||||
|
|
||||||
/// A direction vector in 3d homogeneous space.
|
/// A direction vector in 3d homogeneous space.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
pub co: Float4,
|
pub co: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vector {
|
impl Vector {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Vector {
|
pub fn new(x: f32, y: f32, z: f32) -> Vector {
|
||||||
Vector {
|
Vector {
|
||||||
co: Float4::new(x, y, z, 0.0),
|
co: Vec4::new(x, y, z, 0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn length(&self) -> f32 {
|
pub fn length(&self) -> f32 {
|
||||||
(self.co * self.co).h_sum().sqrt()
|
self.co.length()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn length2(&self) -> f32 {
|
pub fn length2(&self) -> f32 {
|
||||||
(self.co * self.co).h_sum()
|
self.co.length_squared()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn normalized(&self) -> Vector {
|
pub fn normalized(&self) -> Vector {
|
||||||
*self / self.length()
|
Vector {
|
||||||
|
co: self.co.normalize(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -65,32 +67,32 @@ impl Vector {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn x(&self) -> f32 {
|
pub fn x(&self) -> f32 {
|
||||||
self.co.get_0()
|
self.co.x()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn y(&self) -> f32 {
|
pub fn y(&self) -> f32 {
|
||||||
self.co.get_1()
|
self.co.y()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn z(&self) -> f32 {
|
pub fn z(&self) -> f32 {
|
||||||
self.co.get_2()
|
self.co.z()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_x(&mut self, x: f32) {
|
pub fn set_x(&mut self, x: f32) {
|
||||||
self.co.set_0(x);
|
self.co.set_x(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_y(&mut self, y: f32) {
|
pub fn set_y(&mut self, y: f32) {
|
||||||
self.co.set_1(y);
|
self.co.set_y(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_z(&mut self, z: f32) {
|
pub fn set_z(&mut self, z: f32) {
|
||||||
self.co.set_2(z);
|
self.co.set_z(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +142,7 @@ impl Mul<Matrix4x4> for Vector {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, other: Matrix4x4) -> Vector {
|
fn mul(self, other: Matrix4x4) -> Vector {
|
||||||
Vector {
|
Vector {
|
||||||
co: Float4::new(
|
co: other.0.mul_vec4(self.co),
|
||||||
(self.co * other.values[0]).h_sum(),
|
|
||||||
(self.co * other.values[1]).h_sum(),
|
|
||||||
(self.co * other.values[2]).h_sum(),
|
|
||||||
(self.co * other.values[3]).h_sum(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +170,7 @@ impl Neg for Vector {
|
||||||
impl DotProduct for Vector {
|
impl DotProduct for Vector {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn dot(self, other: Vector) -> f32 {
|
fn dot(self, other: Vector) -> f32 {
|
||||||
(self.co * other.co).h_sum()
|
self.co.dot(other.co)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,12 +178,7 @@ impl CrossProduct for Vector {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cross(self, other: Vector) -> Vector {
|
fn cross(self, other: Vector) -> Vector {
|
||||||
Vector {
|
Vector {
|
||||||
co: Float4::new(
|
co: self.co.truncate().cross(other.co.truncate()).extend(0.0),
|
||||||
(self.co.get_1() * other.co.get_2()) - (self.co.get_2() * other.co.get_1()),
|
|
||||||
(self.co.get_2() * other.co.get_0()) - (self.co.get_0() * other.co.get_2()),
|
|
||||||
(self.co.get_0() * other.co.get_1()) - (self.co.get_1() * other.co.get_0()),
|
|
||||||
0.0,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +222,7 @@ mod tests {
|
||||||
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 13.0, 7.0, 15.0, 3.0,
|
1.0, 2.0, 2.0, 1.5, 3.0, 6.0, 7.0, 8.0, 9.0, 2.0, 11.0, 12.0, 13.0, 7.0, 15.0, 3.0,
|
||||||
);
|
);
|
||||||
let mut vm = Vector::new(14.0, 46.0, 58.0);
|
let mut vm = Vector::new(14.0, 46.0, 58.0);
|
||||||
vm.co.set_3(90.5);
|
vm.co.set_w(90.5);
|
||||||
assert_eq!(v * m, vm);
|
assert_eq!(v * m, vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,5 @@ license = "MIT"
|
||||||
name = "spectral_upsampling"
|
name = "spectral_upsampling"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
# Local crate dependencies
|
[dependencies]
|
||||||
[dependencies.float4]
|
glam = {git="https://github.com/bitshifter/glam-rs.git", rev="0f314f99", default-features=false, features=["approx"]}
|
||||||
path = "../float4"
|
|
|
@ -6,7 +6,7 @@
|
||||||
/// The provides similar color matching as full Jakob, at the expense of
|
/// The provides similar color matching as full Jakob, at the expense of
|
||||||
/// somewhat lower quality spectrums, and the inability to precalculate
|
/// somewhat lower quality spectrums, and the inability to precalculate
|
||||||
/// the coefficents for even more efficient evaluation later on.
|
/// the coefficents for even more efficient evaluation later on.
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
/// How many polynomial coefficients?
|
/// How many polynomial coefficients?
|
||||||
const RGB2SPEC_N_COEFFS: usize = 3;
|
const RGB2SPEC_N_COEFFS: usize = 3;
|
||||||
|
@ -15,7 +15,7 @@ const RGB2SPEC_N_COEFFS: usize = 3;
|
||||||
include!(concat!(env!("OUT_DIR"), "/jakob_table_inc.rs"));
|
include!(concat!(env!("OUT_DIR"), "/jakob_table_inc.rs"));
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rec709_to_spectrum_p4(lambdas: Float4, rgb: (f32, f32, f32)) -> Float4 {
|
pub fn rec709_to_spectrum_p4(lambdas: Vec4, rgb: (f32, f32, f32)) -> Vec4 {
|
||||||
small_rgb_to_spectrum_p4(
|
small_rgb_to_spectrum_p4(
|
||||||
REC709_TABLE,
|
REC709_TABLE,
|
||||||
REC709_TABLE_RES,
|
REC709_TABLE_RES,
|
||||||
|
@ -26,7 +26,7 @@ pub fn rec709_to_spectrum_p4(lambdas: Float4, rgb: (f32, f32, f32)) -> Float4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rec2020_to_spectrum_p4(lambdas: Float4, rgb: (f32, f32, f32)) -> Float4 {
|
pub fn rec2020_to_spectrum_p4(lambdas: Vec4, rgb: (f32, f32, f32)) -> Vec4 {
|
||||||
small_rgb_to_spectrum_p4(
|
small_rgb_to_spectrum_p4(
|
||||||
REC2020_TABLE,
|
REC2020_TABLE,
|
||||||
REC2020_TABLE_RES,
|
REC2020_TABLE_RES,
|
||||||
|
@ -37,7 +37,7 @@ pub fn rec2020_to_spectrum_p4(lambdas: Float4, rgb: (f32, f32, f32)) -> Float4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn aces_to_spectrum_p4(lambdas: Float4, rgb: (f32, f32, f32)) -> Float4 {
|
pub fn aces_to_spectrum_p4(lambdas: Vec4, rgb: (f32, f32, f32)) -> Vec4 {
|
||||||
small_rgb_to_spectrum_p4(
|
small_rgb_to_spectrum_p4(
|
||||||
ACES_TABLE,
|
ACES_TABLE,
|
||||||
ACES_TABLE_RES,
|
ACES_TABLE_RES,
|
||||||
|
@ -55,9 +55,9 @@ fn small_rgb_to_spectrum_p4(
|
||||||
table: &[[(f32, f32, f32); 2]],
|
table: &[[(f32, f32, f32); 2]],
|
||||||
table_res: usize,
|
table_res: usize,
|
||||||
table_mid_value: f32,
|
table_mid_value: f32,
|
||||||
lambdas: Float4,
|
lambdas: Vec4,
|
||||||
rgb: (f32, f32, f32),
|
rgb: (f32, f32, f32),
|
||||||
) -> Float4 {
|
) -> Vec4 {
|
||||||
// Determine largest RGB component, and calculate the other two
|
// Determine largest RGB component, and calculate the other two
|
||||||
// components scaled for lookups.
|
// components scaled for lookups.
|
||||||
let (i, max_val, x, y) = if rgb.0 > rgb.1 && rgb.0 > rgb.2 {
|
let (i, max_val, x, y) = if rgb.0 > rgb.1 && rgb.0 > rgb.2 {
|
||||||
|
@ -70,7 +70,7 @@ fn small_rgb_to_spectrum_p4(
|
||||||
if max_val == 0.0 {
|
if max_val == 0.0 {
|
||||||
// If max_val is zero, just return zero. This avoids NaN's from
|
// If max_val is zero, just return zero. This avoids NaN's from
|
||||||
// divide by zero. This is also correct, since it's black.
|
// divide by zero. This is also correct, since it's black.
|
||||||
return Float4::splat(0.0);
|
return Vec4::splat(0.0);
|
||||||
}
|
}
|
||||||
let x = x * 63.0 / max_val;
|
let x = x * 63.0 / max_val;
|
||||||
let y = y * 63.0 / max_val;
|
let y = y * 63.0 / max_val;
|
||||||
|
@ -90,20 +90,20 @@ fn small_rgb_to_spectrum_p4(
|
||||||
|
|
||||||
// Convert to SIMD format for faster interpolation.
|
// Convert to SIMD format for faster interpolation.
|
||||||
let a0 = [
|
let a0 = [
|
||||||
Float4::new(a0[0].0, a0[0].1, a0[0].2, 0.0),
|
Vec4::new(a0[0].0, a0[0].1, a0[0].2, 0.0),
|
||||||
Float4::new(a0[1].0, a0[1].1, a0[1].2, 0.0),
|
Vec4::new(a0[1].0, a0[1].1, a0[1].2, 0.0),
|
||||||
];
|
];
|
||||||
let a1 = [
|
let a1 = [
|
||||||
Float4::new(a1[0].0, a1[0].1, a1[0].2, 0.0),
|
Vec4::new(a1[0].0, a1[0].1, a1[0].2, 0.0),
|
||||||
Float4::new(a1[1].0, a1[1].1, a1[1].2, 0.0),
|
Vec4::new(a1[1].0, a1[1].1, a1[1].2, 0.0),
|
||||||
];
|
];
|
||||||
let a2 = [
|
let a2 = [
|
||||||
Float4::new(a2[0].0, a2[0].1, a2[0].2, 0.0),
|
Vec4::new(a2[0].0, a2[0].1, a2[0].2, 0.0),
|
||||||
Float4::new(a2[1].0, a2[1].1, a2[1].2, 0.0),
|
Vec4::new(a2[1].0, a2[1].1, a2[1].2, 0.0),
|
||||||
];
|
];
|
||||||
let a3 = [
|
let a3 = [
|
||||||
Float4::new(a3[0].0, a3[0].1, a3[0].2, 0.0),
|
Vec4::new(a3[0].0, a3[0].1, a3[0].2, 0.0),
|
||||||
Float4::new(a3[1].0, a3[1].1, a3[1].2, 0.0),
|
Vec4::new(a3[1].0, a3[1].1, a3[1].2, 0.0),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Do interpolation.
|
// Do interpolation.
|
||||||
|
@ -117,16 +117,14 @@ fn small_rgb_to_spectrum_p4(
|
||||||
|
|
||||||
// Evaluate the spectral function and return the result.
|
// Evaluate the spectral function and return the result.
|
||||||
if max_val <= table_mid_value {
|
if max_val <= table_mid_value {
|
||||||
rgb2spec_eval_4([c[0].get_0(), c[0].get_1(), c[0].get_2()], lambdas)
|
rgb2spec_eval_4([c[0].x(), c[0].y(), c[0].z()], lambdas) * (1.0 / table_mid_value) * max_val
|
||||||
* (1.0 / table_mid_value)
|
|
||||||
* max_val
|
|
||||||
} else if max_val < 1.0 {
|
} else if max_val < 1.0 {
|
||||||
let n = (max_val - table_mid_value) / (1.0 - table_mid_value);
|
let n = (max_val - table_mid_value) / (1.0 - table_mid_value);
|
||||||
let s0 = rgb2spec_eval_4([c[0].get_0(), c[0].get_1(), c[0].get_2()], lambdas);
|
let s0 = rgb2spec_eval_4([c[0].x(), c[0].y(), c[0].z()], lambdas);
|
||||||
let s1 = rgb2spec_eval_4([c[1].get_0(), c[1].get_1(), c[1].get_2()], lambdas);
|
let s1 = rgb2spec_eval_4([c[1].x(), c[1].y(), c[1].z()], lambdas);
|
||||||
(s0 * (1.0 - n)) + (s1 * n)
|
(s0 * (1.0 - n)) + (s1 * n)
|
||||||
} else {
|
} else {
|
||||||
rgb2spec_eval_4([c[1].get_0(), c[1].get_1(), c[1].get_2()], lambdas) * max_val
|
rgb2spec_eval_4([c[1].x(), c[1].y(), c[1].z()], lambdas) * max_val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,18 +132,22 @@ fn small_rgb_to_spectrum_p4(
|
||||||
// Coefficient -> eval functions
|
// Coefficient -> eval functions
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn rgb2spec_fma_4(a: Float4, b: Float4, c: Float4) -> Float4 {
|
fn rgb2spec_fma_4(a: Vec4, b: Vec4, c: Vec4) -> Vec4 {
|
||||||
a.fmadd(b, c)
|
(a * b) + c
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rgb2spec_eval_4(coeff: [f32; RGB2SPEC_N_COEFFS], lambda: Float4) -> Float4 {
|
fn rgb2spec_eval_4(coeff: [f32; RGB2SPEC_N_COEFFS], lambda: Vec4) -> Vec4 {
|
||||||
let co0 = Float4::splat(coeff[0]);
|
let co0 = Vec4::splat(coeff[0]);
|
||||||
let co1 = Float4::splat(coeff[1]);
|
let co1 = Vec4::splat(coeff[1]);
|
||||||
let co2 = Float4::splat(coeff[2]);
|
let co2 = Vec4::splat(coeff[2]);
|
||||||
|
|
||||||
let x = rgb2spec_fma_4(rgb2spec_fma_4(co0, lambda, co1), lambda, co2);
|
let x = rgb2spec_fma_4(rgb2spec_fma_4(co0, lambda, co1), lambda, co2);
|
||||||
|
|
||||||
let y = Float4::splat(1.0) / (rgb2spec_fma_4(x, x, Float4::splat(1.0))).sqrt();
|
let y = {
|
||||||
|
// TODO: replace this with a SIMD sqrt op.
|
||||||
|
let (x, y, z, w) = rgb2spec_fma_4(x, x, Vec4::splat(1.0)).into();
|
||||||
|
Vec4::new(x.sqrt(), y.sqrt(), z.sqrt(), w.sqrt()).reciprocal()
|
||||||
|
};
|
||||||
|
|
||||||
rgb2spec_fma_4(Float4::splat(0.5) * x, y, Float4::splat(0.5))
|
rgb2spec_fma_4(Vec4::splat(0.5) * x, y, Vec4::splat(0.5))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
|
||||||
use float4::Float4;
|
use glam::Vec4;
|
||||||
|
|
||||||
mod meng_spectra_tables;
|
mod meng_spectra_tables;
|
||||||
|
|
||||||
|
@ -174,9 +174,9 @@ pub fn spectrum_xyz_to_p(lambda: f32, xyz: (f32, f32, f32)) -> f32 {
|
||||||
///
|
///
|
||||||
/// Works on 4 wavelengths at once via SIMD.
|
/// Works on 4 wavelengths at once via SIMD.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn spectrum_xyz_to_p_4(lambdas: Float4, xyz: (f32, f32, f32)) -> Float4 {
|
pub fn spectrum_xyz_to_p_4(lambdas: Vec4, xyz: (f32, f32, f32)) -> Vec4 {
|
||||||
assert!(lambdas.h_min() >= SPECTRUM_SAMPLE_MIN);
|
assert!(lambdas.min_element() >= SPECTRUM_SAMPLE_MIN);
|
||||||
assert!(lambdas.h_max() <= SPECTRUM_SAMPLE_MAX);
|
assert!(lambdas.max_element() <= SPECTRUM_SAMPLE_MAX);
|
||||||
|
|
||||||
let inv_norm = xyz.0 + xyz.1 + xyz.2;
|
let inv_norm = xyz.0 + xyz.1 + xyz.2;
|
||||||
let norm = {
|
let norm = {
|
||||||
|
@ -184,7 +184,7 @@ pub fn spectrum_xyz_to_p_4(lambdas: Float4, xyz: (f32, f32, f32)) -> Float4 {
|
||||||
if norm < f32::MAX {
|
if norm < f32::MAX {
|
||||||
norm
|
norm
|
||||||
} else {
|
} else {
|
||||||
return Float4::splat(0.0);
|
return Vec4::splat(0.0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ pub fn spectrum_xyz_to_p_4(lambdas: Float4, xyz: (f32, f32, f32)) -> Float4 {
|
||||||
|| uv.1 < 0.0
|
|| uv.1 < 0.0
|
||||||
|| uv.1 >= SPECTRUM_GRID_HEIGHT as f32
|
|| uv.1 >= SPECTRUM_GRID_HEIGHT as f32
|
||||||
{
|
{
|
||||||
return Float4::splat(0.0);
|
return Vec4::splat(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let uvi = (uv.0 as i32, uv.1 as i32);
|
let uvi = (uv.0 as i32, uv.1 as i32);
|
||||||
|
@ -214,53 +214,48 @@ pub fn spectrum_xyz_to_p_4(lambdas: Float4, xyz: (f32, f32, f32)) -> Float4 {
|
||||||
|
|
||||||
// If the cell has no points, nothing we can do, so return 0.0
|
// If the cell has no points, nothing we can do, so return 0.0
|
||||||
if num == 0 {
|
if num == 0 {
|
||||||
return Float4::splat(0.0);
|
return Vec4::splat(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize lambda to spectrum table index range.
|
// Normalize lambda to spectrum table index range.
|
||||||
let sb: Float4 = (lambdas - Float4::splat(SPECTRUM_SAMPLE_MIN))
|
let sb: Vec4 = (lambdas - Vec4::splat(SPECTRUM_SAMPLE_MIN))
|
||||||
/ (SPECTRUM_SAMPLE_MAX - SPECTRUM_SAMPLE_MIN)
|
/ (SPECTRUM_SAMPLE_MAX - SPECTRUM_SAMPLE_MIN)
|
||||||
* (SPECTRUM_NUM_SAMPLES as f32 - 1.0);
|
* (SPECTRUM_NUM_SAMPLES as f32 - 1.0);
|
||||||
debug_assert!(sb.h_min() >= 0.0);
|
debug_assert!(sb.min_element() >= 0.0);
|
||||||
debug_assert!(sb.h_max() <= SPECTRUM_NUM_SAMPLES as f32);
|
debug_assert!(sb.max_element() <= SPECTRUM_NUM_SAMPLES as f32);
|
||||||
|
|
||||||
// Get the spectral values for the vertices of the grid cell.
|
// Get the spectral values for the vertices of the grid cell.
|
||||||
// TODO: use integer SIMD intrinsics to make this part faster.
|
// TODO: use integer SIMD intrinsics to make this part faster.
|
||||||
let mut p = [Float4::splat(0.0); 6];
|
let mut p = [Vec4::splat(0.0); 6];
|
||||||
let sb0: [i32; 4] = [
|
let sb0: [i32; 4] = [sb.x() as i32, sb.y() as i32, sb.z() as i32, sb.w() as i32];
|
||||||
sb.get_0() as i32,
|
|
||||||
sb.get_1() as i32,
|
|
||||||
sb.get_2() as i32,
|
|
||||||
sb.get_3() as i32,
|
|
||||||
];
|
|
||||||
assert!(sb0[0].max(sb0[1]).max(sb0[2].max(sb0[3])) < SPECTRUM_NUM_SAMPLES);
|
assert!(sb0[0].max(sb0[1]).max(sb0[2].max(sb0[3])) < SPECTRUM_NUM_SAMPLES);
|
||||||
let sb1: [i32; 4] = [
|
let sb1: [i32; 4] = [
|
||||||
(sb.get_0() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
(sb.x() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
||||||
(sb.get_1() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
(sb.y() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
||||||
(sb.get_2() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
(sb.z() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
||||||
(sb.get_3() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
(sb.w() as i32 + 1).min(SPECTRUM_NUM_SAMPLES - 1),
|
||||||
];
|
];
|
||||||
let sbf = sb - Float4::new(sb0[0] as f32, sb0[1] as f32, sb0[2] as f32, sb0[3] as f32);
|
let sbf = sb - Vec4::new(sb0[0] as f32, sb0[1] as f32, sb0[2] as f32, sb0[3] as f32);
|
||||||
for i in 0..(num as usize) {
|
for i in 0..(num as usize) {
|
||||||
debug_assert!(idx[i] >= 0);
|
debug_assert!(idx[i] >= 0);
|
||||||
let spectrum = &SPECTRUM_DATA_POINTS[idx[i] as usize].spectrum;
|
let spectrum = &SPECTRUM_DATA_POINTS[idx[i] as usize].spectrum;
|
||||||
let p0 = Float4::new(
|
let p0 = Vec4::new(
|
||||||
spectrum[sb0[0] as usize],
|
spectrum[sb0[0] as usize],
|
||||||
spectrum[sb0[1] as usize],
|
spectrum[sb0[1] as usize],
|
||||||
spectrum[sb0[2] as usize],
|
spectrum[sb0[2] as usize],
|
||||||
spectrum[sb0[3] as usize],
|
spectrum[sb0[3] as usize],
|
||||||
);
|
);
|
||||||
let p1 = Float4::new(
|
let p1 = Vec4::new(
|
||||||
spectrum[sb1[0] as usize],
|
spectrum[sb1[0] as usize],
|
||||||
spectrum[sb1[1] as usize],
|
spectrum[sb1[1] as usize],
|
||||||
spectrum[sb1[2] as usize],
|
spectrum[sb1[2] as usize],
|
||||||
spectrum[sb1[3] as usize],
|
spectrum[sb1[3] as usize],
|
||||||
);
|
);
|
||||||
p[i] = p0 * (Float4::splat(1.0) - sbf) + p1 * sbf;
|
p[i] = p0 * (Vec4::splat(1.0) - sbf) + p1 * sbf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linearly interpolate the spectral power of the cell vertices.
|
// Linearly interpolate the spectral power of the cell vertices.
|
||||||
let mut interpolated_p = Float4::splat(0.0);
|
let mut interpolated_p = Vec4::splat(0.0);
|
||||||
if inside {
|
if inside {
|
||||||
// Fast path for normal inner quads:
|
// Fast path for normal inner quads:
|
||||||
let uv2 = (uv.0 - uvi.0 as f32, uv.1 - uvi.1 as f32);
|
let uv2 = (uv.0 - uvi.0 as f32, uv.1 - uvi.1 as f32);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user