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.
pub fn transformed(&self, xform: Matrix4x4) -> BBox {
// BBox corners
let vs = [Point::new(self.min[0], self.min[1], self.min[2]),
Point::new(self.min[0], self.min[1], self.max[2]),
Point::new(self.min[0], self.max[1], self.min[2]),
Point::new(self.min[0], self.max[1], self.max[2]),
Point::new(self.max[0], self.min[1], self.min[2]),
Point::new(self.max[0], self.min[1], self.max[2]),
Point::new(self.max[0], self.max[1], self.min[2]),
Point::new(self.max[0], self.max[1], self.max[2])];
let vs = [Point::new(self.min.x(), self.min.y(), self.min.z()),
Point::new(self.min.x(), self.min.y(), self.max.z()),
Point::new(self.min.x(), self.max.y(), self.min.z()),
Point::new(self.min.x(), self.max.y(), self.max.z()),
Point::new(self.max.x(), self.min.y(), self.min.z()),
Point::new(self.max.x(), self.min.y(), self.max.z()),
Point::new(self.max.x(), self.max.y(), self.min.z()),
Point::new(self.max.x(), self.max.y(), self.max.z())];
// Transform BBox corners and make new bbox
let mut b = BBox::new();
@ -79,9 +79,9 @@ impl BBox {
}
pub fn surface_area(&self) -> f32 {
let x = self.max[0] - self.min[0];
let y = self.max[1] - self.min[1];
let z = self.max[2] - self.min[2];
let x = self.max.x() - self.min.x();
let y = self.max.y() - self.min.y();
let z = self.max.z() - self.min.z();
((x * y) + (y * z) + (z * x)) * 2.0
}

View File

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

View File

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

View File

@ -52,7 +52,7 @@ impl SpectralSample {
pub fn new(wavelength: f32) -> SpectralSample {
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
SpectralSample {
e: Float4::new(0.0, 0.0, 0.0, 0.0),
e: Float4::splat(0.0),
hero_wavelength: wavelength,
}
}
@ -60,7 +60,7 @@ impl SpectralSample {
pub fn from_value(value: f32, wavelength: f32) -> SpectralSample {
debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX);
SpectralSample {
e: Float4::new(value, value, value, value),
e: Float4::splat(value),
hero_wavelength: wavelength,
}
}
@ -174,10 +174,10 @@ impl XYZ {
}
pub fn from_spectral_sample(ss: &SpectralSample) -> XYZ {
let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e[0]);
let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e[1]);
let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e[2]);
let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e[3]);
let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e.get_0());
let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e.get_1());
let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e.get_2());
let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e.get_3());
(xyz0 + xyz1 + xyz2 + xyz3) * 0.75
}

View File

