diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8d60f54..89054d3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,4 +1,4 @@ -name: Build, Tests and Examples +name: Build, Tests, Lint and Examples on: [push] @@ -9,6 +9,10 @@ jobs: steps: - uses: actions/checkout@v1 + - name: Install Clippy + run: rustup component add clippy + - name: Run Clippy + run: cargo clippy -- -D errors - name: Build run: cargo build --verbose - name: Run tests diff --git a/demo/demo.png b/demo/demo.png index c8225ca..e69de29 100644 Binary files a/demo/demo.png and b/demo/demo.png differ diff --git a/src/camera.rs b/src/camera.rs index b8acee9..1c412f6 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -37,11 +37,11 @@ impl SimpleCamera { //let viewPlaneHalfHeight = aspectRatio*viewPlaneHalfWidth SimpleCamera { - location: location, + location, - camz: camz, + camz, camx: camx * aspect_ratio, - camy: camy, + camy, tax: angle.tan(), tay: angle.tan() @@ -197,17 +197,17 @@ impl FlatLensCamera { //let viewPlaneHalfHeight = aspectRatio*viewPlaneHalfWidth FlatLensCamera { - location: location, + location, - camz: camz, + camz, camx: camx * aspect_ratio, - camy: camy, + camy, tax: angle.tan(), tay: angle.tan(), - aperture: aperture, - focus: focus, + aperture, + focus, } } } @@ -224,7 +224,7 @@ impl Camera for FlatLensCamera { let ro = self.location + Vector3::new(point_lens[0], point_lens[1], 0.0); Ray { - ro: ro, + ro, rd: (focal_point - ro).normalize() } diff --git a/src/color.rs b/src/color.rs index ea71925..3343b16 100644 --- a/src/color.rs +++ b/src/color.rs @@ -10,7 +10,7 @@ pub struct Color { impl Color { pub fn new(r:f64, g:f64, b:f64) -> Color { - return Color { + Color { rgb: Vector3::new(r,g,b) } } @@ -20,40 +20,40 @@ impl Color { } pub fn white() -> Color { - return Color::new(1f64,1f64,1f64); + Color::new(1f64,1f64,1f64) } pub fn red() -> Color { - return Color::new(1f64,0f64,0f64); + Color::new(1f64,0f64,0f64) } pub fn blue() -> Color { - return Color::new(0f64,0f64,01f64); + Color::new(0f64,0f64,01f64) } pub fn green() -> Color { - return Color::new(0f64,1f64,0f64); + Color::new(0f64,1f64,0f64) } - pub fn to_u8(&self) -> (u8, u8, u8) { - return ((self.rgb[0] * 255f64).min(255f64) as u8, (self.rgb[1] * 255f64).min(255f64) as u8, (self.rgb[2] * 255f64).min(255f64) as u8); + pub fn as_u8(&self) -> (u8, u8, u8) { + ((self.rgb[0] * 255f64).min(255f64) as u8, (self.rgb[1] * 255f64).min(255f64) as u8, (self.rgb[2] * 255f64).min(255f64) as u8) } - pub fn to_vec(&self) -> Vector3 { - return self.rgb.clone(); + pub fn as_vec(&self) -> Vector3 { + self.rgb } pub fn clamp(&self, val: f64) -> Color { - return Color::new(self.rgb.x.min(val), self.rgb.y.min(val), self.rgb.z.min(val)); + Color::new(self.rgb.x.min(val), self.rgb.y.min(val), self.rgb.z.min(val)) } pub fn min() -> Color { - return Color::new(1./255.,1./255.,1./255.); + Color::new(1./255.,1./255.,1./255.) } pub fn ignore_nan(&self) -> Color { - return Color::new( + Color::new( if self.rgb.x.is_nan() { 0. } else { self.rgb.x }, if self.rgb.y.is_nan() { 0. } else { self.rgb.y }, if self.rgb.z.is_nan() { 0. } else { self.rgb.z }, - ); + ) } /// Blend this color with another color using the given factor @@ -65,7 +65,7 @@ impl Color { /// # Returns /// A new color that is a blend of this color and the other color pub fn blend(&self, other: &Color, factor: f64) -> Color { - let clamped_factor = factor.max(0.0).min(1.0); + let clamped_factor = factor.clamp(0.0, 1.0); let self_factor = 1.0 - clamped_factor; Color::new( @@ -97,7 +97,7 @@ impl Mul for Color { type Output = Color; fn mul(self, _rhs: Color) -> Color { - Color {rgb: (_rhs * self.to_vec()).to_vec() } + Color {rgb: (_rhs * self.as_vec()).as_vec() } } } @@ -122,7 +122,7 @@ impl Add> for Color { fn add(self, _rhs: Vector3) -> Color { Color { - rgb: _rhs + &self.rgb + rgb: _rhs + self.rgb } } } diff --git a/src/geometry.rs b/src/geometry.rs index 33b7d90..a0f5264 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -4,13 +4,13 @@ use crate::geometry::_rand::Rng; use std::f64; pub fn rand() -> f64 { - return _rand::thread_rng().gen_range(0.,1.); + _rand::thread_rng().gen_range(0.,1.) } pub fn random_point_on_unit_sphere() -> Vector3{ let u = rand(); let v = rand(); - return point_on_unit_sphere(u, v); + point_on_unit_sphere(u, v) } pub fn point_on_unit_sphere(u: f64, v: f64) -> Vector3{ @@ -24,13 +24,13 @@ pub fn point_on_unit_sphere(u: f64, v: f64) -> Vector3{ let x = r * sin_phi * cos_theta; let y = r * sin_phi * sin_theta; let z = r * cos_phi; - return Vector3::new(x, y, z); + Vector3::new(x, y, z) } pub fn random_point_on_disc(radius: f64) -> Vector2{ let r = radius * rand().sqrt(); let theta = rand() * 2.0 * f64::consts::PI; - return Vector2::new(r * theta.cos(), r * theta.sin()); + Vector2::new(r * theta.cos(), r * theta.sin()) } pub fn uniform_sample_hemisphere(r1: f64, r2: f64) -> Vector3{ @@ -38,7 +38,7 @@ pub fn uniform_sample_hemisphere(r1: f64, r2: f64) -> Vector3{ let phi = 2. * f64::consts::PI * r2; let x = sin_theta * phi.cos(); let z = sin_theta * phi.sin(); - return Vector3::new(x, r1, z); + Vector3::new(x, r1, z) } // Transform into the world of vec diff --git a/src/intersection.rs b/src/intersection.rs index b4b25e4..73d0543 100644 --- a/src/intersection.rs +++ b/src/intersection.rs @@ -33,7 +33,7 @@ pub struct MediumIntersection { impl cmp::PartialEq for Intersection { fn eq(&self, other: &Intersection) -> bool { - &self.point == &other.point + self.point == other.point } } diff --git a/src/material/ambient.rs b/src/material/ambient.rs index 3db033a..5c2c9b4 100644 --- a/src/material/ambient.rs +++ b/src/material/ambient.rs @@ -10,7 +10,7 @@ pub struct Ambient { impl MaterialModel for Ambient { fn scatter(&self, _r: &Ray, _intersection: &Intersection, _s: &Scene) -> ScatteredRay{ - return ScatteredRay{ attenuate:self.albedo, ray: None }; + ScatteredRay{ attenuate:self.albedo, ray: None } } diff --git a/src/material/dielectric.rs b/src/material/dielectric.rs index 587eb71..c37f455 100644 --- a/src/material/dielectric.rs +++ b/src/material/dielectric.rs @@ -13,6 +13,6 @@ pub struct Dielectric { impl MaterialModel for Dielectric { fn scatter(&self, r: &Ray, intersection: &Intersection, _s: &Scene) -> ScatteredRay{ - return scatter_dielectric(self.refractive_index, self.attenuate, r, intersection); + scatter_dielectric(self.refractive_index, self.attenuate, r, intersection) } } diff --git a/src/material/diffuse_light.rs b/src/material/diffuse_light.rs index 11a68df..8d34bb9 100644 --- a/src/material/diffuse_light.rs +++ b/src/material/diffuse_light.rs @@ -11,8 +11,8 @@ pub struct DiffuseLight { impl MaterialModel for DiffuseLight { fn scatter(&self, _r: &Ray, _intersection: &Intersection, _s: &Scene) -> ScatteredRay{ - return ScatteredRay{ + ScatteredRay{ attenuate:self.color * self.intensity, - ray: None }; + ray: None } } } diff --git a/src/material/functions.rs b/src/material/functions.rs index 40218ec..e377696 100644 --- a/src/material/functions.rs +++ b/src/material/functions.rs @@ -36,7 +36,7 @@ pub fn scatter_lambertian(albedo: Color, intersection: &Intersection) -> Scatter ro: intersection.point, rd: intersection.normal + random_point_on_unit_sphere(), }; - return ScatteredRay{ attenuate:albedo, ray: Some(refl) }; + ScatteredRay{ attenuate:albedo, ray: Some(refl) } } pub fn scatter_dielectric( @@ -46,21 +46,27 @@ pub fn scatter_dielectric( intersection: &Intersection ) -> ScatteredRay { - let mut ni_over_nt = refractive_index; // Assumes it comes from air - TODO - let cosine; let drn = r.rd.dot(&intersection.normal); - let outward_normal; - if drn > 0.0 { + + let outward_normal = if drn > 0.0 { // when ray shoot through object back into vacuum, // ni_over_nt = ref_idx, surface normal has to be inverted. - cosine = drn / r.rd.norm(); - outward_normal = -intersection.normal + -intersection.normal } else { // when ray shoots into object, - // ni_over_nt = 1 / ref_idx. - cosine = - drn / r.rd.norm(); - ni_over_nt = 1.0 / refractive_index; - outward_normal = intersection.normal + intersection.normal + }; + + let cosine = if drn > 0.0 { + drn / r.rd.norm() + } else { + -drn / r.rd.norm() + }; + + let ni_over_nt = if drn > 0.0 { + refractive_index // Assumes it comes from air - TODO + } else { + 1.0 / refractive_index }; match refract(r.rd, outward_normal, ni_over_nt) { @@ -85,26 +91,27 @@ pub fn scatter_dielectric( } let reflected = reflect(r.rd, intersection.normal); - return ScatteredRay { + ScatteredRay { attenuate: Color::white(), ray: Some(Ray { ro: intersection.point, rd: reflected }) - }; + } } pub fn diffuse (pigment: Color, i: &Intersection, light_vec: &Vector3, light: &Light) -> Color { let diffuse_scale = light_vec.normalize().dot(&i.normal) * light.intensity; if diffuse_scale.is_sign_positive() { - return light.color * pigment * diffuse_scale; + light.color * pigment * diffuse_scale + } else { + Color::black() } - return Color::black() } pub fn phong (phong: f64, r: &Ray, intersection: &Intersection, light_vec: &Vector3) -> Color { - if phong < std::f64::MIN_POSITIVE { + if phong < f64::MIN_POSITIVE { return Color::black(); } let ln = light_vec.normalize(); @@ -116,5 +123,5 @@ pub fn phong (phong: f64, r: &Ray, intersection: &Intersection, light_vec: &Vect return Color::white() * spec_scale; } - return Color::black(); + Color::black() } diff --git a/src/material/lambertian.rs b/src/material/lambertian.rs index 776dce9..28a7886 100644 --- a/src/material/lambertian.rs +++ b/src/material/lambertian.rs @@ -10,7 +10,7 @@ pub struct Lambertian { } impl MaterialModel for Lambertian { fn scatter(&self, _r: &Ray, intersection: &Intersection, _s: &Scene) -> ScatteredRay{ - return scatter_lambertian(self.albedo, intersection); + scatter_lambertian(self.albedo, intersection) } } diff --git a/src/material/legacy.rs b/src/material/legacy.rs index 0387252..fbeb0f4 100644 --- a/src/material/legacy.rs +++ b/src/material/legacy.rs @@ -23,7 +23,7 @@ impl MaterialModel for Whitted { match shadow_intersection { Some(_) => (),// Point in shadow... - None => out = diffuse(self.pigment, &intersection, &light_vec, &light) + phong(self.phong, &r, &intersection, &light_vec), + None => out = diffuse(self.pigment, intersection, &light_vec, light) + phong(self.phong, r, intersection, &light_vec), } } @@ -34,7 +34,7 @@ impl MaterialModel for Whitted { }; return ScatteredRay{ attenuate: out * self.reflection, ray: Some(refl) }; } - return ScatteredRay{ attenuate: out, ray: None }; + ScatteredRay{ attenuate: out, ray: None } } } @@ -44,6 +44,6 @@ pub struct FlatColor { impl MaterialModel for FlatColor { fn scatter(&self, _r: &Ray, _intersection: &Intersection, _s: &Scene) -> ScatteredRay{ - return ScatteredRay{ attenuate: self.pigment, ray: None }; + ScatteredRay{ attenuate: self.pigment, ray: None } } } diff --git a/src/material/model.rs b/src/material/model.rs index b4a1a69..78dafe8 100644 --- a/src/material/model.rs +++ b/src/material/model.rs @@ -3,9 +3,7 @@ use crate::ray::Ray; use crate::intersection::Intersection; use crate::scene::Scene; -/// /// See https://google.github.io/filament//Materials.md.html#materialmodels/litmodel - /// /// In Google Filament they refer to /// - The Lit model (standard material model) diff --git a/src/material/noise.rs b/src/material/noise.rs index 6947aef..d3a217d 100644 --- a/src/material/noise.rs +++ b/src/material/noise.rs @@ -247,7 +247,7 @@ mod tests { for z in 0..5 { let pos = Vector3::new(x as f64, y as f64, z as f64); let value = noise_texture.noise_value(pos); - assert!(value >= 0.0 && value <= 1.0, "Noise value out of range: {}", value); + assert!((0.0..=1.0).contains(&value), "Noise value out of range: {}", value); } } } @@ -272,7 +272,7 @@ mod tests { for z in 0..5 { let pos = Vector3::new(x as f64, y as f64, z as f64); let value = noise_texture.noise_value(pos); - assert!(value >= 0.0 && value <= 1.0, "FBM value out of range: {}", value); + assert!((0.0..=1.0).contains(&value), "FBM value out of range: {}", value); } } } @@ -294,7 +294,7 @@ mod tests { for z in 0..5 { let pos = Vector3::new(x as f64, y as f64, z as f64); let value = noise_texture.noise_value(pos); - assert!(value >= 0.0 && value <= 1.0, "Marble value out of range: {}", value); + assert!((0.0..=1.0).contains(&value), "Marble value out of range: {}", value); } } } diff --git a/src/material/normal.rs b/src/material/normal.rs index eda8a11..e0fa253 100644 --- a/src/material/normal.rs +++ b/src/material/normal.rs @@ -14,7 +14,7 @@ impl MaterialModel for NormalShade { fn scatter(&self, _r: &Ray, intersection: &Intersection, _s: &Scene) -> ScatteredRay{ let angle = intersection.normal.dot(&Vector3::new(0., 1., 0.)); let c = Color::white() * intersection.normal.abs() * angle * angle * angle; - return ScatteredRay{ attenuate: c, ray: None }; + ScatteredRay{ attenuate: c, ray: None } } } diff --git a/src/material/plastic.rs b/src/material/plastic.rs index f9b791b..f7c60a1 100644 --- a/src/material/plastic.rs +++ b/src/material/plastic.rs @@ -29,18 +29,18 @@ impl MaterialModel for Plastic { for light in &s.lights { let light_vec = light.position - intersection.point; let shadow_ray = Ray {ro: intersection.point, rd: light_vec}; - let shadow_intersection = s.objects.nearest_intersection(&shadow_ray, light_vec.norm(), std::f64::MIN_POSITIVE); + let shadow_intersection = s.objects.nearest_intersection(&shadow_ray, light_vec.norm(), f64::MIN_POSITIVE); match shadow_intersection { Some(_) => (),// Point in shadow... None => { - diffuse_refl = diffuse_refl + diffuse(self.albedo, &intersection, &light_vec, &light); + diffuse_refl = diffuse_refl + diffuse(self.albedo, intersection, &light_vec, light); }, } } - return scatter_lambertian(diffuse_refl, intersection); + scatter_lambertian(diffuse_refl, intersection) } else { - return scatter_dielectric(self.refractive_index, self.albedo, r, intersection); + scatter_dielectric(self.refractive_index, self.albedo, r, intersection) } } } diff --git a/src/material/specular.rs b/src/material/specular.rs index fad6ef4..de23068 100644 --- a/src/material/specular.rs +++ b/src/material/specular.rs @@ -20,7 +20,7 @@ impl MaterialModel for Specular { rd: reflect(r.rd, intersection.normal) + fuzz }; - return ScatteredRay{ attenuate:self.albedo, ray: Some(refl) }; + ScatteredRay{ attenuate:self.albedo, ray: Some(refl) } } } diff --git a/src/material/texture.rs b/src/material/texture.rs index 8117352..47fc2dd 100644 --- a/src/material/texture.rs +++ b/src/material/texture.rs @@ -3,15 +3,15 @@ use crate::material::model::MaterialModel; use crate::noise::{PerlinNoise, WorleyNoise, combined_noise}; pub trait Medium : Sync{ - fn material_at(&self, pt: Vector3) -> &Box; + fn material_at(&self, pt: Vector3) -> &(dyn MaterialModel + Sync + Send); } pub struct Solid { pub m: Box } impl Medium for Solid { - fn material_at(&self, _pt: Vector3) -> &Box { - &self.m + fn material_at(&self, _pt: Vector3) -> &(dyn MaterialModel + Sync + Send) { + &*self.m } } @@ -28,11 +28,11 @@ impl CheckeredYPlane { } impl Medium for CheckeredYPlane { - fn material_at(&self, pt: Vector3) -> &Box { + fn material_at(&self, pt: Vector3) -> &(dyn MaterialModel + Sync + Send) { let zig = if (pt[0].abs() / self.xsize) as i32 % 2 == 0 { pt[0] > 0. } else { pt[0] <= 0. }; let zag = if (pt[2].abs() / self.zsize) as i32 % 2 == 0 { pt[2] > 0. } else { pt[2] <= 0. }; // zig XOR zag - return if !zig != !zag { &self.m1 } else { &self.m2 }; + if zig != zag { &*self.m1 } else { &*self.m2 } } } @@ -266,15 +266,15 @@ impl NoiseMedium { } impl Medium for NoiseMedium { - fn material_at(&self, pt: Vector3) -> &Box { + fn material_at(&self, pt: Vector3) -> &(dyn MaterialModel + Sync + Send) { // Calculate noise value at the point let noise_value = self.noise_value(pt); // Choose material based on noise value and threshold if noise_value >= self.threshold { - &self.m2 + &*self.m2 } else { - &self.m1 + &*self.m1 } } } diff --git a/src/noise.rs b/src/noise.rs index bc88838..4081c84 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -42,10 +42,8 @@ impl PerlinNoise { // Double permutation array let mut perm = [0; 512]; - for i in 0..256 { - perm[i] = base_perm[i]; - perm[i + 256] = base_perm[i]; - } + perm[..256].copy_from_slice(&base_perm); + perm[256..512].copy_from_slice(&base_perm); // 12 gradient vectors for 3D noise let grad3 = [ @@ -110,10 +108,8 @@ impl PerlinNoise { let lerp5 = self.lerp(lerp1, lerp2, v); let lerp6 = self.lerp(lerp3, lerp4, v); - let result = self.lerp(lerp5, lerp6, w); - // Scale to [-1, 1] - result + self.lerp(lerp5, lerp6, w) } /// Generate fractal Brownian motion (fBm) noise @@ -275,7 +271,7 @@ pub mod combined_noise { let falloff_factor = (-distance * falloff).exp(); // Ensure density is in [0, 1] range - (raw_density * falloff_factor).max(0.0).min(1.0) + (raw_density * falloff_factor).clamp(0.0, 1.0) } } @@ -292,7 +288,7 @@ mod tests { for y in 0..10 { for z in 0..10 { let n = perlin.noise(x as f64 * 0.1, y as f64 * 0.1, z as f64 * 0.1); - assert!(n >= -1.0 && n <= 1.0); + assert!((-1.0..=1.0).contains(&n)); } } } @@ -312,7 +308,7 @@ mod tests { z as f64 * 0.1, 4, 0.5, 2.0 ); - assert!(n >= 0.0 && n <= 1.0); + assert!((0.0..=1.0).contains(&n)); } } } @@ -344,7 +340,7 @@ mod tests { for z in 0..5 { let pos = Vector3::new(x as f64, y as f64, z as f64); let density = combined_noise::density_field(pos, &perlin, &worley, 0.1, 0.1); - assert!(density >= 0.0 && density <= 1.0); + assert!((0.0..=1.0).contains(&density)); } } } @@ -385,13 +381,11 @@ mod tests { let falloff = 0.05; // Sample a few specific points - let positions = vec![ - Vector3::new(0.0, 0.0, 0.0), + let positions = [Vector3::new(0.0, 0.0, 0.0), Vector3::new(5.0, 5.0, 5.0), Vector3::new(10.0, 0.0, 0.0), Vector3::new(0.0, 10.0, 0.0), - Vector3::new(0.0, 0.0, 10.0), - ]; + Vector3::new(0.0, 0.0, 10.0)]; // Get densities at each position let densities: Vec = positions.iter() @@ -403,7 +397,7 @@ mod tests { // Simple sanity check - make sure all results are in the valid range for &density in &densities { - assert!(density >= 0.0 && density <= 1.0, + assert!((0.0..=1.0).contains(&density), "Density should be in range [0,1], got {}", density); } } diff --git a/src/ocean.rs b/src/ocean.rs index 8ba6094..d5da118 100644 --- a/src/ocean.rs +++ b/src/ocean.rs @@ -54,38 +54,34 @@ use rand::rngs::StdRng; /// /// I still haven't worked out what units everything is in, or what the /// scale factor 'A' should represent. -/// - - +/// /// Normal distribution rand (gaussian) fn randn(rng: &mut StdRng) -> f64 { let normal = Normal::new(0.0, 1.0); - return normal.sample(rng); + normal.sample(rng) } /// Phillips Spectrum fn phillips(k: Vector2, wind: Vector2, scale: f64, gravity: f64) -> f64 { let ksq = k.x * k.x + k.y * k.y; - if ksq < std::f64::MIN_POSITIVE { return 0. }; + if ksq < f64::MIN_POSITIVE { return 0. }; let wind_dir = wind.normalize(); let wk = k.normalize().dot(&wind_dir); let wind_speed = wind.norm(); let l = (wind_speed * wind_speed) / gravity; - return scale * (-1.0 / (ksq * l * l)).exp() / (ksq * ksq) * wk * wk ; + scale * (-1.0 / (ksq * l * l)).exp() / (ksq * ksq) * wk * wk } fn amplitude(k: Vector2, wind: Vector2, scale: f64, gravity: f64, rng: &mut StdRng) -> Complex { - return - 1f64/(2f64.sqrt()) * + 1f64/(2f64.sqrt()) * Complex::new(randn(rng), randn(rng)) * phillips(k, wind, scale, gravity).sqrt() - ; } fn dispersion(k: Vector2, gravity: f64) -> f64 { let w = (k.norm() * gravity).sqrt(); // Deep water frequency relationship to magnitude let w_0 = 2f64 * std::f64::consts::PI / 200f64; // No idea? Rounding factor. Comes from keithlantz impl. - return (w / w_0).floor() * w_0; + (w / w_0).floor() * w_0 } fn create_amplitude_tile( @@ -97,7 +93,7 @@ fn create_amplitude_tile( fourier_grid_size: usize, rng: &mut StdRng, )-> Vec> { - let mut h0 = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; + let mut h0 = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; for j in 0 .. fourier_grid_size { for i in 0 .. fourier_grid_size { @@ -107,50 +103,50 @@ fn create_amplitude_tile( let n = (j as f64 / fourier_grid_size as f64 - 0.5) * fourier_grid_size as f64; let m = (i as f64 / fourier_grid_size as f64 - 0.5) * fourier_grid_size as f64; - let k = gen_k(n, m , lx as f64, lz as f64); + let k = gen_k(n, m , lx, lz); h0[ind] = amplitude(k, wind, scale, gravity, rng); } } - return h0 + h0 } fn gen_k(n: f64, m: f64, lx: f64, lz: f64) -> Vector2 { // <2 pi n / Lx, 2 pi m / Lz> - return Vector2::new( + Vector2::new( 2f64 * std::f64::consts::PI * n / lx, 2f64 * std::f64::consts::PI * m / lz, - ); + ) } fn mn_to_i(m: i32, n: i32, size: i32) -> usize { - return ((n + size/2) * size + (m + size/2)) as usize; + ((n + size/2) * size + (m + size/2)) as usize } -fn transpose(matr: &Vec>, size: usize) -> Vec> { - let mut out = matr.clone(); +fn transpose(matr: &[Complex], size: usize) -> Vec> { + let mut out = matr.to_vec(); for x in 0..size { for y in 0..size { out[x*size + y] = matr[y*size + x]; } } - return out; + out } /// 2D Fast Fourier Transform (Used to test IFFT2) fn fft2 (tile: Vec>, size: usize) -> Vec> { - let ifft = Radix4::new((size) as usize, false); + let ifft = Radix4::new(size, false); let mut tile_clone = tile.clone(); let mut fft = vec![Complex::new(0., 0.); size * size]; ifft.process_multi(&mut tile_clone[..], &mut fft[..]); let mut conj = transpose(&fft, size); let mut out = vec![Complex::new(0., 0.); size * size]; ifft.process_multi(&mut conj, &mut out[..]); - return transpose(&out, size); + transpose(&out, size) } /// Inverse 2D Fast Fourier Transform fn ifft2 (tile: Vec>, size: usize) -> Vec> { - let ifft = Radix4::new((size) as usize, true); + let ifft = Radix4::new(size, true); let mut tile_clone = tile.clone(); let mut fft = vec![Complex::new(0., 0.); size * size]; ifft.process_multi(&mut tile_clone[..], &mut fft[..]); @@ -159,56 +155,59 @@ fn ifft2 (tile: Vec>, size: usize) -> Vec> { let mut out = vec![Complex::new(0., 0.); size * size]; ifft.process_multi(&mut conj[..], &mut out[..]); out = out.iter().map(|x| x.unscale(size as f64)).collect(); - return transpose(&out, size); + transpose(&out, size) } -fn vertex_at(z: usize, x: usize, vertices: &Vec>, fourier_grid_size: usize) -> Vector3{ - return vertices[(z % fourier_grid_size) * fourier_grid_size + (x % fourier_grid_size)]; +fn vertex_at(z: usize, x: usize, vertices: &[Vector3], fourier_grid_size: usize) -> Vector3{ + vertices[(z % fourier_grid_size) * fourier_grid_size + (x % fourier_grid_size)] } -fn make_square_for(x: usize, z: usize, fourier_grid_size: usize, vertices: &Vec>) -> (Triangle, Triangle) { - return ( +fn make_square_for(x: usize, z: usize, fourier_grid_size: usize, vertices: &[Vector3]) -> (Triangle, Triangle) { + ( Triangle::new( - vertex_at(z + 1, x + 1, &vertices, fourier_grid_size), - vertex_at(z, x + 1, &vertices, fourier_grid_size), - vertex_at(z + 1, x, &vertices, fourier_grid_size), + vertex_at(z + 1, x + 1, vertices, fourier_grid_size), + vertex_at(z, x + 1, vertices, fourier_grid_size), + vertex_at(z + 1, x, vertices, fourier_grid_size), ), Triangle::new( - vertex_at(z + 1, x, &vertices, fourier_grid_size), - vertex_at(z, x + 1, &vertices, fourier_grid_size), - vertex_at(z, x, &vertices, fourier_grid_size), + vertex_at(z + 1, x, vertices, fourier_grid_size), + vertex_at(z, x + 1, vertices, fourier_grid_size), + vertex_at(z, x, vertices, fourier_grid_size), ) - ); + ) } +// Type definition for complex height field data +type OceanComplexData = ( + Vec>, // ht + Vec>, // ht_slope_x + Vec>, // ht_slope_z + Vec>, // ht_slope_dx + Vec>, // ht_slope_dz +); + pub fn create_tile( fourier_grid_size:usize, lx: f64, lz: f64, gravity: f64, h0: Vec>) - -> ( - Vec>, - Vec>, - Vec>, - Vec>, - Vec>, - ) { + -> OceanComplexData { let h0trans = transpose(&h0, fourier_grid_size); // Tile of amplitudes - let mut ht = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; - let mut ht_slope_x = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; - let mut ht_slope_z = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; - let mut ht_slope_dx = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; - let mut ht_slope_dz = vec![Complex::new(0., 0.); (fourier_grid_size * fourier_grid_size) as usize]; + let mut ht = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; + let mut ht_slope_x = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; + let mut ht_slope_z = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; + let mut ht_slope_dx = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; + let mut ht_slope_dz = vec![Complex::new(0., 0.); fourier_grid_size * fourier_grid_size]; for j in 0 .. fourier_grid_size { for i in 0 .. fourier_grid_size { let ind = j * fourier_grid_size + i; let n = (j as f64 / fourier_grid_size as f64 - 0.5) * fourier_grid_size as f64; let m = (i as f64 / fourier_grid_size as f64 - 0.5) * fourier_grid_size as f64; - let k = gen_k(n, m , lx as f64, lz as f64); + let k = gen_k(n, m , lx, lz); let w = dispersion(k, gravity); let c0 = Complex::new(w.cos(), w.sin()); let c1 = Complex::new(w.cos(), -w.sin()); @@ -234,13 +233,13 @@ pub fn create_tile( ht_slope_dx = ifft2(ht_slope_dx, fourier_grid_size); ht_slope_dz = ifft2(ht_slope_dz, fourier_grid_size); - return ( + ( ht, ht_slope_x, ht_slope_z, ht_slope_dx, ht_slope_dz, - ); + ) } @@ -257,36 +256,36 @@ fn generate_mesh(vertices: Vec>, size: usize, lx: f64, lz: f64) -> if x == size - 2 { // Need to add the tile from end -> end + 1 let (mut t0, mut t1) = make_square_for(x+1, z, size, &vertices); - t0.v0.x = t0.v0.x + lx; - t0.v1.x = t0.v1.x + lx; - t1.v1.x = t1.v1.x + lx; + t0.v0.x += lx; + t0.v1.x += lx; + t1.v1.x += lx; triangles.push(Arc::new(Triangle::new(t0.v0, t0.v1, t0.v2))); // Recalc normal triangles.push(Arc::new(Triangle::new(t1.v0, t1.v1, t1.v2))); } if z == size - 2 { // Need to add the tile from end -> end + 1 let (mut t0, mut t1) = make_square_for(x, z+1, size, &vertices); - t0.v0.z = t0.v0.z + lz; - t0.v2.z = t0.v2.z + lz; - t1.v0.z = t1.v0.z + lz; + t0.v0.z += lz; + t0.v2.z += lz; + t1.v0.z += lz; triangles.push(Arc::new(Triangle::new(t0.v0, t0.v1, t0.v2))); // Recalc normal triangles.push(Arc::new(Triangle::new(t1.v0, t1.v1, t1.v2))); } if z == size - 2 && x == size - 2 { let (mut t0, mut t1) = make_square_for(x+1, z+1, size, &vertices); - t0.v0.x = t0.v0.x + lx; - t0.v1.x = t0.v1.x + lx; - t1.v1.x = t1.v1.x + lx; - t0.v0.z = t0.v0.z + lz; - t0.v2.z = t0.v2.z + lz; - t1.v0.z = t1.v0.z + lz; + t0.v0.x += lx; + t0.v1.x += lx; + t1.v1.x += lx; + t0.v0.z += lz; + t0.v2.z += lz; + t1.v0.z += lz; triangles.push(Arc::new(Triangle::new(t0.v0, t0.v1, t0.v2))); // Recalc normal triangles.push(Arc::new(Triangle::new(t1.v0, t1.v1, t1.v2))); } } } - return triangles; + triangles } @@ -297,7 +296,7 @@ pub struct OceanGeometry { impl OceanGeometry { pub fn new(o: &Value) -> OceanGeometry { let gravity = SceneFile::parse_number(&o["gravity"], 9.81f64); - let wind = SceneFile::parse_vec2_def(&o, "wind", Vector2::new(40., 30.)); + let wind = SceneFile::parse_vec2_def(o, "wind", Vector2::new(40., 30.)); let time = SceneFile::parse_number(&o["time"],4f64); // Mesh size @@ -376,14 +375,14 @@ impl OceanGeometry { println!(" - OCEAN [A={}, g={}, W={}, t={}, N={}, {}]", scale, gravity, wind, time, lx, fourier_grid_size); println!(" bounded:{}, triangles:{} ", bounds, triangles.len()); - return OceanGeometry { + OceanGeometry { mesh: RepeatingMesh { tile: tree, tile_size: Vector3::new(lx, 0., lz), tile_bounds: bounds, triangle_count: triangles.len(), } - }; + } } fn bounds_of(triangles: &Vec>) -> BBox { @@ -393,21 +392,21 @@ impl OceanGeometry { bb = bb.union(&t.bounds()); } - return bb; + bb } } impl Geometry for OceanGeometry { fn intersects(&self, r: &Ray) -> Option { - return self.mesh.intersects(r); + self.mesh.intersects(r) } fn bounds(&self) -> BBox { - return self.mesh.bounds(); + self.mesh.bounds() } fn primitives(&self) -> u64 { - return self.mesh.triangle_count as u64; + self.mesh.triangle_count as u64 } } @@ -420,8 +419,8 @@ struct OceanMaterial { impl OceanMaterial { pub fn new(o: &Value) -> OceanMaterial { - let deep = SceneFile::parse_color_def(&o, "color", Color::new(0., 0.2, 0.3)); - return OceanMaterial { + let deep = SceneFile::parse_color_def(o, "color", Color::new(0., 0.2, 0.3)); + OceanMaterial { deep_color: deep } } @@ -458,13 +457,13 @@ impl MaterialModel for OceanMaterial { } let reflected = reflect(r.rd, intersection.normal); - return ScatteredRay { + ScatteredRay { attenuate: Color::white(), ray: Some(Ray { ro: intersection.point, rd: reflected }) - }; + } } } @@ -474,9 +473,9 @@ pub fn create_ocean(opts: &Value) -> SceneObject { if opts["debug"].as_bool().unwrap_or(false) { m = Box::new(NormalShade {}); } - return SceneObject { + SceneObject { geometry: Box::new(o), - medium: Box::new(Solid { m: m}), + medium: Box::new(Solid { m }), } } diff --git a/src/octree.rs b/src/octree.rs index e0d1404..4d7101e 100644 --- a/src/octree.rs +++ b/src/octree.rs @@ -24,7 +24,7 @@ pub struct OctreeNode { } fn vec3_invert(rd: Vector3) -> Vector3 { - return Vector3::new(1.0/rd.x, 1.0/rd.y, 1.0/rd.z); + Vector3::new(1.0/rd.x, 1.0/rd.y, 1.0/rd.z) } type OctreeIntersections = Option>; @@ -32,47 +32,40 @@ type OctreeIntersections = Option>; impl OctreeNode { pub fn is_leaf(&self) -> bool { for i in 0..8 { - match self.children[i as usize] { - Some(_) => { return false }, - None => {} - } + if self.children[i as usize].is_some() { return false } } - return true; + true } pub fn is_empty(&self) -> bool { - return self.items.len() > 0; + self.items.len() > 0 } pub fn len(&self) -> usize { - return self.items.len() + self.items.len() } /// Perform a breadth first search of the tree, and then sort results by distance. - pub fn naive_intersection(&self, r: &Ray, max:f64, min:f64) -> OctreeIntersections { + pub fn naive_intersection(&self, r: &Ray, _max:f64, _min:f64) -> OctreeIntersections { let invrd = vec3_invert(r.rd); if !self.bounds.fast_intersects(&r.ro, &invrd) { - return None - } - - if self.is_leaf(){ - return Some(self.items.clone()); - } - - let intersections = self.children + None + } else if self.is_leaf() { + Some(self.items.clone()) + } else { + let intersections = self.children .iter() .filter(|i| i.is_some()) - .map(|c| c.as_ref().unwrap().naive_intersection(r,max, min)) - .filter(|i| i.is_some()) - .map(|i| i.unwrap()) + .filter_map(|c| c.as_ref().unwrap().naive_intersection(r, _max, _min)) .flatten() .collect::>(); - if intersections.is_empty(){ - return None; + if intersections.is_empty() { + None + } else { + Some(intersections) + } } - return Some(intersections); - } } @@ -83,13 +76,13 @@ impl Octree { // Create a new node, and subdivide into further nodes up until max_depth // or until number of children objects is 0. // - pub fn new(max_depth: usize, b: BBox, items: &Vec>) -> Octree { - let items: Vec> = items.into_iter().cloned().collect(); + pub fn new(max_depth: usize, b: BBox, items: &[Arc]) -> Octree { + let items: Vec> = items.to_vec(); let indices: Vec = (0..items.len()).collect(); - return Octree { + Octree { root: Octree::create_node(0, max_depth, b, indices, &items), - items: items, - }; + items, + } } fn create_node(depth: usize, max_depth: usize, b: BBox, items: Vec, geometries: &Vec>) -> OctreeNode{ @@ -106,7 +99,7 @@ impl Octree { .filter( |x| { cbox.intersects_bbox( &geometries[*x].bounds() ) } ) .collect::>(); - if inside.len() > 0 { + if !inside.is_empty() { let node = Octree::create_node(depth + 1, max_depth, cbox, inside, geometries); children[i as usize] = Some(Box::new(node)); } @@ -115,33 +108,25 @@ impl Octree { OctreeNode { - depth: depth, + depth, bounds: b, - children: children, - items: items, + children, + items, } } pub fn raw_intersection(&self, r: &Ray, max:f64, min:f64) -> Option { - return match self.closest_intersection(r, max, min) { - Some(tupl) => Some(tupl.1), - None => None - } + self.closest_intersection(r, max, min).map(|tupl| tupl.1) } pub fn intersection(&self, r: &Ray, max:f64, min:f64) -> Option<(Arc, RawIntersection)> { - match self.closest_intersection(r, max, min) { - Some(tupl) => { - return Some((self.items[tupl.0].clone(), tupl.1)) - }, - None => None - } + self.closest_intersection(r, max, min).map(|tupl| (self.items[tupl.0].clone(), tupl.1)) } fn closest_intersection(&self, r: &Ray, max:f64, min:f64) -> Option<(usize, RawIntersection)> { - return match self.root.naive_intersection(r, max, min) { + match self.root.naive_intersection(r, max, min) { Some(opts) => self.items_intersection(r,max, min, opts), None => None } @@ -152,21 +137,18 @@ impl Octree { let mut cdist = max; let mut closest = None; for i in items { - match self.items[i].intersects(r) { - Some(x) => { - if x.dist < cdist && x.dist >= min { - cdist = x.dist; - closest = Some((i, x)); - } - }, - None => (), + if let Some(x) = self.items[i].intersects(r) { + if x.dist < cdist && x.dist >= min { + cdist = x.dist; + closest = Some((i, x)); + } } } - return closest; + closest } pub fn bounds(&self) -> BBox { - return self.root.bounds; + self.root.bounds } /* @@ -343,9 +325,9 @@ impl fmt::Display for OctreeNode { let mut p = "".to_string(); for _ in -1 .. self.depth as i64{ - p = p + " "; + p += " "; } - p = p + "|-"; + p += "|-"; for i in 0..8 { match self.children[i as usize].as_ref() { diff --git a/src/paint.rs b/src/paint.rs index 7e3c12b..d995bd0 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -7,7 +7,7 @@ use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; pub fn to_png(ctx: &RenderContext) { let img = image::ImageBuffer::from_fn(ctx.width as u32, ctx.height as u32, |x, y| { - let (r,g,b) = ctx.get_pixel(x as usize, ctx.height - y as usize - 1).to_u8(); + let (r,g,b) = ctx.get_pixel(x as usize, ctx.height - y as usize - 1).as_u8(); image::Rgb([r,g,b]) }); @@ -28,7 +28,7 @@ pub fn poor_mans(ctx: &RenderContext) { buffer.set_color(ColorSpec::new().set_fg(Some(termcol))).expect("Could not set color"); write!(&mut buffer, "█").expect("Could not write"); } - write!(&mut buffer, "\n").expect("Could not write"); + writeln!(&mut buffer).expect("Could not write"); } buffer.set_color(&ColorSpec::new()).expect("Could not set color"); diff --git a/src/participatingmedia.rs b/src/participatingmedia.rs index 82f6a5f..25bc099 100644 --- a/src/participatingmedia.rs +++ b/src/participatingmedia.rs @@ -18,7 +18,7 @@ use crate::scenefile::SceneFile; const BIG_NUMBER:f64 = 1000.; pub fn rand() -> f64 { - return _rand::thread_rng().gen_range(0.,1.); + _rand::thread_rng().gen_range(0.,1.) } pub trait ParticipatingMedium: MaterialModel {} @@ -27,7 +27,7 @@ pub struct Vacuum {} impl ParticipatingMedium for Vacuum {} impl MaterialModel for Vacuum { fn scatter(&self, _r: &Ray, _i: &Intersection, _s: &Scene) -> ScatteredRay { - return ScatteredRay { + ScatteredRay { ray: None, attenuate: Color::white(), } @@ -44,7 +44,7 @@ impl ParticipatingMedium for HomogenousFog{} impl MaterialModel for HomogenousFog { fn scatter(&self, r: &Ray, i: &Intersection, _s: &Scene) -> ScatteredRay { // let amount = i.dist * self.density; - return ScatteredRay { + ScatteredRay { ray: Some(Ray { ro: i.point, rd: (r.rd + (random_point_on_unit_sphere() * self.scatter * rand())).normalize(), @@ -58,19 +58,20 @@ impl Geometry for HomogenousFog { fn intersects(&self, r: &Ray) -> Option { if rand() < self.density { let dist = rand().powf(3.) * BIG_NUMBER; - return Some(RawIntersection { - dist: dist, + Some(RawIntersection { + dist, point: r.ro + r.rd * dist, normal: r.rd, }) + } else { + None } - return None } fn bounds(&self) -> BBox { BBox::new( - Vector3::new(std::f64::MIN, std::f64::MIN, std::f64::MIN), - Vector3::new(std::f64::MAX, std::f64::MAX, std::f64::MAX), + Vector3::new(f64::MIN, f64::MIN, f64::MIN), + Vector3::new(f64::MAX, f64::MAX, f64::MAX), ) } } @@ -85,7 +86,7 @@ impl MaterialModel for LowAltitudeFog { fn scatter(&self, _r: &Ray, _i: &Intersection, _s: &Scene) -> ScatteredRay { //let amount = i.dist * self.density; // TODO - return ScatteredRay { + ScatteredRay { ray: None, attenuate: Color::white(), } @@ -96,11 +97,11 @@ impl MaterialModel for LowAltitudeFog { pub fn create_fog(o: &Value) -> SceneObject { let fog = HomogenousFog { - color: SceneFile::parse_color_def(&o, "color", Color::new(0.1, 0.1, 0.1)), + color: SceneFile::parse_color_def(o, "color", Color::new(0.1, 0.1, 0.1)), density: SceneFile::parse_number(&o["density"], 0.2), scatter: SceneFile::parse_number(&o["scatter"], 0.01), }; - return SceneObject { + SceneObject { geometry: Box::new(fog.clone()), medium: Box::new(Solid { m: Box::new(fog)}), } diff --git a/src/procedural/box_terrain.rs b/src/procedural/box_terrain.rs index 861d780..ff078c3 100644 --- a/src/procedural/box_terrain.rs +++ b/src/procedural/box_terrain.rs @@ -27,15 +27,15 @@ pub struct BoxTerrain { impl Geometry for BoxTerrain { fn intersects(&self, r: &Ray) -> Option { - return self.boxes.raw_intersection(r, f64::INFINITY, 0f64); + self.boxes.raw_intersection(r, f64::INFINITY, 0f64) } fn bounds(&self) -> BBox { - return self.bounds; + self.bounds } fn primitives(&self) -> u64 { - return self.boxes_count as u64; + self.boxes_count as u64 } } @@ -61,7 +61,7 @@ pub fn create_box_terrain() -> SceneObject { let boxes = Octree::new(8, bounds, &boxes_vec); let terrain = BoxTerrain { boxes, boxes_count: boxes_vec.len(), bounds}; - return SceneObject { + SceneObject { geometry: Box::new(terrain), medium: Box::new(Solid { m: Box::new(Lambertian { albedo: Color::new(0.75, 0.75, 0.75) diff --git a/src/procedural/fireworks.rs b/src/procedural/fireworks.rs index 3ad9b84..05f0bd9 100644 --- a/src/procedural/fireworks.rs +++ b/src/procedural/fireworks.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use std::f64; fn rand(rng: &mut StdRng) -> f64 { - return rng.gen_range(0.0, 1.0); + rng.gen_range(0.0, 1.0) } struct Particle { @@ -59,9 +59,10 @@ fn trace_particle(impulse: Ray, time: f64, samples: usize, gravity: f64) -> Vec< }; particles.push(p); } - return particles; + particles } +#[allow(clippy::too_many_arguments)] fn create_particles( rng: &mut StdRng, origin: Vector3, @@ -85,7 +86,7 @@ fn create_particles( }; particles.append(&mut trace_particle(impulse, time, samples, gravity)); } - return particles; + particles } @@ -100,7 +101,7 @@ impl MaterialModel for FireworkMaterial { let actual_intersection = self.particles.intersection(r, f64::INFINITY, 0f64); match actual_intersection { Some((particle, _i)) => { - return ScatteredRay { + ScatteredRay { attenuate: self.color * particle.intensity, ray: None, } @@ -109,7 +110,7 @@ impl MaterialModel for FireworkMaterial { // Should never happen panic!("Firework didn't intersect") } - }; + } } } @@ -118,7 +119,7 @@ pub fn create_firework(o: &Value) -> SceneObject { let mut rng: StdRng = SeedableRng::from_seed([0; 32]); - let center = SceneFile::parse_vec3_def(&o, "center", Vector3::new(0., 10., 0.)); + let center = SceneFile::parse_vec3_def(o, "center", Vector3::new(0., 10., 0.)); let time = SceneFile::parse_number(&o["time"], 0.9); let radius = SceneFile::parse_number(&o["radius"], 10.); let samples = SceneFile::parse_number(&o["samples"], 10.) as usize; @@ -126,7 +127,7 @@ pub fn create_firework(o: &Value) -> SceneObject { let num_particles = SceneFile::parse_number(&o["particles"], 100.) as usize; let upward_bias = SceneFile::parse_number(&o["upward_bias"], 2.); let intensity = SceneFile::parse_number(&o["intensity"], 2.); - let color = SceneFile::parse_color_def(&o, "color", Color::white()) * intensity; + let color = SceneFile::parse_color_def(o, "color", Color::white()) * intensity; let particles = create_particles( &mut rng, @@ -145,11 +146,12 @@ pub fn create_firework(o: &Value) -> SceneObject { .collect(); let geom = Union::new(boxed_particles); - let tree = Octree::new(8, geom.bounds(), &particles.into_iter().map(|p| Arc::new(p)).collect()); + let particle_arcs: Vec> = particles.into_iter().map(Arc::new).collect(); + let tree = Octree::new(8, geom.bounds(), &particle_arcs); let m = Box::new(FireworkMaterial { particles: tree, color }); - return SceneObject { + SceneObject { geometry: Box::new(geom), - medium: Box::new(Solid { m: m}), + medium: Box::new(Solid { m }), } } diff --git a/src/ray.rs b/src/ray.rs index d912248..9f0098e 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -31,16 +31,16 @@ impl fmt::Display for Ray { impl Ray { pub fn transform(&self, t: &Transform3) -> Ray { - return Ray { + Ray { ro: (t * Point3::from(self.ro)).coords, rd: t * self.rd - }; + } } pub fn inverse_transform(&self, t: &Affine3) -> Ray { - return Ray { + Ray { ro: t.inverse_transform_point(&Point3::from(self.ro)).coords, rd: t.inverse_transform_vector(&self.rd) - }; + } } } diff --git a/src/rendercontext.rs b/src/rendercontext.rs index 24e515d..eae0031 100644 --- a/src/rendercontext.rs +++ b/src/rendercontext.rs @@ -47,26 +47,26 @@ pub struct RenderedChunk { fn format_f64(v: f64) -> String { if v > 1000000. { - return format!("{:.2}M", v / 1000000.); + format!("{:.2}M", v / 1000000.) + } else if v > 1000. { + format!("{:.2}K", v / 1000.) + } else { + format!("{:.2}", v) } - if v > 1000. { - return format!("{:.2}K", v / 1000.); - } - return format!("{:.2}", v); } impl RenderContext { pub fn new(width:usize, height:usize, progressive_render: bool, filename: &str) -> RenderContext { let start_time = Instant::now(); let output_filename = String::from(filename).replace(".json", ".png"); - return RenderContext { - image: vec![Color::black(); (width*height) as usize], - samples: vec![0; (width*height) as usize], - width: width, - height: height, + RenderContext { + image: vec![Color::black(); width*height], + samples: vec![0; width*height], + width, + height, rays_cast: 0, start_time, - progressive_render: progressive_render, + progressive_render, pixels_rendered: 0, output_filename, } @@ -77,9 +77,9 @@ impl RenderContext { return; } - let i:usize = (y*self.width + x) as usize; + let i:usize = y*self.width + x; self.image[i] = self.image[i] + c.ignore_nan(); - self.samples[i] = self.samples[i] + samples; + self.samples[i] += samples; self.pixels_rendered += 1; } @@ -95,8 +95,8 @@ impl RenderContext { } pub fn get_pixel(&self, x:usize, y:usize) -> Color { - let i = (y*self.width + x) as usize; - return self.image[i] / self.samples[i].max(1) as f64; + let i = y*self.width + x; + self.image[i] / self.samples[i].max(1) as f64 } /* pub fn get_pixel_array(&self) -> Vec { @@ -118,27 +118,27 @@ impl RenderContext { let elapsed = Instant::now() - self.start_time; print!("\n==========================================\n"); - print!("| Rays Cast: {}\n", self.rays_cast); - print!("| Elapsed Time: {:?}\n", elapsed); - print!("| Rays per sec: {:.2}\n", self.rays_cast as f64 / elapsed.as_secs_f64()); - print!("==========================================\n"); + println!("| Rays Cast: {}", self.rays_cast); + println!("| Elapsed Time: {:?}", elapsed); + println!("| Rays per sec: {:.2}", self.rays_cast as f64 / elapsed.as_secs_f64()); + println!("=========================================="); } pub fn progress(&self, s: &Scene) -> String { let elapsed = Instant::now() - self.start_time; - return format!("{:.2}s {} rays cast ({} RPS), {} Rays per pixel, {}%, {} threads", + format!("{:.2}s {} rays cast ({} RPS), {} Rays per pixel, {}%, {} threads", elapsed.as_secs_f64(), format_f64(self.rays_cast as f64), format_f64(self.rays_cast as f64 / elapsed.as_secs_f64()), format_f64(self.rays_cast as f64 / self.pixels_rendered as f64), format_f64(self.progress_percentage(s)), - rayon::current_num_threads()); + rayon::current_num_threads()) } pub fn progress_percentage(&self, s: &Scene) -> f64 { - (self.pixels_rendered as f64 / (self.width * self.height * s.render.supersamples as usize) as f64) * 100. + (self.pixels_rendered as f64 / (self.width * self.height * s.render.supersamples) as f64) * 100. } pub fn iter(&self, s: &Scene) -> impl Iterator + '_ { @@ -147,21 +147,21 @@ impl RenderContext { let chunk_size = s.render.chunk_size; let chunk_layers = s.render.supersamples / s.render.samples_per_chunk; let samples = s.render.samples_per_chunk; - return (0 .. chunk_layers) - .map(move |_x| + (0 .. chunk_layers) + .flat_map(move |_x| RenderIterator { i: 0, width, height, chunk_size, - samples: samples, - }).flatten(); + samples, + }) } } impl RenderableChunk { pub fn width(&self) -> usize { - return self.xmax - self.xmin; + self.xmax - self.xmin } pub fn render(&self, s: &Scene) -> RenderedChunk { @@ -171,14 +171,14 @@ impl RenderableChunk { let mut rays_cast = 0; for y in self.ymin .. self.ymax { for x in self.xmin .. self.xmax { - let (cast, psamples, pixel) = render_pixel(x, y, self.supersamples, &s); + let (cast, psamples, pixel) = render_pixel(x, y, self.supersamples, s); pixels.push(pixel); samples.push(psamples); - rays_cast += cast as u64; + rays_cast += cast; } } - return RenderedChunk { + RenderedChunk { pixels, samples, rays_cast } } @@ -198,46 +198,44 @@ impl Iterator for RenderIterator { if self.height - y > self.chunk_size { if self.width - x > self.chunk_size { - self.i = self.i + self.chunk_size; - return Some(RenderableChunk { + self.i += self.chunk_size; + Some(RenderableChunk { xmin: x, xmax: x + self.chunk_size, ymin: y, ymax: y + self.chunk_size, supersamples: self.samples, - }); + }) } else { // Increment down a row self.i = (self.i - x) + (self.width * self.chunk_size); // return remainder of x - return Some(RenderableChunk { + Some(RenderableChunk { xmin: x , xmax: self.width, ymin: y, ymax: y + self.chunk_size, supersamples: self.samples, - }); + }) } + } else if self.width - x > self.chunk_size { + self.i += self.chunk_size; + Some(RenderableChunk { + xmin: x, + xmax: x + self.chunk_size, + ymin: y, + ymax: self.height, + supersamples: self.samples, + }) } else { - if self.width - x > self.chunk_size { - self.i = self.i + self.chunk_size; - return Some(RenderableChunk { - xmin: x, - xmax: x + self.chunk_size, - ymin: y, - ymax: self.height, - supersamples: self.samples, - }); - } else { - self.i = (self.i - x) + self.chunk_size * self.width; - return Some(RenderableChunk { - xmin: x , - xmax: self.width, - ymin: y, - ymax: self.height, - supersamples: self.samples, - }); - } + self.i = (self.i - x) + self.chunk_size * self.width; + Some(RenderableChunk { + xmin: x , + xmax: self.width, + ymin: y, + ymax: self.height, + supersamples: self.samples, + }) } } } @@ -256,11 +254,11 @@ fn render_pixel(x: usize, y: usize, max_samples: usize, s: &Scene) -> (u64, usiz y as f64 / (s.image.height as f64), sx as f64 / (max_samples as f64) * 1. / (s.image.width as f64), sy as f64 / (max_samples as f64) * 1. / (s.image.height as f64)) - , 0, &s); - cast = cast + rays_cast; + , 0, s); + cast += rays_cast; pixel = pixel + c; - samples = samples + 1; + samples += 1; } } - return (cast, samples, pixel) + (cast, samples, pixel) } diff --git a/src/scenefile.rs b/src/scenefile.rs index 06b00a2..226d9ac 100644 --- a/src/scenefile.rs +++ b/src/scenefile.rs @@ -19,7 +19,6 @@ use std::sync::Arc; use crate::sceneobject::SceneObject; use serde_json::{Value, Map}; use crate::scene::{Scene, ImageOpts, RenderOpts}; -use serde_json; use std::io::prelude::*; use std::fs::File; use crate::material::model::MaterialModel; @@ -57,88 +56,85 @@ pub struct SceneFile { impl SceneFile { pub fn parse_number(v: &Value, default: f64) -> f64 { match v.as_f64(){ - Some(x) => return x, - None => return default + Some(x) => x, + None => default } } pub fn parse_int(v: &Value, default: usize) -> usize { match v.as_i64(){ - Some(x) => return x as usize, - None => return default + Some(x) => x as usize, + None => default } } pub fn parse_string(v: &Value) -> String { - return v.as_str().unwrap().to_string(); // This is pretty nasty, shame serde + v.as_str().unwrap().to_string()// This is pretty nasty, shame serde } pub fn parse_vec3(v: &Value) -> Vector3 { - return Vector3::new(v[0].as_f64().unwrap(), + Vector3::new(v[0].as_f64().unwrap(), v[1].as_f64().unwrap(), - v[2].as_f64().unwrap()); + v[2].as_f64().unwrap()) } pub fn parse_vec3_def(v: &Value, k: &str, def: Vector3) -> Vector3 { - match &v.get(&k) { + match &v.get(k) { Some(x) => SceneFile::parse_vec3(x), - None => return def + None => def } } pub fn parse_vec2(v: &Value) -> Vector2 { - return Vector2::new(v[0].as_f64().unwrap(), - v[1].as_f64().unwrap()); + Vector2::new(v[0].as_f64().unwrap(), + v[1].as_f64().unwrap()) } pub fn parse_vec2_def(v: &Value, k: &str, def: Vector2) -> Vector2 { - match &v.get(&k) { + match &v.get(k) { Some(x) => SceneFile::parse_vec2(x), - None => return def + None => def } } pub fn parse_color(v: &Value) -> Color { - return Color::new(v[0].as_f64().unwrap(), + Color::new(v[0].as_f64().unwrap(), v[1].as_f64().unwrap(), - v[2].as_f64().unwrap()); + v[2].as_f64().unwrap()) } pub fn parse_color_def(v: &Value, k: &str, def: Color) -> Color { - match &v.get(&k) { + match &v.get(k) { Some(x) => SceneFile::parse_color(x), - None => return def + None => def } } pub fn parse_camera(c: Value, width: u32, height: u32) -> camera::FlatLensCamera { - return camera::FlatLensCamera::new( + camera::FlatLensCamera::new( SceneFile::parse_vec3(&c["lookat"]), SceneFile::parse_vec3(&c["location"]), SceneFile::parse_vec3(&c["up"]), c["angle"].as_f64().unwrap(), width, height, SceneFile::parse_number(&c["aperture"], 0.2) - ); + ) } pub fn parse_objects(objs: Vec, materials: &Map, media: &Map) ->Vec> { let mut objects: Vec> = Vec::new(); for obj in objs { - match SceneFile::parse_object(obj, &materials, &media) { - Some(x) => objects.push(x), - None => {}, - } + if let Some(x) = SceneFile::parse_object(obj, materials, media) { objects.push(x) } } - return objects + objects } pub fn parse_object_medium(o: &Value, materials: &Map, media: &Map ) -> Box { match &o.get("medium") { Some(mid) => { - return SceneFile::parse_medium_ref(mid, materials, media).unwrap() + SceneFile::parse_medium_ref(mid, materials, media).unwrap() }, None => { // Check if material is specified @@ -156,11 +152,11 @@ impl SceneFile { // Default case - just use the referenced material let m = SceneFile::parse_material_ref(material_key, materials).unwrap(); - return Box::new(Solid { m: m }) + Box::new(Solid { m }) } else { // No material or medium specified let default_material = Box::new(Lambertian { albedo: Color::white() }); - return Box::new(Solid { m: default_material }) + Box::new(Solid { m: default_material }) } } } @@ -192,9 +188,9 @@ impl SceneFile { let geom = SceneFile::parse_geometry(&o); let m = SceneFile::parse_object_medium(&o, materials, media); - if geom.is_some(){ + if let Some(geometry) = geom { return Some(Arc::new(SceneObject { - geometry: geom.unwrap(), + geometry, medium: m })); } @@ -206,57 +202,57 @@ impl SceneFile { //return None } pub fn parse_skysphere(o: &Value) -> SceneObject { - return create_sky_sphere(o); + create_sky_sphere(o) } pub fn parse_box_terrain(_o: &Value) -> SceneObject { - return create_box_terrain(); + create_box_terrain() } pub fn parse_geometry (o: &Value) -> Option> { let t = o["type"].as_str().unwrap(); if t == "sphere" { - return Some(SceneFile::parse_sphere(&o)); + return Some(SceneFile::parse_sphere(o)); } if t == "triangle" { - return Some(SceneFile::parse_triangle(&o)); + return Some(SceneFile::parse_triangle(o)); } if t == "mesh" { - return Some(SceneFile::parse_mesh(&o)); + return Some(SceneFile::parse_mesh(o)); } if t == "smoothmesh" { - return Some(SceneFile::parse_smoothmesh(&o)); + return Some(SceneFile::parse_smoothmesh(o)); } if t == "box" { - return Some(SceneFile::parse_box(&o)); + return Some(SceneFile::parse_box(o)); } if t == "plane" { - return Some(SceneFile::parse_plane(&o)); + return Some(SceneFile::parse_plane(o)); } if t == "rotate" { - return Some(SceneFile::parse_rotation(&o)); + return Some(SceneFile::parse_rotation(o)); } if t == "difference" { - return Some(SceneFile::parse_difference(&o)); + return Some(SceneFile::parse_difference(o)); } - return None + None } pub fn parse_difference(o: &Value) -> Box { let a = SceneFile::parse_geometry(&o["a"]).unwrap(); // Panic if fails let b = SceneFile::parse_geometry(&o["b"]).unwrap(); - return Box::new(Difference { + Box::new(Difference { a: Primitive { item: a }, b: Primitive { item: b }, - }); + }) } pub fn parse_rotation(o: &Value) -> Box { @@ -264,44 +260,44 @@ impl SceneFile { let roll = SceneFile::parse_number(&o["roll"], 0.).to_radians(); let pitch = SceneFile::parse_number(&o["pitch"], 0.).to_radians(); let yaw = SceneFile::parse_number(&o["yaw"], 0.).to_radians(); - return Box::new(Transform::rotate(a, roll, pitch, yaw)); + Box::new(Transform::rotate(a, roll, pitch, yaw)) } pub fn parse_mesh(o: &Value) -> Box { - return Box::new(Mesh::from_obj( + Box::new(Mesh::from_obj( SceneFile::parse_string(&o["src"]), - SceneFile::parse_vec3_def(&o, "scale", Vector3::new(1., 1., 1.)))); + SceneFile::parse_vec3_def(o, "scale", Vector3::new(1., 1., 1.)))) } pub fn parse_smoothmesh(o: &Value) -> Box { - return Box::new(SmoothMesh::from_obj( + Box::new(SmoothMesh::from_obj( SceneFile::parse_string(&o["src"]), - SceneFile::parse_vec3_def(&o, "scale", Vector3::new(1., 1., 1.)))); + SceneFile::parse_vec3_def(o, "scale", Vector3::new(1., 1., 1.)))) } pub fn parse_sphere(o: &Value) -> Box { - return Box::new(Sphere::new( + Box::new(Sphere::new( SceneFile::parse_vec3(&o["location"]), - o["radius"].as_f64().unwrap())); + o["radius"].as_f64().unwrap())) } pub fn parse_box(o: &Value) -> Box{ - return Box::new(BBox::new( + Box::new(BBox::new( SceneFile::parse_vec3(&o["min"]), SceneFile::parse_vec3(&o["max"]))) } pub fn parse_triangle(o: &Value) -> Box { - return Box::new(Triangle::new( + Box::new(Triangle::new( SceneFile::parse_vec3(&o["v0"]), SceneFile::parse_vec3(&o["v1"]), - SceneFile::parse_vec3(&o["v2"]))); + SceneFile::parse_vec3(&o["v2"]))) } pub fn parse_plane(o: &Value) -> Box { - return Box::new(Plane { + Box::new(Plane { y: SceneFile::parse_number(&o["y"], 0.), - }); + }) } pub fn parse_checkeredplane(o: &Value, m: Box) -> SceneObject { @@ -418,7 +414,7 @@ impl SceneFile { let t = o["type"].as_str().unwrap(); if t == "solid" { let m = SceneFile::parse_material_ref(&o["material"], materials).unwrap(); - return Some(Box::new(Solid { m: m })); + return Some(Box::new(Solid { m })); } if t == "checkered-y-plane" { @@ -427,7 +423,7 @@ impl SceneFile { let xsize = SceneFile::parse_number(&o["xsize"], 1.); let zsize = SceneFile::parse_number(&o["zsize"], 1.); return Some(Box::new(CheckeredYPlane { - m1: m1, m2: m2, xsize: xsize, zsize: zsize + m1, m2, xsize, zsize })); } @@ -627,7 +623,7 @@ impl SceneFile { return Some(Box::new(noise_medium)); } - return None + None } pub fn parse_air(_o: &Option) -> Box{ let air: Box = Box::new(Vacuum {}); @@ -636,12 +632,12 @@ impl SceneFile { air = Box::new(HomogenousFog { density: 0.001, color: Color::red() }); } */ - return air; + air } pub fn parse_light(o: &Value) -> Light { - return Light { + Light { position: SceneFile::parse_vec3(&o["location"]), color: Color::white(), intensity: o["intensity"].as_f64().unwrap(), @@ -651,9 +647,9 @@ impl SceneFile { pub fn parse_lights(lights: &Vec) -> Vec { let mut l: Vec = Vec::new(); for light in lights { - l.push(SceneFile::parse_light(&light)); + l.push(SceneFile::parse_light(light)); } - return l + l } pub fn from_scenefile(s: SceneFile) -> Scene { @@ -668,7 +664,7 @@ impl SceneFile { let width = SceneFile::parse_int(&s.width, 640); let height =SceneFile::parse_int(&s.height, 480); - return Scene { + Scene { image: ImageOpts { width, height }, render: RenderOpts { max_depth: SceneFile::parse_int(&s.max_depth, 2), @@ -684,18 +680,18 @@ impl SceneFile { max_bounding, black_threshold: SceneFile::parse_number(&s.shadow_bias, 1e-7f64) , air_medium: SceneFile::parse_air(&s.air), - }; + } } pub fn from_string(s: String) -> Scene { let scene: SceneFile = serde_json::from_str(&s).unwrap(); - return SceneFile::from_scenefile(scene); + SceneFile::from_scenefile(scene) } pub fn from_file(filename: &str) -> Scene { let mut scenefile = File::open(filename).unwrap(); let mut contents = String::new(); scenefile.read_to_string(&mut contents).unwrap(); - return SceneFile::from_string(contents); + SceneFile::from_string(contents) } } diff --git a/src/scenegraph.rs b/src/scenegraph.rs index 3c51f1d..6506b46 100644 --- a/src/scenegraph.rs +++ b/src/scenegraph.rs @@ -37,7 +37,7 @@ impl SceneGraph { let tree = Octree::new( max_depth, - scene_bounds.clone(), + scene_bounds, &items, ); @@ -56,14 +56,14 @@ impl SceneGraph { self.items .iter() .map(|x| x.geometry.primitives()) - .fold(0, |acc, x| acc + x) + .sum::() } pub fn nearest_intersection(&self, r: &Ray, max:f64, min:f64) -> Option { - return match self.nearest_raw_intersection(r, max, min) { + match self.nearest_raw_intersection(r, max, min) { Some(tupl) =>{ let scene_obj = tupl.0.clone(); - return Some( + Some( Intersection { dist: tupl.1.dist, point: tupl.1.point, @@ -72,7 +72,7 @@ impl SceneGraph { }) }, None => None - }; + } } @@ -91,7 +91,7 @@ impl SceneGraph { if inf.1.dist < tree.1.dist { return Some(inf); } - return Some(tree); + Some(tree) } pub fn naive_intersection_infinites(&self, r: &Ray, max:f64, min:f64) -> Option<(Arc, RawIntersection)> { @@ -109,17 +109,14 @@ impl SceneGraph { None => (), } */ - match o.intersects(r) { - Some(x) => { - if x.dist < cdist && x.dist >= min { - cdist = x.dist; - closest = Some((o.clone(), x)); - } - }, - None => (), + if let Some(x) = o.intersects(r) { + if x.dist < cdist && x.dist >= min { + cdist = x.dist; + closest = Some((o.clone(), x)); + } } } - return closest; + closest } } diff --git a/src/sceneobject.rs b/src/sceneobject.rs index 47ef297..28dcc87 100644 --- a/src/sceneobject.rs +++ b/src/sceneobject.rs @@ -29,10 +29,10 @@ impl SceneObject { impl Geometry for SceneObject { fn intersects(&self, r: &Ray) -> Option { - return self.geometry.intersects(r); + self.geometry.intersects(r) } fn bounds(&self) -> BBox { - return self.geometry.bounds(); + self.geometry.bounds() } } diff --git a/src/shapes/bbox.rs b/src/shapes/bbox.rs index 3792292..6d4682e 100644 --- a/src/shapes/bbox.rs +++ b/src/shapes/bbox.rs @@ -52,7 +52,7 @@ fn find_min_max(min: &Vector3, max: &Vector3, ro: &Vector3, invrd let tmin = t1.min(t2).max(t3.min(t4)).max(t5.min(t6)); let tmax = t1.max(t2).min(t3.max(t4)).min(t5.max(t6)); - return (tmin, tmax); + (tmin, tmax) } impl BBox { @@ -61,10 +61,10 @@ impl BBox { } pub fn min() -> BBox { - return BBox::new( + BBox::new( Vector3::new(0., 0., 0.), Vector3::new(0., 0., 0.) - ); + ) } // Cast the enum here @@ -91,7 +91,7 @@ impl BBox { let ymax = bounds.min.y + (if yoffs !=0 { ydiff } else { ydiff * 0.5 }); let zmax = bounds.min.z + (if zoffs !=0 { zdiff } else { zdiff * 0.5 }); - return BBox { + BBox { min: Point3::new(xmin, ymin, zmin), max: Point3::new(xmax, ymax, zmax), } @@ -99,7 +99,7 @@ impl BBox { pub fn fast_intersects(&self, ro: &Vector3, invrd: &Vector3) -> bool { //http://tavianator.com/fast-branchless-raybounding-box-intersections/ - let (tmin, tmax) = find_min_max(&self.min.coords, &self.max.coords, &ro, &invrd); + let (tmin, tmax) = find_min_max(&self.min.coords, &self.max.coords, ro, invrd); // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us if tmax < 0. { @@ -111,7 +111,7 @@ impl BBox { return false; } - return true + true } pub fn transform(&self, transform: &na::Transform3) -> BBox { @@ -120,146 +120,170 @@ impl BBox { (transform * self.min).coords, (transform * self.min).coords ); - ret = ret.union_point(&(transform * &Point3::new(self.max.x, self.min.y, self.min.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.min.x, self.max.y, self.min.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.min.x, self.min.y, self.max.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.max.x, self.max.y, self.min.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.max.x, self.min.y, self.max.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.min.x, self.max.y, self.max.z)).coords); - ret = ret.union_point(&(transform * &Point3::new(self.max.x, self.max.y, self.max.z)).coords); - return ret; + ret = ret.union_point(&(transform * Point3::new(self.max.x, self.min.y, self.min.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.min.x, self.max.y, self.min.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.min.x, self.min.y, self.max.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.max.x, self.max.y, self.min.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.max.x, self.min.y, self.max.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.min.x, self.max.y, self.max.z)).coords); + ret = ret.union_point(&(transform * Point3::new(self.max.x, self.max.y, self.max.z)).coords); + ret } pub fn entry_face(&self, r: &Ray) -> Option { let invrd = vec3_invert(&r.rd); - if !self.fast_intersects(&r.ro, &invrd) { return None; } - let xmin = if r.rd.x >= 0. { self.min.x } else { self.max.x }; - let ymin = if r.rd.y >= 0. { self.min.y } else { self.max.y }; - let zmin = if r.rd.z >= 0. { self.min.z } else { self.max.z }; - - let tx0 = (xmin - r.ro.x) * invrd.x; - let ty0 = (ymin - r.ro.y) * invrd.y; - let tz0 = (zmin - r.ro.z) * invrd.z; - - if tx0 > ty0 { - if tx0 > tz0 { - // Plane X -> Left or Right depending on ray direction - if r.rd.x > 0. { - return Some(BoxFace::Left); - } - return Some(BoxFace::Right); - } + if !self.fast_intersects(&r.ro, &invrd) { + None } else { - if ty0 > tz0 { + let xmin = if r.rd.x >= 0. { self.min.x } else { self.max.x }; + let ymin = if r.rd.y >= 0. { self.min.y } else { self.max.y }; + let zmin = if r.rd.z >= 0. { self.min.z } else { self.max.z }; + + let tx0 = (xmin - r.ro.x) * invrd.x; + let ty0 = (ymin - r.ro.y) * invrd.y; + let tz0 = (zmin - r.ro.z) * invrd.z; + + if tx0 > ty0 { + if tx0 > tz0 { + // Plane X -> Left or Right depending on ray direction + if r.rd.x > 0. { + Some(BoxFace::Left) + } else { + Some(BoxFace::Right) + } + } else { + // tz0 is largest + if r.rd.z > 0. { + Some(BoxFace::Front) + } else { + Some(BoxFace::Back) + } + } + } else if ty0 > tz0 { // Plane Y -> Top or Bottom if r.rd.y > 0. { - return Some(BoxFace::Bottom); + Some(BoxFace::Bottom) + } else { + Some(BoxFace::Top) } - return Some(BoxFace::Top); - } - } - // Plane Z -> Front or Back - if r.rd.z > 0. { - return Some(BoxFace::Front); + } else { + // tz0 is largest + if r.rd.z > 0. { + Some(BoxFace::Front) + } else { + Some(BoxFace::Back) + } + } } - return Some(BoxFace::Back); } pub fn exit_face(&self, r: &Ray) -> Option { let invrd = vec3_invert(&r.rd); - if !self.fast_intersects(&r.ro, &invrd) { return None; } - let xmax = if r.rd.x >= 0. { self.max.x } else { self.min.x }; - let ymax = if r.rd.y >= 0. { self.max.y } else { self.min.y }; - let zmax = if r.rd.z >= 0. { self.max.z } else { self.min.z }; - - let tx1 = (xmax - r.ro.x) * invrd.x; - let ty1 = (ymax - r.ro.y) * invrd.y; - let tz1 = (zmax - r.ro.z) * invrd.z; - - if tx1 < ty1 { - if tx1 < tz1 { - // Plane X -> Left or Right depending on ray direction - if r.rd.x > 0. { - return Some(BoxFace::Right); - } - return Some(BoxFace::Left); - } + if !self.fast_intersects(&r.ro, &invrd) { + None } else { - if ty1 < tz1 { + let xmax = if r.rd.x >= 0. { self.max.x } else { self.min.x }; + let ymax = if r.rd.y >= 0. { self.max.y } else { self.min.y }; + let zmax = if r.rd.z >= 0. { self.max.z } else { self.min.z }; + + let tx1 = (xmax - r.ro.x) * invrd.x; + let ty1 = (ymax - r.ro.y) * invrd.y; + let tz1 = (zmax - r.ro.z) * invrd.z; + + if tx1 < ty1 { + if tx1 < tz1 { + // Plane X -> Left or Right depending on ray direction + if r.rd.x > 0. { + Some(BoxFace::Right) + } else { + Some(BoxFace::Left) + } + } else { + // tz1 is smallest + if r.rd.z > 0. { + Some(BoxFace::Back) + } else { + Some(BoxFace::Front) + } + } + } else if ty1 < tz1 { // Plane Y -> Top or Bottom if r.rd.y > 0. { - return Some(BoxFace::Top); + Some(BoxFace::Top) + } else { + Some(BoxFace::Bottom) } - return Some(BoxFace::Bottom); - } - } - // Plane Z -> Front or Back - if r.rd.z > 0. { - return Some(BoxFace::Back); + } else { + // tz1 is smallest + if r.rd.z > 0. { + Some(BoxFace::Back) + } else { + Some(BoxFace::Front) + } + } } - return Some(BoxFace::Front); } pub fn mid(&self) -> Vector3 { Vector3::new( - &self.min.x + (&self.max.x - &self.min.x)/2f64, - &self.min.y + (&self.max.y - &self.min.y)/2f64, - &self.min.z + (&self.max.z - &self.min.z)/2f64, + self.min.x + (self.max.x - self.min.x)/2f64, + self.min.y + (self.max.y - self.min.y)/2f64, + self.min.z + (self.max.z - self.min.z)/2f64, ) } pub fn size(&self) -> Vector3 { - return self.max - self.min; + self.max - self.min } - pub fn intersects_bbox(&self, b: &BBox) -> bool{ - if &self.max.x < &b.min.x { return false; } // self is left of b - if &self.min.x > &b.max.x { return false; }// self is right of b - if &self.max.y < &b.min.y { return false; }// self is above b - if &self.min.y > &b.max.y { return false; }// self is below b - if &self.max.z < &b.min.z { return false; }// self is behind b - if &self.min.z > &b.max.z { return false; }// self is in front of b - return true; // boxes overlap + pub fn intersects_bbox(&self, b: &BBox) -> bool { + // Check if there's any separation along any axis + !(self.max.x < b.min.x || // self is left of b + self.min.x > b.max.x || // self is right of b + self.max.y < b.min.y || // self is above b + self.min.y > b.max.y || // self is below b + self.max.z < b.min.z || // self is behind b + self.min.z > b.max.z) // self is in front of b } pub fn union(self, b: &BBox) -> BBox { - let mut o = self.clone(); - if &self.min.x > &b.min.x { o.min.x = b.min.x; } - if &self.max.x < &b.max.x { o.max.x = b.max.x; } - if &self.min.y > &b.min.y { o.min.y = b.min.y; } - if &self.max.y < &b.max.y { o.max.y = b.max.y; } - if &self.min.z > &b.min.z { o.min.z = b.min.z; } - if &self.max.z < &b.max.z { o.max.z = b.max.z; } - return o; + let mut o = self; + if self.min.x > b.min.x { o.min.x = b.min.x; } + if self.max.x < b.max.x { o.max.x = b.max.x; } + if self.min.y > b.min.y { o.min.y = b.min.y; } + if self.max.y < b.max.y { o.max.y = b.max.y; } + if self.min.z > b.min.z { o.min.z = b.min.z; } + if self.max.z < b.max.z { o.max.z = b.max.z; } + o } pub fn union_point(self, p: &Vector3) -> BBox{ - let mut o = self.clone(); - if &self.min.x > &p.x { o.min.x = p.x; } - if &self.max.x < &p.x { o.max.x = p.x; } - if &self.min.y > &p.y { o.min.y = p.y; } - if &self.max.y < &p.y { o.max.y = p.y; } - if &self.min.z > &p.z { o.min.z = p.z; } - if &self.max.z < &p.z { o.max.z = p.z; } - return o; + let mut o = self; + if self.min.x > p.x { o.min.x = p.x; } + if self.max.x < p.x { o.max.x = p.x; } + if self.min.y > p.y { o.min.y = p.y; } + if self.max.y < p.y { o.max.y = p.y; } + if self.min.z > p.z { o.min.z = p.z; } + if self.max.z < p.z { o.max.z = p.z; } + o } pub fn contains(self, b: &BBox) -> bool { - if self.min.x > b.min.x { return false; } - if self.min.y > b.min.y { return false; } - if self.min.z > b.min.z { return false; } - if self.max.x < b.max.x { return false; } - if self.max.y < b.max.y { return false; } - if self.max.z < b.max.z { return false; } - return true; + // Check if all min/max constraints are met + self.min.x <= b.min.x && + self.min.y <= b.min.y && + self.min.z <= b.min.z && + self.max.x >= b.max.x && + self.max.y >= b.max.y && + self.max.z >= b.max.z } pub fn contains_point(self, pt: &Vector3) -> bool { - if pt.x < self.min.x || pt.x > self.max.x { return false; } - if pt.y < self.min.y || pt.y > self.max.y { return false; } - if pt.z < self.min.z || pt.z > self.max.z { return false; } - return true; + // Point is inside if it's within all axis bounds + pt.x >= self.min.x && pt.x <= self.max.x && + pt.y >= self.min.y && pt.y <= self.max.y && + pt.z >= self.min.z && pt.z <= self.max.z } } @@ -278,7 +302,7 @@ impl fmt::Display for BBox { } fn vec3_invert(rd: &Vector3) -> Vector3 { - return Vector3::new(1.0/rd.x, 1.0/rd.y, 1.0/rd.z); + Vector3::new(1.0/rd.x, 1.0/rd.y, 1.0/rd.z) } @@ -286,34 +310,35 @@ impl Geometry for BBox { fn intersects(&self, r: &Ray) -> Option { let invrd = vec3_invert(&r.rd); if !self.fast_intersects(&r.ro, &invrd) { - return None + None + } else { + let (tmin, _tmax) = find_min_max(&self.min.coords, &self.max.coords, &r.ro, &invrd); + let dist = tmin; + let point = r.ro + (r.rd * dist); + let center = na::center(&self.min, &self.max); + let p = (point - center.coords).normalize().component_div(&(self.max - self.min)); + let ndir = p.iamax(); + let mut normal = Vector3::new(0.,0.,0.); + normal[ndir] = if p[ndir].is_sign_positive() { 1. } else { -1. }; + + Some(RawIntersection { + point, + dist, + normal + }) } - let (tmin, _tmax) = find_min_max(&self.min.coords, &self.max.coords, &r.ro, &invrd); - let dist = tmin; - let point = r.ro + (r.rd * dist); - let center = na::center(&self.min, &self.max); - let p = (point - center.coords).normalize().component_div(&(self.max - self.min)); - let ndir = p.iamax(); - let mut normal = Vector3::new(0.,0.,0.); - normal[ndir] = if p[ndir].is_sign_positive() { 1. } else { -1. }; - - return Some(RawIntersection { - point, - dist, - normal - }); } fn bounds(&self) -> BBox { - return self.clone() + *self } fn fast_intersects(&self, r: &Ray) -> bool { - return BBox::fast_intersects(&self, &r.ro, &vec3_invert(&r.rd)); + BBox::fast_intersects(self, &r.ro, &vec3_invert(&r.rd)) } fn inside(&self, p: &Vector3) -> bool { - return self.contains_point(p); + self.contains_point(p) } } @@ -334,8 +359,8 @@ mod tests { rd: Vector3::new(1.4, 1., 1.1), }; - assert!((&b.entry_face(&r).unwrap() == &BoxFace::Bottom)); - assert!((&b.exit_face(&r).unwrap() == &BoxFace::Right)); + assert!((b.entry_face(&r).unwrap() == BoxFace::Bottom)); + assert!((b.exit_face(&r).unwrap() == BoxFace::Right)); } #[test] @@ -350,8 +375,8 @@ mod tests { rd: Vector3::new(0., 1., 0.), }; - assert!((&b.entry_face(&r).unwrap() == &BoxFace::Bottom)); - assert!((&b.exit_face(&r).unwrap() == &BoxFace::Top)); + assert!((b.entry_face(&r).unwrap() == BoxFace::Bottom)); + assert!((b.exit_face(&r).unwrap() == BoxFace::Top)); } #[test] @@ -366,8 +391,8 @@ mod tests { rd: Vector3::new(0., -1., 0.), }; - assert!((&b.entry_face(&r).unwrap() == &BoxFace::Top)); - assert!((&b.exit_face(&r).unwrap() == &BoxFace::Bottom)); + assert!((b.entry_face(&r).unwrap() == BoxFace::Top)); + assert!((b.exit_face(&r).unwrap() == BoxFace::Bottom)); } #[test] @@ -382,21 +407,21 @@ mod tests { rd: (Vector3::new(3.5, 0., 1.5) - Vector3::new(0., 3.5, 1.5)).normalize(), }; - assert!((&b.entry_face(&r).unwrap() == &BoxFace::Top)); - assert!((&b.exit_face(&r).unwrap() == &BoxFace::Right)); + assert!((b.entry_face(&r).unwrap() == BoxFace::Top)); + assert!((b.exit_face(&r).unwrap() == BoxFace::Right)); let r2 = Ray { ro: Vector3::new(1.5, 3.5, 0.), rd: (Vector3::new(1.5, 0., 3.5) - Vector3::new(1.5, 3.5, 0.)).normalize(), }; - assert!((&b.entry_face(&r2).unwrap() == &BoxFace::Top)); - assert!((&b.exit_face(&r2).unwrap() == &BoxFace::Back)); + assert!((b.entry_face(&r2).unwrap() == BoxFace::Top)); + assert!((b.exit_face(&r2).unwrap() == BoxFace::Back)); let r3 = Ray { ro: Vector3::new(1.5, 3.5, 2.5), rd: (Vector3::new(1.5, 0., 0.) - Vector3::new(1.5, 3.5, 2.5)).normalize(), }; - assert!((&b.entry_face(&r3).unwrap() == &BoxFace::Top)); - assert!((&b.exit_face(&r3).unwrap() == &BoxFace::Front)); + assert!((b.entry_face(&r3).unwrap() == BoxFace::Top)); + assert!((b.exit_face(&r3).unwrap() == BoxFace::Front)); } } diff --git a/src/shapes/csg.rs b/src/shapes/csg.rs index dcb159b..0e916a5 100644 --- a/src/shapes/csg.rs +++ b/src/shapes/csg.rs @@ -13,17 +13,17 @@ type CSGOp = fn(&IntersectionRange, &IntersectionRange) -> Option RawIntersection { - let mut j = i.clone(); + let mut j = i; j.normal = i.normal * -1.; - return j + j } // A U B fn union(a: &IntersectionRange, b: &IntersectionRange) -> Option { if a.0.dist < b.0.dist { - return Some(a.0) + Some(a.0) } else { - return Some(b.0) + Some(b.0) } } @@ -40,24 +40,24 @@ fn difference(a: &IntersectionRange, b: &IntersectionRange) -> Option { if ao.dist < bo.dist { // contained in b - return None + None } else { - return Some(_reflect_normal(bo)) + Some(_reflect_normal(bo)) } }, None => { // Infinite A - return Some(_reflect_normal(bo)) + Some(_reflect_normal(bo)) } } } else { // B is before A - return Some(a.0) + Some(a.0) } }, None => { // B is infinite - return None; + None } } } @@ -80,18 +80,15 @@ impl Primitive { Some(mut x) => { x.dist = (x.point - r.ro).norm(); - return Some(x) + Some(x) }, - None => { return None; } + None => { None} } } fn next_intersection_range(&self, r: &Ray, dist: f64) -> Option { let in_a = self.next_intersection(r, dist); - return match in_a { - Some (x) => Some(IntersectionRange(x, self.next_intersection(r, x.dist))), - None => None - }; + in_a.map(|x| IntersectionRange(x, self.next_intersection(r, x.dist))) } @@ -100,20 +97,13 @@ impl Primitive { let mut bdist = 0.; loop { - let arange = match self.next_intersection_range(r, adist) { - Some(arange) => arange, - None => return None - }; + let arange = self.next_intersection_range(r, adist)?; adist += match arange.1 { Some(x) => x.dist, None => arange.0.dist + 1. // Bigger than entry to infinite obj }; - loop { - let brange = match other.next_intersection_range(r, bdist) { - Some(brange) => brange, - None => break - }; + while let Some(brange) = other.next_intersection_range(r, bdist) { bdist += match brange.1 { Some(x) => x.dist, None => brange.0.dist + 1. // Bigger than entry to infinite obj @@ -130,10 +120,10 @@ impl Primitive { impl Geometry for Primitive { fn intersects(&self, r: &Ray) -> Option { - return self.item.intersects(r); + self.item.intersects(r) } fn bounds(&self) -> BBox { - return self.item.bounds(); + self.item.bounds() } } @@ -151,14 +141,14 @@ impl Union { pub fn new (geometries: Vec>) -> Union { let mut count = 0; let mut bounds = BBox::min() ; - let primitives = geometries.into_iter().map(|g| { + let primitives: Vec> = geometries.into_iter().map(|g| { count += 1; bounds = bounds.union(&g.bounds()); Arc::new(Primitive { item: g }) }).collect(); let tree = Octree::new(8, bounds, &primitives); - return Union { + Union { items: tree, primitives: count, } @@ -167,14 +157,14 @@ impl Union { impl Geometry for Union { fn intersects(&self, r: &Ray) -> Option { - return self.items.raw_intersection(r, f64::INFINITY, 0f64); + self.items.raw_intersection(r, f64::INFINITY, 0f64) } fn bounds(&self) -> BBox { - return self.items.bounds(); + self.items.bounds() } fn primitives(&self) -> u64 { - return self.primitives; + self.primitives } } @@ -192,21 +182,21 @@ fn _find_intersect_iter(a: &Primitive, b: &Primitive, r: &Ray, adist: f64, bdist Some(ib) => { if ia.0.dist < ib.0.dist { // Enter A first - return Some(ia.0); + Some(ia.0) } else { - return _find_intersect_inside_b_iter(a, b, &ia, &ib, r); + _find_intersect_inside_b_iter(a, b, &ia, &ib, r) } } None => { // No B intersection - return Some(ia.0); + Some(ia.0) } } }, None => { // Would never have hit A - return None + None } } } @@ -225,7 +215,7 @@ fn _find_intersect_inside_b_iter( match brange.1 { None => { // That was the last B intersection, B stretches forever. - return None + None }, Some(nb) => { if nb.dist < arange.0.dist { @@ -242,20 +232,20 @@ fn _find_intersect_inside_b_iter( Some(narange) => { // There is another A intersection. print!("!!"); - return _find_intersect_inside_b_iter(a, b, &narange, brange, r); + _find_intersect_inside_b_iter(a, b, &narange, brange, r) }, - None => { return None } + None => { None } } } else { // We're inside a inside b, the b exit is smaller than a exit // Therefore as soon as we leave B we are still in A. // Therefore B exit is intersection - return Some(_reflect_normal(nb)); + Some(_reflect_normal(nb)) } }, None => { // last A intersection, A is infinite, intersect at exit of B - return Some(_reflect_normal(nb)); + Some(_reflect_normal(nb)) } } } @@ -265,11 +255,11 @@ fn _find_intersect_inside_b_iter( impl Geometry for Difference { fn intersects(&self, r: &Ray) -> Option { - return _find_intersect_iter(&self.a, &self.b, r, 0., 0.); + _find_intersect_iter(&self.a, &self.b, r, 0., 0.) //return self.a.apply_csg(r, difference, &self.b); } fn bounds(&self) -> BBox { - return self.a.bounds(); // Can never be bigger than A + self.a.bounds()// Can never be bigger than A } } diff --git a/src/shapes/geometry.rs b/src/shapes/geometry.rs index 24ecffd..9ce1af6 100644 --- a/src/shapes/geometry.rs +++ b/src/shapes/geometry.rs @@ -28,7 +28,7 @@ pub trait Geometry: Sync{ // than just calling intersects. This is only really for cases where you want to avoid // allocation of a RawIntersection object. fn fast_intersects(&self, r: &Ray) -> bool { - return self.intersects(r).is_some(); + self.intersects(r).is_some() } // Number of primitives inside geometry (ie triangles in mesh, circles etc.) diff --git a/src/shapes/infinite.rs b/src/shapes/infinite.rs index d7870f4..7d71231 100644 --- a/src/shapes/infinite.rs +++ b/src/shapes/infinite.rs @@ -8,17 +8,17 @@ pub struct Infinite {} impl Geometry for Infinite{ fn intersects(&self, r: &Ray) -> Option { - return Some(RawIntersection { - dist: std::f64::MAX, - point: r.ro + r.rd * std::f64::MAX, + Some(RawIntersection { + dist: f64::MAX, + point: r.ro + r.rd * f64::MAX, normal: r.rd * -1. }) } fn bounds(&self) -> BBox { BBox::new( - Vector3::new(std::f64::MIN, std::f64::MIN, std::f64::MIN), - Vector3::new(std::f64::MAX, std::f64::MAX, std::f64::MAX), + Vector3::new(f64::MIN, f64::MIN, f64::MIN), + Vector3::new(f64::MAX, f64::MAX, f64::MAX), ) } } diff --git a/src/shapes/mesh.rs b/src/shapes/mesh.rs index 6d8a3e3..d7aefb5 100644 --- a/src/shapes/mesh.rs +++ b/src/shapes/mesh.rs @@ -41,14 +41,14 @@ pub struct Mesh { // A simple triangle collection mesh. impl Mesh { pub fn from_obj(pth: String, scale: Vector3) -> Mesh { - let obj = tobj::load_obj(&Path::new(&pth)); + let obj = tobj::load_obj(Path::new(&pth)); assert!(obj.is_ok()); let (models, _materials) = obj.unwrap(); //println!("# of models: {}", models.len()); //println!("# of materials: {}", materials.len()); let mut triangles = Vec::new(); - for (_i, m) in models.iter().enumerate() { + for m in models.iter() { let mesh = &m.mesh; let positions: Arc>> = Arc::new( mesh.positions @@ -72,9 +72,9 @@ impl Mesh { let bounds = Mesh::bounds_of(&triangles); let tree = Octree::new(8, bounds, &triangles); - return Mesh { + Mesh { triangles: tree, - bounds: bounds, + bounds, triangle_count: triangles.len() } } @@ -86,21 +86,21 @@ impl Mesh { bb = bb.union(&t.bounds()); } - return bb; + bb } } impl Geometry for Mesh { fn intersects(&self, r: &Ray) -> Option { - return self.triangles.raw_intersection(r, f64::INFINITY, 0f64); + self.triangles.raw_intersection(r, f64::INFINITY, 0f64) } fn bounds(&self) -> BBox { - return self.bounds; + self.bounds } fn primitives(&self) -> u64 { - return self.triangle_count as u64; + self.triangle_count as u64 } } @@ -113,14 +113,14 @@ pub struct SmoothMesh { impl SmoothMesh { pub fn from_obj(pth: String, scale: Vector3) -> SmoothMesh { - let obj = tobj::load_obj(&Path::new(&pth)); + let obj = tobj::load_obj(Path::new(&pth)); assert!(obj.is_ok()); let (models, _materials) = obj.unwrap(); //println!("# of models: {}", models.len()); //println!("# of materials: {}", materials.len()); let mut triangles = Vec::new(); - for (_i, m) in models.iter().enumerate() { + for m in models.iter() { let mesh = &m.mesh; if mesh.normals.is_empty() { print!("!! [ Warning in STL parse ] Normals are required for a smooth mesh - skipping {}", m.name); @@ -161,9 +161,9 @@ impl SmoothMesh { let bounds = SmoothMesh::bounds_of(&triangles); let tree = Octree::new(8, bounds, &triangles); - return SmoothMesh { + SmoothMesh { triangles: tree, - bounds: bounds, + bounds, triangle_count: triangles.len() } } @@ -175,21 +175,21 @@ impl SmoothMesh { bb = bb.union(&t.bounds()); } - return bb; + bb } } impl Geometry for SmoothMesh { fn intersects(&self, r: &Ray) -> Option { - return self.triangles.raw_intersection(r, f64::INFINITY, 0f64); + self.triangles.raw_intersection(r, f64::INFINITY, 0f64) } fn bounds(&self) -> BBox { - return self.bounds; + self.bounds } fn primitives(&self) -> u64 { - return self.triangle_count as u64; + self.triangle_count as u64 } } diff --git a/src/shapes/plane.rs b/src/shapes/plane.rs index 2e72912..a0ca8a2 100644 --- a/src/shapes/plane.rs +++ b/src/shapes/plane.rs @@ -23,7 +23,7 @@ impl Geometry for Plane { return Some( RawIntersection { - dist: dist, + dist, point: r.ro + (rdn * dist), normal: norm, }) @@ -35,8 +35,8 @@ impl Geometry for Plane { fn bounds(&self) -> BBox { BBox::new( - Vector3::new(std::f64::MIN, 0., std::f64::MIN), - Vector3::new(std::f64::MAX, std::f64::MIN_POSITIVE, std::f64::MAX), + Vector3::new(f64::MIN, 0., f64::MIN), + Vector3::new(f64::MAX, f64::MIN_POSITIVE, f64::MAX), ) } } diff --git a/src/shapes/repeating_mesh.rs b/src/shapes/repeating_mesh.rs index 205b563..2a79873 100644 --- a/src/shapes/repeating_mesh.rs +++ b/src/shapes/repeating_mesh.rs @@ -36,7 +36,7 @@ impl RepeatingMesh { fn transform_for(&self, stepx: f64, stepz: f64, curr_transform: &Vector3) -> Vector3 { //println!(" : {}x{}", stepx, stepz); - return curr_transform + self.tile_size.component_mul(&Vector3::new(stepx, 0., stepz)); + curr_transform + self.tile_size.component_mul(&Vector3::new(stepx, 0., stepz)) } fn find_tile_transform(&self, r: &Ray, denom: f64, y: f64) -> (Vector3, f64) { @@ -50,22 +50,22 @@ impl RepeatingMesh { let iz = (point.z / self.tile_size.z).floor(); //println!("NEW ---"); let transform = self.transform_for(ix, iz, &Vector3::new(0., 0., 0.)); - return (transform, dist); + (transform, dist) } fn find_next_tile(&self, transformed_ray: &Ray, curr_transform: &Vector3) -> Option> { match self.tile.bounds().exit_face(transformed_ray){ - Some(BoxFace::Top) => return None, - Some(BoxFace::Bottom) => return None, - Some(BoxFace::Left) => return Some(self.transform_for(-1., 0., curr_transform)), - Some(BoxFace::Right) => return Some(self.transform_for(1., 0., curr_transform)), - Some(BoxFace::Front) => return Some(self.transform_for(0., -1., curr_transform)), - Some(BoxFace::Back) => return Some(self.transform_for(0., 1., curr_transform)), + Some(BoxFace::Top) => None, + Some(BoxFace::Bottom) => None, + Some(BoxFace::Left) => Some(self.transform_for(-1., 0., curr_transform)), + Some(BoxFace::Right) => Some(self.transform_for(1., 0., curr_transform)), + Some(BoxFace::Front) => Some(self.transform_for(0., -1., curr_transform)), + Some(BoxFace::Back) => Some(self.transform_for(0., 1., curr_transform)), None => { // did not intersect with this bbox? Should never happen! //panic!("ERR: No intersection - {} - {} {}", self.tile.bounds(), curr_transform, transformed_ray); print!("ERR: No intersection - {} - {} {}", self.tile.bounds(), curr_transform, transformed_ray); - return None; + None } } } @@ -87,20 +87,20 @@ impl RepeatingMesh { match intersects { Some(i) => { - let mut intersection = i.clone(); + let mut intersection = i; // reverse the transform on the intersection - intersection.point = intersection.point + transform; - return Some(intersection); + intersection.point += transform; + Some(intersection) }, None => { - match self.find_next_tile(&transformed_ray, &transform) { + match self.find_next_tile(&transformed_ray, transform) { Some(t) => { - return self.intersect_tile(r, &t, depth + 1); + self.intersect_tile(r, &t, depth + 1) }, None => { - return None; + None } - }; + } } } } @@ -122,14 +122,14 @@ impl Geometry for RepeatingMesh { // preceding rays will intersect the previous tile let (transform, dist) = self.find_tile_transform(r, denom, self.tile_bounds.max.y); if dist < 0. { return None } - return self.intersect_tile(&r, &transform, 1); + return self.intersect_tile(r, &transform, 1); } if r.ro.y < self.tile_bounds.min.y { // Looking up at plane let (transform, dist) = self.find_tile_transform(r, denom, self.tile_bounds.min.y); if dist < 0. { return None } - return self.intersect_tile(&r, &transform, 1); + return self.intersect_tile(r, &transform, 1); } @@ -139,13 +139,13 @@ impl Geometry for RepeatingMesh { let iz = (r.ro.z / self.tile_size.z).floor(); let transform = self.transform_for(ix, iz, &Vector3::new(0., 0., 0.)); - return self.intersect_tile(&r, &transform, 1); + self.intersect_tile(r, &transform, 1) } fn bounds(&self) -> BBox { BBox::new( - Vector3::new(std::f64::MIN, self.tile_bounds.min.y, std::f64::MIN), - Vector3::new(std::f64::MAX, self.tile_bounds.max.y, std::f64::MAX), + Vector3::new(f64::MIN, self.tile_bounds.min.y, f64::MIN), + Vector3::new(f64::MAX, self.tile_bounds.max.y, f64::MAX), ) } } diff --git a/src/shapes/sphere.rs b/src/shapes/sphere.rs index 2b1cf5d..980e8db 100644 --- a/src/shapes/sphere.rs +++ b/src/shapes/sphere.rs @@ -13,8 +13,8 @@ pub struct Sphere { impl Sphere{ pub fn new(center:Vector3, radius: f64) -> Sphere { Sphere { - center: center, - radius: radius, + center, + radius, } } } @@ -51,23 +51,23 @@ impl Geometry for Sphere { let point = r.ro + (r.rd.normalize() * dist); - return Some( + Some( RawIntersection { - dist: dist, - point: point, + dist, + point, normal: (point - self.center).normalize() }) } fn bounds(&self) -> BBox { BBox::new( - Vector3::new(&self.center.x - &self.radius, - &self.center.y - &self.radius, - &self.center.z - &self.radius + Vector3::new(self.center.x - self.radius, + self.center.y - self.radius, + self.center.z - self.radius ), - Vector3::new(&self.center.x + &self.radius, - &self.center.y + &self.radius, - &self.center.z + &self.radius + Vector3::new(self.center.x + self.radius, + self.center.y + self.radius, + self.center.z + self.radius ), ) } diff --git a/src/shapes/transform.rs b/src/shapes/transform.rs index 49973ef..06d2efe 100644 --- a/src/shapes/transform.rs +++ b/src/shapes/transform.rs @@ -15,18 +15,18 @@ pub struct Transform { // Affine transformation (invertible) impl Transform { pub fn new(item: Box) -> Transform { - return Transform { - item: item, + Transform { + item, transform: Affine3::identity() - }; + } } pub fn rotate( item: Box, roll: f64, pitch: f64, yaw: f64 ) -> Transform { - return Transform { - item: item, + Transform { + item, transform: na::convert(Rotation3::from_euler_angles(roll, pitch, yaw)) } } @@ -34,9 +34,9 @@ impl Transform { impl Geometry for Transform { fn intersects(&self, r: &Ray) -> Option { - return self.item.intersects(&r.inverse_transform(&self.transform)); + self.item.intersects(&r.inverse_transform(&self.transform)) } fn bounds(&self) -> BBox { - return self.item.bounds().transform(&na::convert(self.transform)); + self.item.bounds().transform(&na::convert(self.transform)) } } diff --git a/src/shapes/triangle.rs b/src/shapes/triangle.rs index 9e9bd1b..6e69349 100644 --- a/src/shapes/triangle.rs +++ b/src/shapes/triangle.rs @@ -31,24 +31,24 @@ impl Triangle { //let area2 = normal.length(); // Before norm let normal = v0v1.cross(&v0v2).normalize(); //panic_if_nan(normal); - return Triangle { - v0: v0, - v1: v1, - v2: v2, - normal: normal, + Triangle { + v0, + v1, + v2, + normal, } } pub fn new_with_normal(v0: Vector3, v1: Vector3, v2: Vector3, normal: Vector3) -> Triangle{ - return Triangle { - v0: v0, - v1: v1, - v2: v2, - normal: normal, + Triangle { + v0, + v1, + v2, + normal, } } pub fn translate_vec3(&self, v: Vector3) -> Triangle { - return Triangle { + Triangle { v0: self.v0 - v, v1: self.v1 - v, v2: self.v2 - v, @@ -78,7 +78,7 @@ fn intersects_dist(v0: Vector3, v1: Vector3, v2: Vector3, r: &Ray let tvec = r.ro - v0; let u = tvec.dot(&pvec) * inv_det; - if u < 0. || u > 1. { return None }; + if !(0. ..=1.).contains(&u) { return None }; let qvec = tvec.cross(&v0v1); panic_if_nan(qvec); @@ -92,20 +92,17 @@ fn intersects_dist(v0: Vector3, v1: Vector3, v2: Vector3, r: &Ray let point = r.ro + (r.rd.normalize() * dist); return Some(IntersectionPoint { dist, point }) } - return None; + None } impl Geometry for Triangle { fn intersects(&self, r: &Ray) -> Option { - return match intersects_dist(self.v0, self.v1, self.v2, r) { - Some(x) => Some(RawIntersection { + intersects_dist(self.v0, self.v1, self.v2, r).map(|x| RawIntersection { dist: x.dist, point: x.point, normal: self.normal - }), - None => None - } + }) } fn bounds(&self) -> BBox { @@ -153,7 +150,7 @@ impl SmoothTriangle { normalv1: Vector3, normalv2: Vector3 ) -> SmoothTriangle{ - return SmoothTriangle { v0, v1, v2, normalv0, normalv1, normalv2 } + SmoothTriangle { v0, v1, v2, normalv0, normalv1, normalv2 } } /* @@ -175,20 +172,17 @@ impl SmoothTriangle { let a = triangle_area(self.v0, self.v1, p.point) / triangle_area(self.v0, self.v1, self.v2); let b = triangle_area(self.v0, self.v2, p.point) / triangle_area(self.v0, self.v1, self.v2); // We can skip c as a + b + c = 1 - return self.normalv2 * a + self.normalv1 * b + (1. - a - b) * self.normalv0; + self.normalv2 * a + self.normalv1 * b + (1. - a - b) * self.normalv0 } } impl Geometry for SmoothTriangle { fn intersects(&self, r: &Ray) -> Option { - return match intersects_dist(self.v0, self.v1, self.v2, r) { - Some(x) => Some(RawIntersection { + intersects_dist(self.v0, self.v1, self.v2, r).map(|x| RawIntersection { dist: x.dist, point: x.point, normal: self.interpolate_normal(&x) - }), - None => None - } + }) } // Copy of Triangle diff --git a/src/skysphere.rs b/src/skysphere.rs index 6acebe4..0927f3b 100644 --- a/src/skysphere.rs +++ b/src/skysphere.rs @@ -282,8 +282,8 @@ impl MaterialModel for SkyMaterial { let attenuation = Vector3::new((-tau.x).exp(), (-tau.y).exp(), (-tau.z).exp()); // Accumulate contributions for Rayleigh and Mie - rayleigh_sum = rayleigh_sum + attenuation.component_mul(&Vector3::new(rayleigh_depth, rayleigh_depth, rayleigh_depth)); - mie_sum = mie_sum + attenuation.component_mul(&Vector3::new(mie_depth, mie_depth, mie_depth)); + rayleigh_sum += attenuation.component_mul(&Vector3::new(rayleigh_depth, rayleigh_depth, rayleigh_depth)); + mie_sum += attenuation.component_mul(&Vector3::new(mie_depth, mie_depth, mie_depth)); } // Calculate final attenuate value combining Rayleigh and Mie scattering diff --git a/src/trace.rs b/src/trace.rs index d9c72fa..627ff0b 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -10,28 +10,28 @@ pub fn trace (r: &Ray, depth: u64, s: &Scene) -> (u64, Color) { let closest = s.objects.nearest_intersection(r, f64::INFINITY, 0f64); match closest { - Some(x) => return trace_intersection(r, x, depth, s), - None => return (1, s.render.background), + Some(x) => trace_intersection(r, x, depth, s), + None => (1, s.render.background), } } fn trace_sample(r: &Ray, intersection: &Intersection, depth: u64, s: &Scene) -> (u64, Color){ let mut cast = 1; let material = intersection.object.medium.material_at(intersection.point); - let interaction = material.scatter(r, &intersection, s); + let interaction = material.scatter(r, intersection, s); - if depth < s.render.max_depth as u64 && interaction.attenuate.to_vec().norm() > s.black_threshold { + if depth < s.render.max_depth as u64 && interaction.attenuate.as_vec().norm() > s.black_threshold { if let Some(ray) = interaction.ray { let (c, col) = trace(&ray, depth + 1, s); cast += c; - return (cast, interaction.attenuate * col);//.clamp(2.)); // TODO - use emission + return (cast, interaction.attenuate * col); //.clamp(2.)); // TODO - use emission } else { - return (cast, interaction.attenuate) + return (cast, interaction.attenuate); } } // Too many bounce, fallback to color - return (cast, (interaction.attenuate * s.render.background)); + (cast, (interaction.attenuate * s.render.background)) } fn trace_intersection(r: &Ray, intersection: Intersection, depth: u64, scene: &Scene) -> (u64, Color) { @@ -43,8 +43,8 @@ fn trace_intersection(r: &Ray, intersection: Intersection, depth: u64, scene: &S let mut cast = 1; let (c, o) = trace_sample(r, &biased_intersection, depth, scene); - cast = cast + c; - return (cast, o) + cast += c; + (cast, o) }