Got rid of indexing into Float4 and 3d vector elements.

This assures correct semantics for SIMD usage.
This commit is contained in:
Nathan Vegdahl 2016-07-30 19:36:54 -07:00
parent 378f69dd57
commit 7ef5846c89
16 changed files with 321 additions and 225 deletions

View File

@ -58,14 +58,14 @@ impl BBox {
// Creates a new BBox transformed into a different space. // Creates a new BBox transformed into a different space.
pub fn transformed(&self, xform: Matrix4x4) -> BBox { pub fn transformed(&self, xform: Matrix4x4) -> BBox {
// BBox corners // BBox corners
let vs = [Point::new(self.min[0], self.min[1], self.min[2]), let vs = [Point::new(self.min.x(), self.min.y(), self.min.z()),
Point::new(self.min[0], self.min[1], self.max[2]), Point::new(self.min.x(), self.min.y(), self.max.z()),
Point::new(self.min[0], self.max[1], self.min[2]), Point::new(self.min.x(), self.max.y(), self.min.z()),
Point::new(self.min[0], self.max[1], self.max[2]), Point::new(self.min.x(), self.max.y(), self.max.z()),
Point::new(self.max[0], self.min[1], self.min[2]), Point::new(self.max.x(), self.min.y(), self.min.z()),
Point::new(self.max[0], self.min[1], self.max[2]), Point::new(self.max.x(), self.min.y(), self.max.z()),
Point::new(self.max[0], self.max[1], self.min[2]), Point::new(self.max.x(), self.max.y(), self.min.z()),
Point::new(self.max[0], self.max[1], self.max[2])]; Point::new(self.max.x(), self.max.y(), self.max.z())];
// Transform BBox corners and make new bbox // Transform BBox corners and make new bbox
let mut b = BBox::new(); let mut b = BBox::new();
@ -79,9 +79,9 @@ impl BBox {
} }
pub fn surface_area(&self) -> f32 { pub fn surface_area(&self) -> f32 {
let x = self.max[0] - self.min[0]; let x = self.max.x() - self.min.x();
let y = self.max[1] - self.min[1]; let y = self.max.y() - self.min.y();
let z = self.max[2] - self.min[2]; let z = self.max.z() - self.min.z();
((x * y) + (y * z) + (z * x)) * 2.0 ((x * y) + (y * z) + (z * x)) * 2.0
} }

View File

@ -145,10 +145,10 @@ impl BVH {
let sah_divs = { let sah_divs = {
let mut sah_divs = [[0.0f32; SAH_BIN_COUNT - 1]; 3]; let mut sah_divs = [[0.0f32; SAH_BIN_COUNT - 1]; 3];
for d in 0..3 { for d in 0..3 {
let extent = bounds.max[d] - bounds.min[d]; let extent = bounds.max.get_n(d) - bounds.min.get_n(d);
for div in 0..(SAH_BIN_COUNT - 1) { for div in 0..(SAH_BIN_COUNT - 1) {
let part = extent * ((div + 1) as f32 / SAH_BIN_COUNT as f32); let part = extent * ((div + 1) as f32 / SAH_BIN_COUNT as f32);
sah_divs[d][div] = bounds.min[d] + part; sah_divs[d][div] = bounds.min.get_n(d) + part;
} }
} }
sah_divs sah_divs
@ -163,7 +163,7 @@ impl BVH {
for d in 0..3 { for d in 0..3 {
for div in 0..(SAH_BIN_COUNT - 1) { for div in 0..(SAH_BIN_COUNT - 1) {
if centroid[d] <= sah_divs[d][div] { if centroid.get_n(d) <= sah_divs[d][div] {
sah_bins[d][div].0 |= tb; sah_bins[d][div].0 |= tb;
sah_bins[d][div].2 += 1; sah_bins[d][div].2 += 1;
} else { } else {
@ -203,7 +203,7 @@ impl BVH {
// Partition // Partition
let mut split_i = partition(&mut objects[..], |obj| { let mut split_i = partition(&mut objects[..], |obj| {
let tb = lerp_slice(bounder(obj), 0.5); let tb = lerp_slice(bounder(obj), 0.5);
let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5; let centroid = (tb.min.get_n(split_axis) + tb.max.get_n(split_axis)) * 0.5;
centroid < div centroid < div
}); });
if split_i < 1 { if split_i < 1 {
@ -219,7 +219,7 @@ impl BVH {
let mut axis = 0; let mut axis = 0;
let mut largest = std::f32::NEG_INFINITY; let mut largest = std::f32::NEG_INFINITY;
for i in 0..3 { for i in 0..3 {
let extent = bounds.max[i] - bounds.min[i]; let extent = bounds.max.get_n(i) - bounds.min.get_n(i);
if extent > largest { if extent > largest {
largest = extent; largest = extent;
axis = i; axis = i;
@ -234,8 +234,10 @@ impl BVH {
&|a, b| { &|a, b| {
let tb_a = lerp_slice(bounder(a), 0.5); let tb_a = lerp_slice(bounder(a), 0.5);
let tb_b = lerp_slice(bounder(b), 0.5); let tb_b = lerp_slice(bounder(b), 0.5);
let centroid_a = (tb_a.min[split_axis] + tb_a.max[split_axis]) * 0.5; let centroid_a = (tb_a.min.get_n(split_axis) + tb_a.max.get_n(split_axis)) *
let centroid_b = (tb_b.min[split_axis] + tb_b.max[split_axis]) * 0.5; 0.5;
let centroid_b = (tb_b.min.get_n(split_axis) + tb_b.max.get_n(split_axis)) *
0.5;
if centroid_a < centroid_b { if centroid_a < centroid_b {
Ordering::Less Ordering::Less
@ -307,7 +309,7 @@ impl BVH {
i_stack[stack_ptr + 1] = second_child_index; i_stack[stack_ptr + 1] = second_child_index;
ray_i_stack[stack_ptr] = part; ray_i_stack[stack_ptr] = part;
ray_i_stack[stack_ptr + 1] = part; ray_i_stack[stack_ptr + 1] = part;
if rays[0].dir_inv[split_axis as usize].is_sign_positive() { if rays[0].dir_inv.get_n(split_axis as usize).is_sign_positive() {
i_stack.swap(stack_ptr, stack_ptr + 1); i_stack.swap(stack_ptr, stack_ptr + 1);
} }
stack_ptr += 1; stack_ptr += 1;

View File

@ -70,8 +70,8 @@ impl Camera {
}; };
// Ray direction // Ray direction
let dir = Vector::new((x * tfov) - (orig[0] / focus_distance), let dir = Vector::new((x * tfov) - (orig.x() / focus_distance),
(y * tfov) - (orig[1] / focus_distance), (y * tfov) - (orig.y() / focus_distance),
1.0) 1.0)
.normalized(); .normalized();

View File

@ -52,7 +52,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::new(0.0, 0.0, 0.0, 0.0), e: Float4::splat(0.0),
hero_wavelength: wavelength, hero_wavelength: wavelength,
} }
} }
@ -60,7 +60,7 @@ 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::new(value, value, value, value), e: Float4::splat(value),
hero_wavelength: wavelength, hero_wavelength: wavelength,
} }
} }
@ -174,10 +174,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[0]); let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e.get_0());
let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e[1]); let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e.get_1());
let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e[2]); let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e.get_2());
let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e[3]); let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e.get_3());
(xyz0 + xyz1 + xyz2 + xyz3) * 0.75 (xyz0 + xyz1 + xyz2 + xyz3) * 0.75
} }

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div}; use std::ops::{Add, Sub, Mul, Div};
use std::cmp::PartialEq; use std::cmp::PartialEq;
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
@ -140,11 +140,25 @@ impl Float4 {
}) })
} }
/// Set the nth element to the given value.
#[inline]
pub fn set_n(&mut self, n: usize, v: f32) {
match n {
0 => self.set_0(v),
1 => self.set_1(v),
2 => self.set_2(v),
3 => self.set_3(v),
_ => panic!("Attempted to set element of Float4 outside of bounds."),
}
}
/// Set the 0th element to the given value. /// Set the 0th element to the given value.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_0(&mut self, n: f32) { pub fn set_0(&mut self, n: f32) {
self.data = self.data.replace(0, n); self.data = self.data.replace(0, n);
} }
#[inline(always)]
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
pub fn set_0(&mut self, n: f32) { pub fn set_0(&mut self, n: f32) {
unsafe { unsafe {
@ -154,10 +168,12 @@ impl Float4 {
/// Set the 1th element to the given value. /// Set the 1th element to the given value.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_1(&mut self, n: f32) { pub fn set_1(&mut self, n: f32) {
self.data = self.data.replace(1, n); self.data = self.data.replace(1, n);
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_1(&mut self, n: f32) { pub fn set_1(&mut self, n: f32) {
unsafe { unsafe {
*self.data.get_unchecked_mut(1) = n; *self.data.get_unchecked_mut(1) = n;
@ -166,10 +182,12 @@ impl Float4 {
/// Set the 2th element to the given value. /// Set the 2th element to the given value.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_2(&mut self, n: f32) { pub fn set_2(&mut self, n: f32) {
self.data = self.data.replace(2, n); self.data = self.data.replace(2, n);
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_2(&mut self, n: f32) { pub fn set_2(&mut self, n: f32) {
unsafe { unsafe {
*self.data.get_unchecked_mut(2) = n; *self.data.get_unchecked_mut(2) = n;
@ -178,92 +196,80 @@ impl Float4 {
/// Set the 3th element to the given value. /// Set the 3th element to the given value.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_3(&mut self, n: f32) { pub fn set_3(&mut self, n: f32) {
self.data = self.data.replace(3, n); self.data = self.data.replace(3, n);
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_3(&mut self, n: f32) { pub fn set_3(&mut self, n: f32) {
unsafe { unsafe {
*self.data.get_unchecked_mut(3) = n; *self.data.get_unchecked_mut(3) = n;
} }
} }
/// Returns the value of the nth element.
#[inline]
pub fn get_n(&self, n: usize) -> f32 {
match n {
0 => self.get_0(),
1 => self.get_1(),
2 => self.get_2(),
3 => self.get_3(),
_ => panic!("Attempted to access element of Float4 outside of bounds."),
}
}
/// Returns the value of the 0th element. /// Returns the value of the 0th element.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_0(&self) -> f32 { pub fn get_0(&self) -> f32 {
self.data.extract(0) self.data.extract(0)
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_0(&self) -> f32 { pub fn get_0(&self) -> f32 {
unsafe { *self.data.get_unchecked(0) } unsafe { *self.data.get_unchecked(0) }
} }
/// Returns the value of the 1th element. /// Returns the value of the 1th element.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_1(&self) -> f32 { pub fn get_1(&self) -> f32 {
self.data.extract(1) self.data.extract(1)
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_1(&self) -> f32 { pub fn get_1(&self) -> f32 {
unsafe { *self.data.get_unchecked(1) } unsafe { *self.data.get_unchecked(1) }
} }
/// Returns the value of the 2th element. /// Returns the value of the 2th element.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_2(&self) -> f32 { pub fn get_2(&self) -> f32 {
self.data.extract(2) self.data.extract(2)
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_2(&self) -> f32 { pub fn get_2(&self) -> f32 {
unsafe { *self.data.get_unchecked(2) } unsafe { *self.data.get_unchecked(2) }
} }
/// Returns the value of the 3th element. /// Returns the value of the 3th element.
#[cfg(feature = "simd_perf")] #[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_3(&self) -> f32 { pub fn get_3(&self) -> f32 {
self.data.extract(3) self.data.extract(3)
} }
#[cfg(not(feature = "simd_perf"))] #[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_3(&self) -> f32 { pub fn get_3(&self) -> f32 {
unsafe { *self.data.get_unchecked(3) } unsafe { *self.data.get_unchecked(3) }
} }
} }
impl Index<usize> for Float4 {
type Output = f32;
#[cfg(feature = "simd_perf")]
fn index(&self, index: usize) -> &f32 {
// TODO: this might not be correct! It works, but need to make sure
// to do this in a way with proper defined behavior.
use std::mem::transmute;
let vs: &[f32; 4] = unsafe { transmute(&self.data) };
&vs[index]
}
#[cfg(not(feature = "simd_perf"))]
fn index(&self, index: usize) -> &f32 {
&self.data[index]
}
}
impl IndexMut<usize> for Float4 {
#[cfg(feature = "simd_perf")]
fn index_mut(&mut self, index: usize) -> &mut f32 {
// TODO: this might not be correct! It works, but need to make sure
// to do this in a way with proper defined behavior.
use std::mem::transmute;
let vs: &mut [f32; 4] = unsafe { transmute(&mut self.data) };
&mut vs[index]
}
#[cfg(not(feature = "simd_perf"))]
fn index_mut(&mut self, index: usize) -> &mut f32 {
&mut self.data[index]
}
}
impl PartialEq for Float4 { impl PartialEq for Float4 {
fn eq(&self, other: &Float4) -> bool { fn eq(&self, other: &Float4) -> bool {
self.get_0() == other.get_0() && self.get_1() == other.get_1() && self.get_0() == other.get_0() && self.get_1() == other.get_1() &&
@ -389,27 +395,51 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn index() { fn get() {
let f = Float4::new(1.0, 2.0, 3.0, 4.0); let f = Float4::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(f[0], 1.0); assert_eq!(f.get_0(), 1.0);
assert_eq!(f[1], 2.0); assert_eq!(f.get_1(), 2.0);
assert_eq!(f[2], 3.0); assert_eq!(f.get_2(), 3.0);
assert_eq!(f[3], 4.0); assert_eq!(f.get_3(), 4.0);
} }
#[test] #[test]
fn index_mut() { fn get_n() {
let mut f = Float4::new(1.0, 2.0, 3.0, 4.0); let f = Float4::new(1.0, 2.0, 3.0, 4.0);
f[0] = 5.0;
f[1] = 6.0;
f[2] = 7.0;
f[3] = 8.0;
assert_eq!(f[0], 5.0); assert_eq!(f.get_n(0), 1.0);
assert_eq!(f[1], 6.0); assert_eq!(f.get_n(1), 2.0);
assert_eq!(f[2], 7.0); assert_eq!(f.get_n(2), 3.0);
assert_eq!(f[3], 8.0); assert_eq!(f.get_n(3), 4.0);
}
#[test]
fn set() {
let mut f = Float4::new(1.0, 2.0, 3.0, 4.0);
f.set_0(5.0);
f.set_1(6.0);
f.set_2(7.0);
f.set_3(8.0);
assert_eq!(f.get_0(), 5.0);
assert_eq!(f.get_1(), 6.0);
assert_eq!(f.get_2(), 7.0);
assert_eq!(f.get_3(), 8.0);
}
#[test]
fn set_n() {
let mut f = Float4::new(1.0, 2.0, 3.0, 4.0);
f.set_n(0, 5.0);
f.set_n(1, 6.0);
f.set_n(2, 7.0);
f.set_n(3, 8.0);
assert_eq!(f.get_0(), 5.0);
assert_eq!(f.get_1(), 6.0);
assert_eq!(f.get_2(), 7.0);
assert_eq!(f.get_3(), 8.0);
} }
#[test] #[test]

View File

@ -79,11 +79,15 @@ impl LightSource for RectangleLight {
// Project shadow_vec back onto the light's surface // Project shadow_vec back onto the light's surface
let arr_local = arr * *space; let arr_local = arr * *space;
let shadow_vec_local = shadow_vec * *space; let shadow_vec_local = shadow_vec * *space;
let shadow_vec_local = shadow_vec_local * (-arr_local[2] / shadow_vec_local[2]); let shadow_vec_local = shadow_vec_local * (-arr_local.z() / shadow_vec_local.z());
let mut sample_point_local = arr_local + shadow_vec_local; let mut sample_point_local = arr_local + shadow_vec_local;
sample_point_local[0] = sample_point_local[0].max(dim.0 * -0.5).min(dim.0 * 0.5); {
sample_point_local[1] = sample_point_local[1].max(dim.1 * -0.5).min(dim.1 * 0.5); let x = sample_point_local.x().max(dim.0 * -0.5).min(dim.0 * 0.5);
sample_point_local[2] = 0.0; let y = sample_point_local.y().max(dim.1 * -0.5).min(dim.1 * 0.5);
sample_point_local.set_x(x);
sample_point_local.set_y(y);
sample_point_local.set_z(0.0);
}
let sample_point = sample_point_local * space_inv; let sample_point = sample_point_local * space_inv;
let shadow_vec = sample_point - arr; let shadow_vec = sample_point - arr;

View File

@ -69,7 +69,7 @@ impl LightSource for SphereLight {
// Sample the cone subtended by the sphere and calculate // Sample the cone subtended by the sphere and calculate
// useful data from that. // useful data from that.
let sample = uniform_sample_cone(u, v, cos_theta_max).normalized(); let sample = uniform_sample_cone(u, v, cos_theta_max).normalized();
let cos_theta: f64 = sample[2] as f64; let cos_theta: f64 = sample.z() as f64;
let cos_theta2: f64 = cos_theta * cos_theta; let cos_theta2: f64 = cos_theta * cos_theta;
let sin_theta2: f64 = (1.0 - cos_theta2).max(0.0); let sin_theta2: f64 = (1.0 - cos_theta2).max(0.0);
let sin_theta: f64 = sin_theta2.sqrt(); let sin_theta: f64 = sin_theta2.sqrt();
@ -90,7 +90,7 @@ impl LightSource for SphereLight {
(d - (cos_a * radius)) as f32); (d - (cos_a * radius)) as f32);
// Calculate the final values and return everything. // Calculate the final values and return everything.
let shadow_vec = (x * sample[0]) + (y * sample[1]) + (z * sample[2]); let shadow_vec = (x * sample.x()) + (y * sample.y()) + (z * sample.z());
let pdf = uniform_sample_cone_pdf(cos_theta_max); let pdf = uniform_sample_cone_pdf(cos_theta_max);
let spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength); let spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength);
return (spectral_sample, shadow_vec, pdf as f32); return (spectral_sample, shadow_vec, pdf as f32);

View File

@ -59,9 +59,9 @@ impl Matrix4x4 {
pub fn from_location(loc: Point) -> Matrix4x4 { pub fn from_location(loc: Point) -> Matrix4x4 {
Matrix4x4 { Matrix4x4 {
values: [Float4::new(1.0, 0.0, 0.0, loc[0]), values: [Float4::new(1.0, 0.0, 0.0, loc.x()),
Float4::new(0.0, 1.0, 0.0, loc[1]), Float4::new(0.0, 1.0, 0.0, loc.y()),
Float4::new(0.0, 0.0, 1.0, loc[2]), Float4::new(0.0, 0.0, 1.0, loc.z()),
Float4::new(0.0, 0.0, 0.0, 1.0)], Float4::new(0.0, 0.0, 0.0, 1.0)],
} }
} }
@ -79,8 +79,8 @@ impl Matrix4x4 {
// http://floating-point-gui.de/errors/comparison/ // http://floating-point-gui.de/errors/comparison/
// It might be worth breaking this out into a separate funcion, // It might be worth breaking this out into a separate funcion,
// but I'm not entirely sure where to put it. // but I'm not entirely sure where to put it.
let a = self[y][x]; let a = self[y].get_n(x);
let b = other[y][x]; let b = other[y].get_n(x);
let aabs = a.abs(); let aabs = a.abs();
let babs = b.abs(); let babs = b.abs();
let diff = (a - b).abs(); let diff = (a - b).abs();
@ -102,10 +102,22 @@ impl Matrix4x4 {
pub fn transposed(&self) -> Matrix4x4 { pub fn transposed(&self) -> Matrix4x4 {
Matrix4x4 { Matrix4x4 {
values: { values: {
[Float4::new(self[0][0], self[1][0], self[2][0], self[3][0]), [Float4::new(self[0].get_0(),
Float4::new(self[0][1], self[1][1], self[2][1], self[3][1]), self[1].get_0(),
Float4::new(self[0][2], self[1][2], self[2][2], self[3][2]), self[2].get_0(),
Float4::new(self[0][3], self[1][3], self[2][3], self[3][3])] self[3].get_0()),
Float4::new(self[0].get_1(),
self[1].get_1(),
self[2].get_1(),
self[3].get_1()),
Float4::new(self[0].get_2(),
self[1].get_2(),
self[2].get_2(),
self[3].get_2()),
Float4::new(self[0].get_3(),
self[1].get_3(),
self[2].get_3(),
self[3].get_3())]
}, },
} }
} }
@ -113,19 +125,19 @@ impl Matrix4x4 {
/// Returns the inverse of the Matrix /// Returns the inverse of the Matrix
pub fn inverse(&self) -> Matrix4x4 { pub fn inverse(&self) -> Matrix4x4 {
let s0 = (self[0][0] * self[1][1]) - (self[1][0] * self[0][1]); let s0 = (self[0].get_0() * self[1].get_1()) - (self[1].get_0() * self[0].get_1());
let s1 = (self[0][0] * self[1][2]) - (self[1][0] * self[0][2]); let s1 = (self[0].get_0() * self[1].get_2()) - (self[1].get_0() * self[0].get_2());
let s2 = (self[0][0] * self[1][3]) - (self[1][0] * self[0][3]); let s2 = (self[0].get_0() * self[1].get_3()) - (self[1].get_0() * self[0].get_3());
let s3 = (self[0][1] * self[1][2]) - (self[1][1] * self[0][2]); let s3 = (self[0].get_1() * self[1].get_2()) - (self[1].get_1() * self[0].get_2());
let s4 = (self[0][1] * self[1][3]) - (self[1][1] * self[0][3]); let s4 = (self[0].get_1() * self[1].get_3()) - (self[1].get_1() * self[0].get_3());
let s5 = (self[0][2] * self[1][3]) - (self[1][2] * self[0][3]); let s5 = (self[0].get_2() * self[1].get_3()) - (self[1].get_2() * self[0].get_3());
let c5 = (self[2][2] * self[3][3]) - (self[3][2] * self[2][3]); let c5 = (self[2].get_2() * self[3].get_3()) - (self[3].get_2() * self[2].get_3());
let c4 = (self[2][1] * self[3][3]) - (self[3][1] * self[2][3]); let c4 = (self[2].get_1() * self[3].get_3()) - (self[3].get_1() * self[2].get_3());
let c3 = (self[2][1] * self[3][2]) - (self[3][1] * self[2][2]); let c3 = (self[2].get_1() * self[3].get_2()) - (self[3].get_1() * self[2].get_2());
let c2 = (self[2][0] * self[3][3]) - (self[3][0] * self[2][3]); let c2 = (self[2].get_0() * self[3].get_3()) - (self[3].get_0() * self[2].get_3());
let c1 = (self[2][0] * self[3][2]) - (self[3][0] * self[2][2]); let c1 = (self[2].get_0() * self[3].get_2()) - (self[3].get_0() * self[2].get_2());
let c0 = (self[2][0] * self[3][1]) - (self[3][0] * self[2][1]); let c0 = (self[2].get_0() * self[3].get_1()) - (self[3].get_0() * self[2].get_1());
// TODO: handle 0.0 determinant // TODO: handle 0.0 determinant
let det = (s0 * c5) - (s1 * c4) + (s2 * c3) + (s3 * c2) - (s4 * c1) + (s5 * c0); let det = (s0 * c5) - (s1 * c4) + (s2 * c3) + (s3 * c2) - (s4 * c1) + (s5 * c0);
@ -133,25 +145,41 @@ impl Matrix4x4 {
Matrix4x4 { Matrix4x4 {
values: { values: {
[Float4::new(((self[1][1] * c5) - (self[1][2] * c4) + (self[1][3] * c3)) * invdet, [Float4::new(((self[1].get_1() * c5) - (self[1].get_2() * c4) +
((-self[0][1] * c5) + (self[0][2] * c4) - (self[0][3] * c3)) * invdet, (self[1].get_3() * c3)) * invdet,
((self[3][1] * s5) - (self[3][2] * s4) + (self[3][3] * s3)) * invdet, ((-self[0].get_1() * c5) + (self[0].get_2() * c4) -
((-self[2][1] * s5) + (self[2][2] * s4) - (self[2][3] * s3)) * invdet), (self[0].get_3() * c3)) * invdet,
((self[3].get_1() * s5) - (self[3].get_2() * s4) +
(self[3].get_3() * s3)) * invdet,
((-self[2].get_1() * s5) + (self[2].get_2() * s4) -
(self[2].get_3() * s3)) * invdet),
Float4::new(((-self[1][0] * c5) + (self[1][2] * c2) - (self[1][3] * c1)) * invdet, Float4::new(((-self[1].get_0() * c5) + (self[1].get_2() * c2) -
((self[0][0] * c5) - (self[0][2] * c2) + (self[0][3] * c1)) * invdet, (self[1].get_3() * c1)) * invdet,
((-self[3][0] * s5) + (self[3][2] * s2) - (self[3][3] * s1)) * invdet, ((self[0].get_0() * c5) - (self[0].get_2() * c2) +
((self[2][0] * s5) - (self[2][2] * s2) + (self[2][3] * s1)) * invdet), (self[0].get_3() * c1)) * invdet,
((-self[3].get_0() * s5) + (self[3].get_2() * s2) -
(self[3].get_3() * s1)) * invdet,
((self[2].get_0() * s5) - (self[2].get_2() * s2) +
(self[2].get_3() * s1)) * invdet),
Float4::new(((self[1][0] * c4) - (self[1][1] * c2) + (self[1][3] * c0)) * invdet, Float4::new(((self[1].get_0() * c4) - (self[1].get_1() * c2) +
((-self[0][0] * c4) + (self[0][1] * c2) - (self[0][3] * c0)) * invdet, (self[1].get_3() * c0)) * invdet,
((self[3][0] * s4) - (self[3][1] * s2) + (self[3][3] * s0)) * invdet, ((-self[0].get_0() * c4) + (self[0].get_1() * c2) -
((-self[2][0] * s4) + (self[2][1] * s2) - (self[2][3] * s0)) * invdet), (self[0].get_3() * c0)) * invdet,
((self[3].get_0() * s4) - (self[3].get_1() * s2) +
(self[3].get_3() * s0)) * invdet,
((-self[2].get_0() * s4) + (self[2].get_1() * s2) -
(self[2].get_3() * s0)) * invdet),
Float4::new(((-self[1][0] * c3) + (self[1][1] * c1) - (self[1][2] * c0)) * invdet, Float4::new(((-self[1].get_0() * c3) + (self[1].get_1() * c1) -
((self[0][0] * c3) - (self[0][1] * c1) + (self[0][2] * c0)) * invdet, (self[1].get_2() * c0)) * invdet,
((-self[3][0] * s3) + (self[3][1] * s1) - (self[3][2] * s0)) * invdet, ((self[0].get_0() * c3) - (self[0].get_1() * c1) +
((self[2][0] * s3) - (self[2][1] * s1) + (self[2][2] * s0)) * invdet)] (self[0].get_2() * c0)) * invdet,
((-self[3].get_0() * s3) + (self[3].get_1() * s1) -
(self[3].get_2() * s0)) * invdet,
((self[2].get_0() * s3) - (self[2].get_1() * s1) +
(self[2].get_2() * s0)) * invdet)]
}, },
} }
} }
@ -180,7 +208,7 @@ impl PartialEq for Matrix4x4 {
for y in 0..4 { for y in 0..4 {
for x in 0..4 { for x in 0..4 {
result = result && (self[y][x] == other[y][x]); result = result && (self[y].get_n(x) == other[y].get_n(x));
} }
} }
@ -224,25 +252,10 @@ 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; let alpha_minus = 1.0 - alpha;
Matrix4x4 { Matrix4x4 {
values: [Float4::new((self[0][0] * alpha_minus) + (other[0][0] * alpha), values: [(self[0] * alpha_minus) + (other[0] * alpha),
(self[0][1] * alpha_minus) + (other[0][1] * alpha), (self[1] * alpha_minus) + (other[1] * alpha),
(self[0][2] * alpha_minus) + (other[0][2] * alpha), (self[2] * alpha_minus) + (other[2] * alpha),
(self[0][3] * alpha_minus) + (other[0][3] * alpha)), (self[3] * alpha_minus) + (other[3] * alpha)],
Float4::new((self[1][0] * alpha_minus) + (other[1][0] * alpha),
(self[1][1] * alpha_minus) + (other[1][1] * alpha),
(self[1][2] * alpha_minus) + (other[1][2] * alpha),
(self[1][3] * alpha_minus) + (other[1][3] * alpha)),
Float4::new((self[2][0] * alpha_minus) + (other[2][0] * alpha),
(self[2][1] * alpha_minus) + (other[2][1] * alpha),
(self[2][2] * alpha_minus) + (other[2][2] * alpha),
(self[2][3] * alpha_minus) + (other[2][3] * alpha)),
Float4::new((self[3][0] * alpha_minus) + (other[3][0] * alpha),
(self[3][1] * alpha_minus) + (other[3][1] * alpha),
(self[3][2] * alpha_minus) + (other[3][2] * alpha),
(self[3][3] * alpha_minus) + (other[3][3] * alpha))],
} }
} }
} }

View File

@ -134,12 +134,12 @@ pub fn log2_64(value: u64) -> u64 {
/// Creates a coordinate system from a single vector. /// Creates a coordinate system from a single vector.
pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) { pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) {
let v2 = if v[0].abs() > v[1].abs() { let v2 = if v.x().abs() > v.y().abs() {
let invlen = 1.0 / ((v[0] * v[0]) + (v[2] * v[2])).sqrt(); let invlen = 1.0 / ((v.x() * v.x()) + (v.z() * v.z())).sqrt();
Vector::new(-v[2] * invlen, 0.0, v[0] * invlen) Vector::new(-v.z() * invlen, 0.0, v.x() * invlen)
} else { } else {
let invlen = 1.0 / ((v[1] * v[1]) + (v[2] * v[2])).sqrt(); let invlen = 1.0 / ((v.y() * v.y()) + (v.z() * v.z())).sqrt();
Vector::new(0.0, v[2] * invlen, -v[1] * invlen) Vector::new(0.0, v.z() * invlen, -v.y() * invlen)
}; };
let v3 = cross(v, v2); let v3 = cross(v, v2);
@ -164,7 +164,7 @@ pub fn zup_to_vec(from: Vector, toz: Vector) -> Vector {
// Use simple linear algebra to convert the "from" // Use simple linear algebra to convert the "from"
// vector to a space composed of tox, toy, and toz // vector to a space composed of tox, toy, and toz
// as the x, y, and z axes. // as the x, y, and z axes.
(tox * from[0]) + (toy * from[1]) + (toz * from[2]) (tox * from.x()) + (toy * from.y()) + (toz * from.z())
} }
/// The logit function, scaled to approximate the probit function. /// The logit function, scaled to approximate the probit function.

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div, Neg}; use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::PartialEq; use std::cmp::PartialEq;
use lerp::Lerp; use lerp::Lerp;
@ -33,26 +33,40 @@ impl Normal {
} }
pub fn into_vector(self) -> Vector { pub fn into_vector(self) -> Vector {
Vector::new(self.co[0], self.co[1], self.co[2]) Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2())
}
pub fn get_n(&self, n: usize) -> f32 {
match n {
0 => self.x(),
1 => self.y(),
2 => self.z(),
_ => panic!("Attempt to access dimension beyond z."),
} }
} }
pub fn x(&self) -> f32 {
impl Index<usize> for Normal { self.co.get_0()
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
}
} }
impl IndexMut<usize> for Normal { pub fn y(&self) -> f32 {
fn index_mut(&mut self, index: usize) -> &mut f32 { self.co.get_1()
debug_assert!(index < 3); }
&mut self.co[index] pub fn z(&self) -> f32 {
self.co.get_2()
}
pub fn set_x(&mut self, x: f32) {
self.co.set_0(x);
}
pub fn set_y(&mut self, y: f32) {
self.co.set_1(y);
}
pub fn set_z(&mut self, z: f32) {
self.co.set_2(z);
} }
} }
@ -96,9 +110,9 @@ impl Mul<Matrix4x4> for Normal {
fn mul(self, other: Matrix4x4) -> Normal { fn mul(self, other: Matrix4x4) -> Normal {
let mat = other.inverse().transposed(); let mat = other.inverse().transposed();
Normal { Normal {
co: Float4::new((self[0] * mat[0][0]) + (self[1] * mat[0][1]) + (self[2] * mat[0][2]), co: Float4::new((self.co * mat[0]).h_sum(),
(self[0] * mat[1][0]) + (self[1] * mat[1][1]) + (self[2] * mat[1][2]), (self.co * mat[1]).h_sum(),
(self[0] * mat[2][0]) + (self[1] * mat[2][1]) + (self[2] * mat[2][2]), (self.co * mat[2]).h_sum(),
0.0), 0.0),
} }
} }
@ -140,9 +154,12 @@ impl DotProduct for Normal {
impl CrossProduct for Normal { impl CrossProduct for Normal {
fn cross(self, other: Normal) -> Normal { fn cross(self, other: Normal) -> Normal {
Normal { Normal {
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]), co: Float4::new((self.co.get_1() * other.co.get_2()) -
(self[2] * other[0]) - (self[0] * other[2]), (self.co.get_2() * other.co.get_1()),
(self[0] * other[1]) - (self[1] * other[0]), (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), 0.0),
} }
} }
@ -231,9 +248,9 @@ mod tests {
let n1 = Normal::new(1.0, 2.0, 3.0); let n1 = Normal::new(1.0, 2.0, 3.0);
let n2 = Normal::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732); let n2 = Normal::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
let n3 = n1.normalized(); let n3 = n1.normalized();
assert!((n3[0] - n2[0]).abs() < 0.000001); assert!((n3.x() - n2.x()).abs() < 0.000001);
assert!((n3[1] - n2[1]).abs() < 0.000001); assert!((n3.y() - n2.y()).abs() < 0.000001);
assert!((n3[2] - n2[2]).abs() < 0.000001); assert!((n3.z() - n2.z()).abs() < 0.000001);
} }
#[test] #[test]

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul}; use std::ops::{Add, Sub, Mul};
use std::cmp::PartialEq; use std::cmp::PartialEq;
use lerp::Lerp; use lerp::Lerp;
@ -23,7 +23,7 @@ impl Point {
/// Returns the point in standardized coordinates, where the /// Returns the point in standardized coordinates, where the
/// fourth homogeneous component has been normalized to 1.0. /// fourth homogeneous component has been normalized to 1.0.
pub fn norm(&self) -> Point { pub fn norm(&self) -> Point {
Point { co: self.co / self.co[3] } Point { co: self.co / self.co.get_3() }
} }
pub fn min(&self, other: Point) -> Point { pub fn min(&self, other: Point) -> Point {
@ -41,26 +41,40 @@ impl Point {
} }
pub fn into_vector(self) -> Vector { pub fn into_vector(self) -> Vector {
Vector::new(self[0], self[1], self[2]) Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2())
}
pub fn get_n(&self, n: usize) -> f32 {
match n {
0 => self.x(),
1 => self.y(),
2 => self.z(),
_ => panic!("Attempt to access dimension beyond z."),
} }
} }
pub fn x(&self) -> f32 {
impl Index<usize> for Point { self.co.get_0()
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
}
} }
impl IndexMut<usize> for Point { pub fn y(&self) -> f32 {
fn index_mut(&mut self, index: usize) -> &mut f32 { self.co.get_1()
debug_assert!(index < 3); }
&mut self.co[index] pub fn z(&self) -> f32 {
self.co.get_2()
}
pub fn set_x(&mut self, x: f32) {
self.co.set_0(x);
}
pub fn set_y(&mut self, y: f32) {
self.co.set_1(y);
}
pub fn set_z(&mut self, z: f32) {
self.co.set_2(z);
} }
} }
@ -130,7 +144,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[3] = 0.5; p1.co.set_3(0.5);
assert_eq!(p2, p1.norm()); assert_eq!(p2, p1.norm());
} }
@ -196,7 +210,7 @@ mod tests {
1.0, 1.0,
5.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[3] = 18.5; pm.co.set_3(18.5);
assert_eq!(p * m, pm); assert_eq!(p * m, pm);
} }

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div, Neg}; use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::PartialEq; use std::cmp::PartialEq;
use lerp::Lerp; use lerp::Lerp;
@ -33,26 +33,40 @@ impl Vector {
} }
pub fn into_normal(self) -> Normal { pub fn into_normal(self) -> Normal {
Normal::new(self.co[0], self.co[1], self.co[2]) Normal::new(self.x(), self.y(), self.z())
}
pub fn get_n(&self, n: usize) -> f32 {
match n {
0 => self.x(),
1 => self.y(),
2 => self.z(),
_ => panic!("Attempt to access dimension beyond z."),
} }
} }
pub fn x(&self) -> f32 {
impl Index<usize> for Vector { self.co.get_0()
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
}
} }
impl IndexMut<usize> for Vector { pub fn y(&self) -> f32 {
fn index_mut(&mut self, index: usize) -> &mut f32 { self.co.get_1()
debug_assert!(index < 3); }
&mut self.co[index] pub fn z(&self) -> f32 {
self.co.get_2()
}
pub fn set_x(&mut self, x: f32) {
self.co.set_0(x);
}
pub fn set_y(&mut self, y: f32) {
self.co.set_1(y);
}
pub fn set_z(&mut self, z: f32) {
self.co.set_2(z);
} }
} }
@ -140,9 +154,12 @@ impl DotProduct for Vector {
impl CrossProduct for Vector { impl CrossProduct for Vector {
fn cross(self, other: Vector) -> Vector { fn cross(self, other: Vector) -> Vector {
Vector { Vector {
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]), co: Float4::new((self.co.get_1() * other.co.get_2()) -
(self[2] * other[0]) - (self[0] * other[2]), (self.co.get_2() * other.co.get_1()),
(self[0] * other[1]) - (self[1] * other[0]), (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), 0.0),
} }
} }
@ -202,7 +219,7 @@ mod tests {
15.0, 15.0,
3.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[3] = 90.5; vm.co.set_3(90.5);
assert_eq!(v * m, vm); assert_eq!(v * m, vm);
} }
@ -255,9 +272,9 @@ mod tests {
let v1 = Vector::new(1.0, 2.0, 3.0); let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = Vector::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732); let v2 = Vector::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
let v3 = v1.normalized(); let v3 = v1.normalized();
assert!((v3[0] - v2[0]).abs() < 0.000001); assert!((v3.x() - v2.x()).abs() < 0.000001);
assert!((v3[1] - v2[1]).abs() < 0.000001); assert!((v3.y() - v2.y()).abs() < 0.000001);
assert!((v3[2] - v2[2]).abs() < 0.000001); assert!((v3.z() - v2.z()).abs() < 0.000001);
} }
#[test] #[test]