@ -1,6 +1,6 @@
#![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div};
use std::ops::{Add, Sub, Mul, Div};
use std::cmp::PartialEq;
#[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.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_0(&mut self, n: f32) {
self.data = self.data.replace(0, n);
}
#[inline(always)]
#[cfg(not(feature = "simd_perf"))]
pub fn set_0(&mut self, n: f32) {
unsafe {
@ -154,10 +168,12 @@ impl Float4 {
/// Set the 1th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_1(&mut self, n: f32) {
self.data = self.data.replace(1, n);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_1(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(1) = n;
@ -166,10 +182,12 @@ impl Float4 {
/// Set the 2th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_2(&mut self, n: f32) {
self.data = self.data.replace(2, n);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_2(&mut self, n: f32) {
unsafe {
*self.data.get_unchecked_mut(2) = n;
@ -178,92 +196,80 @@ impl Float4 {
/// Set the 3th element to the given value.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn set_3(&mut self, n: f32) {
self.data = self.data.replace(3, n);
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn set_3(&mut self, n: f32) {
unsafe {
*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.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_0(&self) -> f32 {
self.data.extract(0)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_0(&self) -> f32 {
unsafe { *self.data.get_unchecked(0) }
}
/// Returns the value of the 1th element.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_1(&self) -> f32 {
self.data.extract(1)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_1(&self) -> f32 {
unsafe { *self.data.get_unchecked(1) }
}
/// Returns the value of the 2th element.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_2(&self) -> f32 {
self.data.extract(2)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_2(&self) -> f32 {
unsafe { *self.data.get_unchecked(2) }
}
/// Returns the value of the 3th element.
#[cfg(feature = "simd_perf")]
#[inline(always)]
pub fn get_3(&self) -> f32 {
self.data.extract(3)
}
#[cfg(not(feature = "simd_perf"))]
#[inline(always)]
pub fn get_3(&self) -> f32 {
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 {
fn eq(&self, other: &Float4) -> bool {
self.get_0() == other.get_0() && self.get_1() == other.get_1() &&
@ -389,27 +395,51 @@ mod tests {
use super::*;
#[test]
fn index() {
fn get() {
let f = Float4::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(f[0], 1.0);
assert_eq!(f[1], 2.0);
assert_eq!(f[2], 3.0);
assert_eq!(f[3], 4.0);
assert_eq!(f.get_0(), 1.0);
assert_eq!(f.get_1(), 2.0);
assert_eq!(f.get_2(), 3.0);
assert_eq!(f.get_3(), 4.0);
}
#[test]
fn index_mut() {
let mut 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;
fn get_n() {
let f = Float4::new(1.0, 2.0, 3.0, 4.0);
assert_eq!(f[0], 5.0);
assert_eq!(f[1], 6.0);
assert_eq!(f[2], 7.0);
assert_eq!(f[3], 8.0);
assert_eq!(f.get_n(0), 1.0);
assert_eq!(f.get_n(1), 2.0);
assert_eq!(f.get_n(2), 3.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]

View File

@ -79,11 +79,15 @@ impl LightSource for RectangleLight {
// Project shadow_vec back onto the light's surface
let arr_local = arr * *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;
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);
sample_point_local[2] = 0.0;
{
let x = sample_point_local.x().max(dim.0 * -0.5).min(dim.0 * 0.5);
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 shadow_vec = sample_point - arr;

View File

@ -69,7 +69,7 @@ impl LightSource for SphereLight {
// Sample the cone subtended by the sphere and calculate
// useful data from that.
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 sin_theta2: f64 = (1.0 - cos_theta2).max(0.0);
let sin_theta: f64 = sin_theta2.sqrt();
@ -90,7 +90,7 @@ impl LightSource for SphereLight {
(d - (cos_a * radius)) as f32);
// 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 spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength);
return (spectral_sample, shadow_vec, pdf as f32);

View File

@ -59,9 +59,9 @@ impl Matrix4x4 {
pub fn from_location(loc: Point) -> Matrix4x4 {
Matrix4x4 {
values: [Float4::new(1.0, 0.0, 0.0, loc[0]),
Float4::new(0.0, 1.0, 0.0, loc[1]),
Float4::new(0.0, 0.0, 1.0, loc[2]),
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)],
}
}
@ -79,8 +79,8 @@ impl Matrix4x4 {
// 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][x];
let b = other[y][x];
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();
@ -102,10 +102,22 @@ impl Matrix4x4 {
pub fn transposed(&self) -> Matrix4x4 {
Matrix4x4 {
values: {
[Float4::new(self[0][0], self[1][0], self[2][0], self[3][0]),
Float4::new(self[0][1], self[1][1], self[2][1], self[3][1]),
Float4::new(self[0][2], self[1][2], self[2][2], self[3][2]),
Float4::new(self[0][3], self[1][3], self[2][3], self[3][3])]
[Float4::new(self[0].get_0(),
self[1].get_0(),
self[2].get_0(),
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
pub fn inverse(&self) -> Matrix4x4 {
let s0 = (self[0][0] * self[1][1]) - (self[1][0] * self[0][1]);
let s1 = (self[0][0] * self[1][2]) - (self[1][0] * self[0][2]);
let s2 = (self[0][0] * self[1][3]) - (self[1][0] * self[0][3]);
let s3 = (self[0][1] * self[1][2]) - (self[1][1] * self[0][2]);
let s4 = (self[0][1] * self[1][3]) - (self[1][1] * self[0][3]);
let s5 = (self[0][2] * self[1][3]) - (self[1][2] * self[0][3]);
let s0 = (self[0].get_0() * self[1].get_1()) - (self[1].get_0() * self[0].get_1());
let s1 = (self[0].get_0() * self[1].get_2()) - (self[1].get_0() * self[0].get_2());
let s2 = (self[0].get_0() * self[1].get_3()) - (self[1].get_0() * self[0].get_3());
let s3 = (self[0].get_1() * self[1].get_2()) - (self[1].get_1() * self[0].get_2());
let s4 = (self[0].get_1() * self[1].get_3()) - (self[1].get_1() * self[0].get_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 c4 = (self[2][1] * self[3][3]) - (self[3][1] * self[2][3]);
let c3 = (self[2][1] * self[3][2]) - (self[3][1] * self[2][2]);
let c2 = (self[2][0] * self[3][3]) - (self[3][0] * self[2][3]);
let c1 = (self[2][0] * self[3][2]) - (self[3][0] * self[2][2]);
let c0 = (self[2][0] * self[3][1]) - (self[3][0] * self[2][1]);
let c5 = (self[2].get_2() * self[3].get_3()) - (self[3].get_2() * self[2].get_3());
let c4 = (self[2].get_1() * self[3].get_3()) - (self[3].get_1() * self[2].get_3());
let c3 = (self[2].get_1() * self[3].get_2()) - (self[3].get_1() * self[2].get_2());
let c2 = (self[2].get_0() * self[3].get_3()) - (self[3].get_0() * self[2].get_3());
let c1 = (self[2].get_0() * self[3].get_2()) - (self[3].get_0() * self[2].get_2());
let c0 = (self[2].get_0() * self[3].get_1()) - (self[3].get_0() * self[2].get_1());
// TODO: handle 0.0 determinant
let det = (s0 * c5) - (s1 * c4) + (s2 * c3) + (s3 * c2) - (s4 * c1) + (s5 * c0);
@ -133,25 +145,41 @@ impl Matrix4x4 {
Matrix4x4 {
values: {
[Float4::new(((self[1][1] * c5) - (self[1][2] * c4) + (self[1][3] * c3)) * invdet,
((-self[0][1] * c5) + (self[0][2] * c4) - (self[0][3] * c3)) * invdet,
((self[3][1] * s5) - (self[3][2] * s4) + (self[3][3] * s3)) * invdet,
((-self[2][1] * s5) + (self[2][2] * s4) - (self[2][3] * s3)) * invdet),
[Float4::new(((self[1].get_1() * c5) - (self[1].get_2() * c4) +
(self[1].get_3() * c3)) * invdet,
((-self[0].get_1() * c5) + (self[0].get_2() * c4) -
(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,
((self[0][0] * c5) - (self[0][2] * c2) + (self[0][3] * c1)) * invdet,
((-self[3][0] * s5) + (self[3][2] * s2) - (self[3][3] * s1)) * invdet,
((self[2][0] * s5) - (self[2][2] * s2) + (self[2][3] * s1)) * invdet),
Float4::new(((-self[1].get_0() * c5) + (self[1].get_2() * c2) -
(self[1].get_3() * c1)) * invdet,
((self[0].get_0() * c5) - (self[0].get_2() * c2) +
(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,
((-self[0][0] * c4) + (self[0][1] * c2) - (self[0][3] * c0)) * invdet,
((self[3][0] * s4) - (self[3][1] * s2) + (self[3][3] * s0)) * invdet,
((-self[2][0] * s4) + (self[2][1] * s2) - (self[2][3] * s0)) * invdet),
Float4::new(((self[1].get_0() * c4) - (self[1].get_1() * c2) +
(self[1].get_3() * c0)) * invdet,
((-self[0].get_0() * c4) + (self[0].get_1() * c2) -
(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,
((self[0][0] * c3) - (self[0][1] * c1) + (self[0][2] * c0)) * invdet,
((-self[3][0] * s3) + (self[3][1] * s1) - (self[3][2] * s0)) * invdet,
((self[2][0] * s3) - (self[2][1] * s1) + (self[2][2] * s0)) * invdet)]
Float4::new(((-self[1].get_0() * c3) + (self[1].get_1() * c1) -
(self[1].get_2() * c0)) * invdet,
((self[0].get_0() * c3) - (self[0].get_1() * c1) +
(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 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 {
let alpha_minus = 1.0 - alpha;
Matrix4x4 {
values: [Float4::new((self[0][0] * alpha_minus) + (other[0][0] * alpha),
(self[0][1] * alpha_minus) + (other[0][1] * alpha),
(self[0][2] * alpha_minus) + (other[0][2] * alpha),
(self[0][3] * alpha_minus) + (other[0][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))],
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)],
}
}
}

View File

@ -134,12 +134,12 @@ pub fn log2_64(value: u64) -> u64 {
/// Creates a coordinate system from a single vector.
pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) {
let v2 = if v[0].abs() > v[1].abs() {
let invlen = 1.0 / ((v[0] * v[0]) + (v[2] * v[2])).sqrt();
Vector::new(-v[2] * invlen, 0.0, v[0] * invlen)
let v2 = if v.x().abs() > v.y().abs() {
let invlen = 1.0 / ((v.x() * v.x()) + (v.z() * v.z())).sqrt();
Vector::new(-v.z() * invlen, 0.0, v.x() * invlen)
} else {
let invlen = 1.0 / ((v[1] * v[1]) + (v[2] * v[2])).sqrt();
Vector::new(0.0, v[2] * invlen, -v[1] * invlen)
let invlen = 1.0 / ((v.y() * v.y()) + (v.z() * v.z())).sqrt();
Vector::new(0.0, v.z() * invlen, -v.y() * invlen)
};
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"
// vector to a space composed of tox, toy, and toz
// 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.

View File

@ -1,6 +1,6 @@
#![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 lerp::Lerp;
@ -33,26 +33,40 @@ impl Normal {
}
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())
}
}
impl Index<usize> for Normal {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
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."),
}
}
}
impl IndexMut<usize> for Normal {
fn index_mut(&mut self, index: usize) -> &mut f32 {
debug_assert!(index < 3);
pub fn x(&self) -> f32 {
self.co.get_0()
}
&mut self.co[index]
pub fn y(&self) -> f32 {
self.co.get_1()
}
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 {
let mat = other.inverse().transposed();
Normal {
co: Float4::new((self[0] * mat[0][0]) + (self[1] * mat[0][1]) + (self[2] * mat[0][2]),
(self[0] * mat[1][0]) + (self[1] * mat[1][1]) + (self[2] * mat[1][2]),
(self[0] * mat[2][0]) + (self[1] * mat[2][1]) + (self[2] * mat[2][2]),
co: Float4::new((self.co * mat[0]).h_sum(),
(self.co * mat[1]).h_sum(),
(self.co * mat[2]).h_sum(),
0.0),
}
}
@ -140,9 +154,12 @@ impl DotProduct for Normal {
impl CrossProduct for Normal {
fn cross(self, other: Normal) -> Normal {
Normal {
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]),
(self[2] * other[0]) - (self[0] * other[2]),
(self[0] * other[1]) - (self[1] * other[0]),
co: Float4::new((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),
}
}
@ -231,9 +248,9 @@ mod tests {
let n1 = Normal::new(1.0, 2.0, 3.0);
let n2 = Normal::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
let n3 = n1.normalized();
assert!((n3[0] - n2[0]).abs() < 0.000001);
assert!((n3[1] - n2[1]).abs() < 0.000001);
assert!((n3[2] - n2[2]).abs() < 0.000001);
assert!((n3.x() - n2.x()).abs() < 0.000001);
assert!((n3.y() - n2.y()).abs() < 0.000001);
assert!((n3.z() - n2.z()).abs() < 0.000001);
}
#[test]

View File

@ -1,6 +1,6 @@
#![allow(dead_code)]
use std::ops::{Index, IndexMut, Add, Sub, Mul};
use std::ops::{Add, Sub, Mul};
use std::cmp::PartialEq;
use lerp::Lerp;
@ -23,7 +23,7 @@ impl Point {
/// Returns the point in standardized coordinates, where the
/// fourth homogeneous component has been normalized to 1.0.
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 {
@ -41,26 +41,40 @@ impl Point {
}
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())
}
}
impl Index<usize> for Point {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
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."),
}
}
}
impl IndexMut<usize> for Point {
fn index_mut(&mut self, index: usize) -> &mut f32 {
debug_assert!(index < 3);
pub fn x(&self) -> f32 {
self.co.get_0()
}
&mut self.co[index]
pub fn y(&self) -> f32 {
self.co.get_1()
}
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() {
let mut p1 = Point::new(1.0, 2.0, 3.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());
}
@ -196,7 +210,7 @@ mod tests {
1.0,
5.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);
}

View File

@ -1,6 +1,6 @@
#![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 lerp::Lerp;
@ -33,26 +33,40 @@ impl Vector {
}
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())
}
}
impl Index<usize> for Vector {
type Output = f32;
fn index(&self, index: usize) -> &f32 {
debug_assert!(index < 3);
&self.co[index]
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."),
}
}
}
impl IndexMut<usize> for Vector {
fn index_mut(&mut self, index: usize) -> &mut f32 {
debug_assert!(index < 3);
pub fn x(&self) -> f32 {
self.co.get_0()
}
&mut self.co[index]
pub fn y(&self) -> f32 {
self.co.get_1()
}
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 {
fn cross(self, other: Vector) -> Vector {
Vector {
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]),
(self[2] * other[0]) - (self[0] * other[2]),
(self[0] * other[1]) - (self[1] * other[0]),
co: Float4::new((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),
}
}
@ -202,7 +219,7 @@ mod tests {
15.0,
3.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);
}
@ -255,9 +272,9 @@ mod tests {
let v1 = Vector::new(1.0, 2.0, 3.0);
let v2 = Vector::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
let v3 = v1.normalized();
assert!((v3[0] - v2[0]).abs() < 0.000001);
assert!((v3[1] - v2[1]).abs() < 0.000001);
assert!((v3[2] - v2[2]).abs() < 0.000001);
assert!((v3.x() - v2.x()).abs() < 0.000001);
assert!((v3.y() - v2.y()).abs() < 0.000001);
assert!((v3.z() - v2.z()).abs() < 0.000001);
}
#[test]

View File

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

View File

@ -650,7 +650,7 @@ mod tests {
"#)
.unwrap();
let mut i = dt.iter_children_with_type("A");
let i = dt.iter_children_with_type("A");
assert_eq!(i.count(), 3);
}
@ -665,7 +665,7 @@ mod tests {
"#)
.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);
}
@ -680,7 +680,7 @@ mod tests {
"#)
.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);
}
}

View File

@ -210,7 +210,7 @@ impl SurfaceClosure for LambertClosure {
// Generate a random ray direction in the hemisphere
// of the surface.
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 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] {
// | | | | | | | | |
// 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 s6 = s4 + 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.y().is_sign_positive());
let s1 = partition(&mut rays[..s2], |r| r.dir_inv[2].is_sign_positive());
let s3 = s2 + partition(&mut rays[s2..s4], |r| r.dir_inv[2].is_sign_positive());
let s5 = s4 + partition(&mut rays[s4..s6], |r| r.dir_inv[2].is_sign_positive());
let s7 = s6 + partition(&mut rays[s6..], |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.z().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.z().is_sign_positive());
let (rest, rs7) = rays.split_at_mut(s7);
let (rest, rs6) = rest.split_at_mut(s6);