diff --git a/scene/src/lib.rs b/scene/src/lib.rs index b330dd0..7b950db 100644 --- a/scene/src/lib.rs +++ b/scene/src/lib.rs @@ -18,6 +18,7 @@ struct TriangleNormals { } impl TriangleNormals { + #[inline] fn lerp(&self, u: f32, v: f32) -> Vec3 { ((1.0 - (u + v)) * self.n0 + u * self.n1 + v * self.n2).normalize() } @@ -31,6 +32,7 @@ struct TriangleTexcoords { } impl TriangleTexcoords { + #[inline] fn lerp(&self, u: f32, v: f32) -> Vec2 { (1.0 - (u + v)) * self.uv0 + u * self.uv1 + v * self.uv2 } diff --git a/tracing/src/pathtracer.rs b/tracing/src/pathtracer.rs index c40c967..ca32d9f 100644 --- a/tracing/src/pathtracer.rs +++ b/tracing/src/pathtracer.rs @@ -1,5 +1,3 @@ -use std::ops::RangeInclusive; - use crate::{ image_buffer::ImageBuffer, material::{material_brdf, material_sample, IncomingRay, OutgoingRay}, @@ -8,7 +6,7 @@ use crate::{ }; use geometry::ray::Ray; use glam::{UVec2, Vec3}; -use kdtree::{intersection::KdIntersection, KdNode}; +use kdtree::KdNode; use rand::rngs::SmallRng; use scene::{camera::Pinhole, Scene}; @@ -19,14 +17,6 @@ pub struct Pathtracer { } impl Pathtracer { - fn intersect(&self, ray: &Ray, t_range: RangeInclusive) -> Option { - self.kdtree.intersect(&self.scene.geometries, ray, t_range) - } - - fn intersect_any(&self, ray: &Ray, t_range: RangeInclusive) -> bool { - self.intersect(ray, t_range).is_some() - } - fn trace_ray( &self, mut ray_logger: RayLoggerWithIterationAndPixel, @@ -40,7 +30,9 @@ impl Pathtracer { return accumulated_radiance; } - let intersection = self.intersect(ray, 0.0..=f32::MAX); + let intersection = self + .kdtree + .intersect(&self.scene.geometries, ray, 0.0..=f32::MAX); if intersection.is_none() { ray_logger.log_infinite(ray, accumulated_bounces).unwrap(); return accumulated_radiance + accumulated_transport * self.scene.environment; @@ -69,7 +61,10 @@ impl Pathtracer { .iter() .map(|light| { let shadow_ray = Ray::between(point_above, sample_light(light, rng)); - if self.intersect_any(&shadow_ray, 0.0..=1.0) { + let intersection = + self.kdtree + .intersect(&self.scene.geometries, &shadow_ray, 0.0..=1.0); + if intersection.is_some() { return Vec3::ZERO; } let wo = shadow_ray.direction.normalize(); @@ -89,27 +84,24 @@ impl Pathtracer { &IncomingRay { wi, n, uv }, rng, ); - let next_ray = Ray::new( - if sample.wo.dot(n) >= 0.0 { - point_above - } else { - point_below - }, - sample.wo, - ); - if sample.pdf <= 0.01 { return accumulated_radiance; } - let cosine_term = sample.wo.dot(n).abs(); + let cosine_term = sample.wo.dot(n); let accumulated_transport = - accumulated_transport * sample.brdf * (cosine_term / sample.pdf); - - if accumulated_transport.length() <= 0.01 { + accumulated_transport * sample.brdf * (cosine_term.abs() / sample.pdf); + if accumulated_transport.length_squared() <= 1.0e-4 { return accumulated_radiance; } + let next_start_point = if cosine_term >= 0.0 { + point_above + } else { + point_below + }; + let next_ray = Ray::new(next_start_point, sample.wo); + self.trace_ray( ray_logger, rng, diff --git a/tracing/src/sampling.rs b/tracing/src/sampling.rs index 2645181..dc17232 100644 --- a/tracing/src/sampling.rs +++ b/tracing/src/sampling.rs @@ -10,8 +10,9 @@ pub fn uniform_sample_unit_sphere(rng: &mut SmallRng) -> Vec3 { let z = rng.gen_range(-1.0..1.0); let a = rng.gen_range(0.0..std::f32::consts::TAU); let r = (1.0f32 - z * z).sqrt(); - let x = r * a.cos(); - let y = r * a.sin(); + let (a_sin, a_cos) = a.sin_cos(); + let x = r * a_cos; + let y = r * a_sin; Vec3::new(x, y, z) } @@ -24,8 +25,8 @@ pub fn uniform_sample_unit_sphere(rng: &mut SmallRng) -> Vec3 { // } fn concentric_sample_unit_disk(rng: &mut SmallRng) -> Vec2 { - let x = rng.gen_range(-1.0..=1.0); - let y = rng.gen_range(-1.0..=1.0); + let x = rng.gen_range(-1.0f32..=1.0f32); + let y = rng.gen_range(-1.0f32..=1.0f32); if x == 0.0 && y == 0.0 { return Vec2::ZERO; } @@ -37,8 +38,8 @@ fn concentric_sample_unit_disk(rng: &mut SmallRng) -> Vec2 { (x, y) => (-y, 6.0 - x / y), }; - let theta = theta * std::f32::consts::FRAC_PI_4; - Vec2::new(r * theta.cos(), r * theta.sin()) + let (theta_sin, theta_cos) = (theta * std::f32::consts::FRAC_PI_4).sin_cos(); + Vec2::new(r * theta_cos, r * theta_sin) } pub fn cosine_sample_hemisphere(rng: &mut SmallRng) -> Vec3 {