View File

@ -138,7 +138,6 @@ fn take_decimal_real(i: &[u8]) -> IResult<&[u8], &[u8]> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use nom::IResult;
use nom::IResult::*; use nom::IResult::*;
use super::take_decimal_real; use super::take_decimal_real;
use super::*; use super::*;

View File

@ -650,7 +650,7 @@ mod tests {
"#) "#)
.unwrap(); .unwrap();
let mut i = dt.iter_children_with_type("A"); let i = dt.iter_children_with_type("A");
assert_eq!(i.count(), 3); assert_eq!(i.count(), 3);
} }
@ -665,7 +665,7 @@ mod tests {
"#) "#)
.unwrap(); .unwrap();
let mut i = dt.iter_internal_children_with_type("A"); let i = dt.iter_internal_children_with_type("A");
assert_eq!(i.count(), 2); assert_eq!(i.count(), 2);
} }
@ -680,7 +680,7 @@ mod tests {
"#) "#)
.unwrap(); .unwrap();
let mut i = dt.iter_leaf_children_with_type("A"); let i = dt.iter_leaf_children_with_type("A");
assert_eq!(i.count(), 2); assert_eq!(i.count(), 2);
} }
} }

View File

@ -210,7 +210,7 @@ impl SurfaceClosure for LambertClosure {
// Generate a random ray direction in the hemisphere // Generate a random ray direction in the hemisphere
// of the surface. // of the surface.
let dir = cosine_sample_hemisphere(uv.0, uv.1); let dir = cosine_sample_hemisphere(uv.0, uv.1);
let pdf = dir[2] * INV_PI; let pdf = dir.z() * INV_PI;
let out = zup_to_vec(dir, nn); let out = zup_to_vec(dir, nn);
let filter = self.evaluate(inc, out, nor, wavelength); let filter = self.evaluate(inc, out, nor, wavelength);

View File

@ -154,15 +154,15 @@ impl<'a> TracerInner<'a> {
fn split_rays_by_direction(rays: &mut [AccelRay]) -> [&mut [AccelRay]; 8] { fn split_rays_by_direction(rays: &mut [AccelRay]) -> [&mut [AccelRay]; 8] {
// | | | | | | | | | // | | | | | | | | |
// s1 s2 s3 s4 s5 s6 s7 // s1 s2 s3 s4 s5 s6 s7
let s4 = partition(&mut rays[..], |r| r.dir_inv[0].is_sign_positive()); let s4 = partition(&mut rays[..], |r| r.dir_inv.x().is_sign_positive());
let s2 = partition(&mut rays[..s4], |r| r.dir_inv[1].is_sign_positive()); let s2 = partition(&mut rays[..s4], |r| r.dir_inv.y().is_sign_positive());
let s6 = s4 + partition(&mut rays[s4..], |r| r.dir_inv[1].is_sign_positive()); let s6 = s4 + partition(&mut rays[s4..], |r| r.dir_inv.y().is_sign_positive());
let s1 = partition(&mut rays[..s2], |r| r.dir_inv[2].is_sign_positive()); let s1 = partition(&mut rays[..s2], |r| r.dir_inv.z().is_sign_positive());
let s3 = s2 + partition(&mut rays[s2..s4], |r| r.dir_inv[2].is_sign_positive()); let s3 = s2 + partition(&mut rays[s2..s4], |r| r.dir_inv.z().is_sign_positive());
let s5 = s4 + partition(&mut rays[s4..s6], |r| r.dir_inv[2].is_sign_positive()); let s5 = s4 + partition(&mut rays[s4..s6], |r| r.dir_inv.z().is_sign_positive());
let s7 = s6 + partition(&mut rays[s6..], |r| r.dir_inv[2].is_sign_positive()); let s7 = s6 + partition(&mut rays[s6..], |r| r.dir_inv.z().is_sign_positive());
let (rest, rs7) = rays.split_at_mut(s7); let (rest, rs7) = rays.split_at_mut(s7);
let (rest, rs6) = rest.split_at_mut(s6); let (rest, rs6) = rest.split_at_mut(s6);