From 4188adbc336c98afce93ae3d5ae84e5b81627041 Mon Sep 17 00:00:00 2001 From: Wito Wiala Date: Fri, 5 Jun 2026 15:51:06 +0100 Subject: [PATCH] Spring cleaning --- .gitignore | 3 ++ shared/src/core/geometry/bounds.rs | 16 +++++++-- shared/src/core/geometry/cone.rs | 12 +++---- shared/src/core/geometry/ray.rs | 26 +++++++-------- shared/src/core/interaction.rs | 2 ++ shared/src/core/pbrt.rs | 11 +++++-- shared/src/shapes/disk.rs | 6 ++-- shared/src/shapes/sphere.rs | 3 +- shared/src/utils/transform.rs | 4 +-- shared/src/wavefront/workitems.rs | 52 ++++++++---------------------- src/core/film.rs | 12 ++++--- src/wavefront/aggregate.rs | 21 ++++++++---- src/wavefront/integrator.rs | 32 +++++++----------- 13 files changed, 99 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index b6ecf47..9aff772 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ tests/ scenes/ compile.sh output/ +*.md +!README.md +!INSTALL.md diff --git a/shared/src/core/geometry/bounds.rs b/shared/src/core/geometry/bounds.rs index 8e37d76..bb3e14b 100644 --- a/shared/src/core/geometry/bounds.rs +++ b/shared/src/core/geometry/bounds.rs @@ -5,6 +5,7 @@ use crate::core::geometry::{max, min}; use crate::utils::gpu_array_from_fn; use crate::utils::interval::Interval; use crate::utils::math::lerp; +use crate::{gamma, gamma_t}; use core::mem; use core::ops::{Add, Div, DivAssign, Mul, Sub}; use num_traits::{Bounded, Num}; @@ -220,7 +221,7 @@ where (center, radius) } - pub fn insersect(&self, o: Point3, d: Vector3, t_max: T) -> Option<(T, T)> { + pub fn intersect(&self, o: Point3, d: Vector3, t_max: T) -> Option<(T, T)> { let mut t0 = T::zero(); let mut t1 = t_max; @@ -231,6 +232,8 @@ where if t_near > t_far { mem::swap(&mut t_near, &mut t_far); } + + t_far = t_far * (T::one() + (T::one() + T::one()) * gamma_t::(3)); t0 = if t_near > t0 { t_near } else { t0 }; t1 = if t_far < t1 { t_far } else { t1 }; if t0 > t1 { @@ -274,7 +277,10 @@ impl Bounds3f { // Check Y let ty_min = (bounds[dir_is_neg[1]].y() - o.y()) * inv_dir.y(); - let ty_max = (bounds[1 - dir_is_neg[1]].y() - o.y()) * inv_dir.y(); + let mut ty_max = (bounds[1 - dir_is_neg[1]].y() - o.y()) * inv_dir.y(); + + t_max = t_max * (1. + 2. * gamma(3)); + ty_max = ty_max * (1. + 2. * gamma(3)); if t_min > ty_max || ty_min > t_max { return None; @@ -321,7 +327,11 @@ impl Bounds3f { let mut t_min = (bounds[dir_is_neg[0]].x() - o.x()) * inv_dir.x(); let mut t_max = (bounds[1 - dir_is_neg[0]].x() - o.x()) * inv_dir.x(); let ty_min = (bounds[dir_is_neg[1]].y() - o.y()) * inv_dir.y(); - let ty_max = (bounds[1 - dir_is_neg[1]].y() - o.y()) * inv_dir.y(); + let mut ty_max = (bounds[1 - dir_is_neg[1]].y() - o.y()) * inv_dir.y(); + + + t_max = t_max * (1. + 2. * gamma(3)); + ty_max = ty_max * (1. + 2. * gamma(3)); if t_min > ty_max || ty_min > t_max { return false; diff --git a/shared/src/core/geometry/cone.rs b/shared/src/core/geometry/cone.rs index edaa7b2..27a0a11 100644 --- a/shared/src/core/geometry/cone.rs +++ b/shared/src/core/geometry/cone.rs @@ -52,13 +52,13 @@ impl DirectionCone { * Vector3f::new( w.x() * (wp.y() * w.y() + wp.z() * w.z() - - wp.x() * (square(w.y() + square(w.z())))), + - wp.x() * (square(w.y()) + square(w.z()))), w.y() * (wp.x() * w.x() + wp.z() * w.z() - - wp.y() * (square(w.x() + square(w.z())))), + - wp.y() * (square(w.x()) + square(w.z()))), w.z() * (wp.x() * w.x() + wp.y() * w.y() - - wp.z() * (square(w.x() + square(w.y())))), + - wp.z() * (square(w.x()) + square(w.y()))), ) } @@ -91,10 +91,10 @@ impl DirectionCone { let theta_b = safe_acos(b.cos_theta); let theta_d = a.w.angle_between(b.w); - if (theta_d + theta_b).min(PI) <= theta_b { + if (theta_d + theta_b).min(PI) <= theta_a { return a.clone(); } - if (theta_d + theta_a).min(PI) <= theta_a { + if (theta_d + theta_a).min(PI) <= theta_b { return b.clone(); } @@ -107,7 +107,7 @@ impl DirectionCone { // Find the merged cone's axis and return cone union let theta_r = theta_o - theta_a; let wr = a.w.cross(b.w); - if wr.norm_squared() >= 0. { + if wr.norm_squared() == 0. { return DirectionCone::entire_sphere(); } diff --git a/shared/src/core/geometry/ray.rs b/shared/src/core/geometry/ray.rs index 4ac67a9..7c23e79 100644 --- a/shared/src/core/geometry/ray.rs +++ b/shared/src/core/geometry/ray.rs @@ -43,25 +43,21 @@ impl Ray { self.o + self.d * t } - pub fn offset_origin(p: &Point3fi, n: &Normal3f, w: &Vector3f) -> Point3f { - let d: Float = Vector3f::from(n.abs()).dot(p.error()); - let normal: Vector3f = Vector3f::from(*n); - - let mut offset = p.midpoint(); - if w.dot(normal) < 0.0 { - offset -= normal * d; - } else { - offset += normal * d; + pub fn offset_origin(pi: &Point3fi, n: &Normal3f, w: &Vector3f) -> Point3f { + let d: Float = Vector3f::from(n.abs()).dot(pi.error()); + let mut disp: Vector3f = Vector3f::from(*n) * d; + if w.dot(Vector3f::from(*n)) < 0.0 { + disp = -disp; } - + let mut po = pi.midpoint() + disp; for i in 0..3 { - if n[i] > 0.0 { - offset[i] = next_float_up(offset[i]); - } else if n[i] < 0.0 { - offset[i] = next_float_down(offset[i]); + if disp[i] > 0.0 { + po[i] = next_float_up(po[i]); + } else if disp[i] < 0.0 { + po[i] = next_float_down(po[i]); } } - offset + po } pub fn spawn(pi: &Point3fi, n: &Normal3f, time: Float, d: Vector3f) -> Ray { diff --git a/shared/src/core/interaction.rs b/shared/src/core/interaction.rs index 5de3a73..df5f67f 100644 --- a/shared/src/core/interaction.rs +++ b/shared/src/core/interaction.rs @@ -561,6 +561,8 @@ impl SurfaceInteraction { self.shading.n = ns; if orientation { self.common.n = self.n().face_forward(self.shading.n); + } else { + self.shading.n = self.shading.n.face_forward(self.common.n); } self.shading.dpdu = dpdus; self.shading.dpdv = dpdvs; diff --git a/shared/src/core/pbrt.rs b/shared/src/core/pbrt.rs index d63f343..fc3b813 100644 --- a/shared/src/core/pbrt.rs +++ b/shared/src/core/pbrt.rs @@ -1,6 +1,6 @@ use crate::core::geometry::Lerp; use core::ops::{Add, Mul}; -use num_traits::{Num, PrimInt}; +use num_traits::{Float as NumFloat, Num, NumCast, PrimInt}; use crate::core::light::LightTrait; use crate::core::shape::Shape; @@ -104,9 +104,16 @@ pub const PI_OVER_2: Float = core::f32::consts::FRAC_PI_2; pub const PI_OVER_4: Float = core::f32::consts::FRAC_PI_4; pub const SQRT_2: Float = core::f32::consts::SQRT_2; +#[inline] +pub fn gamma_t(n: i32) -> T { + let n = T::from(n).unwrap(); + let eps = T::epsilon() / (T::one() + T::one()); + n * eps / (T::one() - n * eps) +} + #[inline] pub fn gamma(n: i32) -> Float { - n as Float * MACHINE_EPSILON / (1. - n as Float * MACHINE_EPSILON) + gamma_t::(n) } #[cfg(feature = "cpu_debug")] diff --git a/shared/src/shapes/disk.rs b/shared/src/shapes/disk.rs index 159b69f..fe6c1f8 100644 --- a/shared/src/shapes/disk.rs +++ b/shared/src/shapes/disk.rs @@ -48,8 +48,8 @@ impl DiskShape { } fn basic_intersect(&self, r: &Ray, t_max: Float) -> Option { - let oi = self.object_from_render.apply_to_point(r.o); - let di = self.object_from_render.apply_to_vector(r.d); + let oi = self.object_from_render.apply_to_interval(Point3fi::new_from_point(r.o)); + let di = self.object_from_render.apply_to_vector_interval(Vector3fi::new_from_vector(r.d)); // Reject disk intersections for rays parallel to the disk’s plane if di.z() == 0. { return None; @@ -61,7 +61,7 @@ impl DiskShape { } // See if hit point is inside disk radii and phi_max - let p_hit: Point3f = oi + t_shape_hit * di; + let p_hit: Point3fi = oi + t_shape_hit * di; let dist2 = square(p_hit.x()) + square(p_hit.y()); if dist2 > square(self.radius) || dist2 < square(self.inner_radius) { return None; diff --git a/shared/src/shapes/sphere.rs b/shared/src/shapes/sphere.rs index 3918196..c7bba39 100644 --- a/shared/src/shapes/sphere.rs +++ b/shared/src/shapes/sphere.rs @@ -86,7 +86,7 @@ impl SphereShape { let c: Interval = square(oi.x()) + square(oi.y()) + square(oi.z()) - square(Interval::new(self.radius)); - let v: Vector3fi = (oi - b / Vector3fi::from((2. * a) * di)).into(); + let v: Vector3fi = (oi - b / 2. * a * di).into(); let length: Interval = v.norm(); let discrim = 4. * a * (Interval::new(self.radius) + length) * (Interval::new(self.radius) - length); @@ -120,6 +120,7 @@ impl SphereShape { } let mut p_hit = Point3f::from(oi) + Float::from(t_shape_hit) * Vector3f::from(di); + p_hit *= self.radius / p_hit.distance(Point3f::new(0., 0., 0.)); if p_hit.x() == 0. && p_hit.y() == 0. { p_hit[0] = 1e-5 * self.radius; } diff --git a/shared/src/utils/transform.rs b/shared/src/utils/transform.rs index 46bc0e6..d3d6038 100644 --- a/shared/src/utils/transform.rs +++ b/shared/src/utils/transform.rs @@ -129,8 +129,8 @@ impl TransformGeneric { let y = p.y(); let z = p.z(); let xn = self.m_inv[0][0] * x + self.m_inv[1][1] * y + self.m_inv[2][0] * z; - let yn = self.m_inv[0][1] * x + self.m_inv[1][1] * y + self.m_inv[2][1] * z; - let zn = self.m_inv[0][2] * x + self.m_inv[1][2] * y + self.m_inv[2][2] * z; + let yn = self.m_inv[1][0] * x + self.m_inv[1][1] * y + self.m_inv[2][1] * z; + let zn = self.m_inv[2][0] * x + self.m_inv[1][2] * y + self.m_inv[2][2] * z; Normal3f::new(xn, yn, zn) } diff --git a/shared/src/wavefront/workitems.rs b/shared/src/wavefront/workitems.rs index 7a9df51..3498be4 100644 --- a/shared/src/wavefront/workitems.rs +++ b/shared/src/wavefront/workitems.rs @@ -1,4 +1,5 @@ use crate::core::bxdf::BxDFFlags; +use crate::core::film::VisibleSurface; use crate::core::geometry::{ Normal3f, Point2f, Point2i, Point3f, Point3fi, Ray, RayDifferential, Vector3f, }; @@ -15,22 +16,13 @@ use crate::{Float, Ptr}; #[repr(C)] #[derive(Clone, Copy)] pub struct PixelSampleState { - pub filter_weight: SoABuffer, - pub p_film: SoABuffer, + pub pixel: SoABuffer, pub l: SoABuffer, pub lambda: SoABuffer, - pub r_u: SoABuffer, - pub r_l: SoABuffer, - pub prev_intr_ctx: SoABuffer, - pub beta: SoABuffer, - pub depth: SoABuffer, - pub specular_bounce: SoABuffer, - pub any_non_specular_bounces: SoABuffer, - pub eta_scale: SoABuffer, + pub filter_weight: SoABuffer, pub camera_ray_weight: SoABuffer, - pub visible_surface_idx: SoABuffer, + pub visible_surface: SoABuffer, pub samples: SoABuffer, - pub p_pixel: SoABuffer, } impl SoA for PixelSampleState { @@ -38,22 +30,13 @@ impl SoA for PixelSampleState { fn allocate(n: u32, alloc: &dyn SoAAllocator) -> Self { Self { - filter_weight: alloc_soa_buffer(n, alloc), - p_film: alloc_soa_buffer(n, alloc), + pixel: alloc_soa_buffer(n, alloc), l: alloc_soa_buffer(n, alloc), lambda: alloc_soa_buffer(n, alloc), - r_u: alloc_soa_buffer(n, alloc), - r_l: alloc_soa_buffer(n, alloc), - prev_intr_ctx: alloc_soa_buffer(n, alloc), - beta: alloc_soa_buffer(n, alloc), - depth: alloc_soa_buffer(n, alloc), - specular_bounce: alloc_soa_buffer(n, alloc), - any_non_specular_bounces: alloc_soa_buffer(n, alloc), - eta_scale: alloc_soa_buffer(n, alloc), + filter_weight: alloc_soa_buffer(n, alloc), camera_ray_weight: alloc_soa_buffer(n, alloc), - visible_surface_idx: alloc_soa_buffer(n, alloc), + visible_surface: alloc_soa_buffer(n, alloc), samples: alloc_soa_buffer(n, alloc), - p_pixel: alloc_soa_buffer(n, alloc), } } @@ -73,8 +56,8 @@ pub struct RayWorkItem { pub r_l: SampledSpectrum, pub prev_intr_ctx: LightSampleContext, pub eta_scale: Float, - pub specular_bounce: u8, - pub any_non_specular_bounces: u8, + pub specular_bounce: bool, + pub any_non_specular_bounces: bool, } #[repr(C)] @@ -89,8 +72,8 @@ pub struct RayWorkItemSoA { pub r_l: SoABuffer, pub prev_intr_ctx: SoABuffer, pub eta_scale: SoABuffer, - pub specular_bounce: SoABuffer, - pub any_non_specular_bounces: SoABuffer, + pub specular_bounce: SoABuffer, + pub any_non_specular_bounces: SoABuffer, } impl SoA for RayWorkItemSoA { @@ -332,14 +315,13 @@ pub struct MaterialEvalWorkItem { pub lambda: SampledWavelengths, pub beta: SampledSpectrum, pub r_u: SampledSpectrum, - // pub r_l: SampledSpectrum, pub any_non_specular_bounces: bool, pub depth: u32, pub eta_scale: Float, - pub dpdus: Vector3f , + pub dpdus: Vector3f, pub dpdvs: Vector3f, pub dndus: Normal3f, - pub dndvs: Normal3f + pub dndvs: Normal3f, } #[repr(C)] @@ -361,15 +343,13 @@ pub struct MaterialEvalWorkItemSoA { pub lambda: SoABuffer, pub beta: SoABuffer, pub r_u: SoABuffer, - // pub r_l: SoABuffer, pub any_non_specular_bounces: SoABuffer, pub depth: SoABuffer, pub eta_scale: SoABuffer, pub dpdus: SoABuffer, pub dpdvs: SoABuffer, pub dndus: SoABuffer, - pub dndvs: SoABuffer - + pub dndvs: SoABuffer, } impl SoA for MaterialEvalWorkItemSoA { @@ -393,7 +373,6 @@ impl SoA for MaterialEvalWorkItemSoA { lambda: alloc_soa_buffer(n, alloc), beta: alloc_soa_buffer(n, alloc), r_u: alloc_soa_buffer(n, alloc), - // r_l: alloc_soa_buffer(n, alloc), any_non_specular_bounces: alloc_soa_buffer(n, alloc), depth: alloc_soa_buffer(n, alloc), eta_scale: alloc_soa_buffer(n, alloc), @@ -422,7 +401,6 @@ impl SoA for MaterialEvalWorkItemSoA { lambda: self.lambda.get(i), beta: self.beta.get(i), r_u: self.r_u.get(i), - // r_l: self.r_l.get(i), any_non_specular_bounces: self.any_non_specular_bounces.get(i) != 0, depth: self.depth.get(i), eta_scale: self.eta_scale.get(i), @@ -430,7 +408,6 @@ impl SoA for MaterialEvalWorkItemSoA { dpdvs: self.dpdvs.get(i), dndus: self.dndus.get(i), dndvs: self.dndvs.get(i), - } } @@ -451,7 +428,6 @@ impl SoA for MaterialEvalWorkItemSoA { self.lambda.set(i, v.lambda); self.beta.set(i, v.beta); self.r_u.set(i, v.r_u); - // self.r_l.set(i, v.r_l); self.any_non_specular_bounces .set(i, v.any_non_specular_bounces as u8); self.depth.set(i, v.depth); diff --git a/src/core/film.rs b/src/core/film.rs index f9bfc1b..cfb967a 100644 --- a/src/core/film.rs +++ b/src/core/film.rs @@ -15,7 +15,7 @@ use shared::spectra::{ cie::SWATCHES_RAW, DenselySampledSpectrum, PiecewiseLinearSpectrum, RGBColorSpace, }; use shared::utils::math::{linear_least_squares, SquareMatrix}; -use shared::{Float, Ptr, leak}; +use shared::{leak, Float, Ptr}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, LazyLock}; @@ -100,7 +100,7 @@ impl CreatePixelSensor for PixelSensor { output_colorspace.as_ref(), sensor_illum.as_deref(), imaging_ratio, - arena + arena, )) } else { let r_opt = get_named_spectrum(&format!("{}_r", sensor_name)); @@ -129,7 +129,7 @@ impl CreatePixelSensor for PixelSensor { .expect("Sensor must have illuminant"), ), imaging_ratio, - arena + arena, )) } } @@ -205,7 +205,7 @@ impl CreatePixelSensor for PixelSensor { output_colorspace: &RGBColorSpace, sensor_illum: Option<&Spectrum>, imaging_ratio: Float, - arena: &Arena + arena: &Arena, ) -> Self { let spectra = get_spectra_context(); let r_bar = CIE_X_DATA.clone(); @@ -229,7 +229,6 @@ impl CreatePixelSensor for PixelSensor { imaging_ratio, } } - } pub trait CreateFilmBase { @@ -336,6 +335,9 @@ pub trait FilmTrait: Sync { for x in pixel_bounds.p_min.x()..pixel_bounds.p_max.x() { let p = Point2i::new(x, y); let mut rgb = self.get_pixel_rgb(p, Some(splat_scale)); + if rgb.r > 1.0 || rgb.g > 1.0 || rgb.b > 1.0 { + eprintln!("p={:?} get_pixel_rgb=({}, {}, {})", p, rgb.r, rgb.g, rgb.b); + } let mut was_clamped = false; if write_fp16 { if rgb.r > 65504.0 { diff --git a/src/wavefront/aggregate.rs b/src/wavefront/aggregate.rs index a8eecc1..3c0ac01 100644 --- a/src/wavefront/aggregate.rs +++ b/src/wavefront/aggregate.rs @@ -1,4 +1,5 @@ use crate::globals::get_options; +use log::debug; use rayon::prelude::*; use shared::core::geometry::{Bounds3f, Ray, VectorLike}; use shared::core::interaction::{InteractionTrait, SurfaceInteraction}; @@ -60,7 +61,7 @@ impl WavefrontAggregate for CpuAggregate { r_u: r.r_u, r_l: r.r_l, depth: r.depth, - specular_bounce: r.specular_bounce != 0, + specular_bounce: r.specular_bounce, prev_intr_ctx: r.prev_intr_ctx, }); return; @@ -83,14 +84,14 @@ impl WavefrontAggregate for CpuAggregate { p: intr.p(), n: intr.n(), uv: intr.common.uv, - wo: -r.ray.d, + wo: intr.wo(), lambda: r.lambda, pixel_index: r.pixel_index, beta: r.beta, r_u: r.r_u, r_l: r.r_l, depth: r.depth, - specular_bounce: r.specular_bounce != 0, + specular_bounce: r.specular_bounce, prev_intr_ctx: r.prev_intr_ctx, }); } @@ -103,12 +104,20 @@ impl WavefrontAggregate for CpuAggregate { universal_eval_mtl_q }; + if material.is_conductor() { + debug!("shading frame: {:?}", intr.shading.dpdu); + debug!( + "dot product: {:?}", + intr.shading.dpdu.normalize().dot(intr.n().into()) + ); + } + eval_q.push(MaterialEvalWorkItem { p: intr.pi(), n: intr.n(), ns: intr.shading.n, - dpdu: intr.shading.dpdu, - dpdv: intr.shading.dpdv, + dpdu: intr.dpdu, + dpdv: intr.dpdv, uv: intr.common.uv, wo: intr.wo(), time: r.ray.time, @@ -120,7 +129,7 @@ impl WavefrontAggregate for CpuAggregate { lambda: r.lambda, beta: r.beta, r_u: r.r_u, - any_non_specular_bounces: r.any_non_specular_bounces != 0, + any_non_specular_bounces: r.any_non_specular_bounces, depth: r.depth, eta_scale: r.eta_scale, dpdus: intr.shading.dpdu, diff --git a/src/wavefront/integrator.rs b/src/wavefront/integrator.rs index 0537900..c84d5c7 100644 --- a/src/wavefront/integrator.rs +++ b/src/wavefront/integrator.rs @@ -75,8 +75,6 @@ where let scanlines_per_pass = (max_samples / res_x).max(1); let max_queue_size = res_x * scanlines_per_pass; - eprintln!("wavefront got {} lights", lights.len()); - let mut infinite_lights = gvec(); for light in &lights { if light.light_type().is_infinite() { @@ -84,10 +82,6 @@ where } } - eprintln!("infinite_lights len = {}", infinite_lights.len()); - - // for light in - let cpu_aggregate = CpuAggregate::new(*aggregate); CpuWavefrontRenderer(WavefrontPathIntegrator { @@ -241,7 +235,7 @@ impl CpuWavefrontRenderer { pixel_bounds.p_min.x() + (pixel_index as i32 % x_resolution), y0 + (pixel_index as i32 / x_resolution), ); - pixel_sample_state.p_pixel.set(pixel_index, p_pixel); + pixel_sample_state.pixel.set(pixel_index, p_pixel); // Skipped pixels contribute nothing; their slots are simply never // populated, and update_film filters them by the same bounds test. @@ -263,9 +257,6 @@ impl CpuWavefrontRenderer { pixel_sample_state .filter_weight .set(pixel_index, camera_sample.filter_weight); - pixel_sample_state - .p_film - .set(pixel_index, camera_sample.p_film); let Some(camera_ray) = camera.generate_ray(camera_sample, &lambda) else { pixel_sample_state @@ -288,8 +279,8 @@ impl CpuWavefrontRenderer { r_l: SampledSpectrum::new(1.0), prev_intr_ctx: LightSampleContext::default(), eta_scale: 1.0, - specular_bounce: 0, - any_non_specular_bounces: 0, + specular_bounce: false, + any_non_specular_bounces: false, }); }); } @@ -318,7 +309,7 @@ impl CpuWavefrontRenderer { if w.depth == 0 || w.specular_bounce { l_contrib += w.beta * le / w.r_u.average(); } else { - // MIS: combine BSDF and light sampling weights via ratio tracking + // Compute MIS-weighted radiance contribution from infinite light let ctx = w.prev_intr_ctx; let light_choice_pdf = light_sampler.pmf_with_context(&ctx, light); let r_l = w.r_l * light_choice_pdf * light.pdf_li(&ctx, w.ray_d, true); @@ -353,13 +344,14 @@ impl CpuWavefrontRenderer { let l_contrib = if w.depth == 0 || w.specular_bounce { w.beta * le / w.r_u.average() } else { + let wi = -w.wo; let ctx = w.prev_intr_ctx; let light_choice_pdf = light_sampler.pmf_with_context(&ctx, light); // wi from previous interaction to this light hit - let wi = (w.p - Point3f::from(ctx.pi)).normalize(); let light_pdf = light_choice_pdf * light.pdf_li(&ctx, wi, true); + let r_u = w.r_u; let r_l = w.r_l * light_pdf; - w.beta * le / (w.r_u + r_l).average() + w.beta * le / (r_u + r_l).average() }; if !l_contrib.is_black() { @@ -489,8 +481,8 @@ impl CpuWavefrontRenderer { r_l, prev_intr_ctx: ctx, eta_scale, - specular_bounce: bs.is_specular() as u8, - any_non_specular_bounces: any_non_specular as u8, + specular_bounce: bs.is_specular(), + any_non_specular_bounces: any_non_specular, }); } } @@ -505,7 +497,7 @@ impl CpuWavefrontRenderer { }; if flags.is_reflective() && !flags.is_transmissive() { - light_ctx.pi = Point3fi::new_from_point(Ray::offset_origin(&w.p, &w.n, &(-wo))); + light_ctx.pi = Point3fi::new_from_point(Ray::offset_origin(&w.p, &w.n, &wo)); } else if flags.is_transmissive() && flags.is_reflective() { light_ctx.pi = Point3fi::new_from_point(Ray::offset_origin(&w.p, &w.n, &(-wo))); } @@ -573,7 +565,7 @@ impl CpuWavefrontRenderer { (0..self.max_queue_size as usize) .into_par_iter() .for_each(|pixel_index| { - let p_pixel = self.pixel_sample_state.p_pixel.get(pixel_index); + let p_pixel = self.pixel_sample_state.pixel.get(pixel_index); if !pixel_bounds.contains_exclusive(p_pixel) { return; } @@ -600,7 +592,7 @@ impl CpuWavefrontRenderer { let w = unsafe { ray_queue.storage.get(i) }; let dimension = 6 + 7 * w.depth; let pi = w.pixel_index as usize; - let p_pixel = pixel_sample_state.p_pixel.get(pi); + let p_pixel = pixel_sample_state.pixel.get(pi); let mut sampler = sampler_proto.clone(); sampler.start_pixel_sample(p_pixel, sample_index as i32, Some(dimension));