Still broken

This commit is contained in:
Wito Wiala 2026-06-02 21:46:11 +01:00
parent f18aed2c91
commit 66032abf76
7 changed files with 246 additions and 218 deletions

View file

@ -189,7 +189,7 @@ pub mod device {
// on the material, which we can refine later.
let q = &*params.universal_eval_mtl_q.as_raw();
q.push(MaterialEvalWorkItem {
p: intr.p(),
p: intr.pi(),
n: intr.n(),
ns: intr.shading.n,
dpdu: intr.shading.dpdu,
@ -258,8 +258,6 @@ pub mod device {
pub n_rays: u32,
}
// -- Helper functions --
unsafe fn push_escaped(
params: &IntersectClosestParams,
work: &RayWorkItem,

View file

@ -316,8 +316,7 @@ impl SoA for HitAreaLightWorkItemSoA {
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct MaterialEvalWorkItem {
// Surface interaction
pub p: Point3f,
pub p: Point3fi,
pub n: Normal3f,
pub ns: Normal3f,
pub dpdu: Vector3f,
@ -326,30 +325,27 @@ pub struct MaterialEvalWorkItem {
pub wo: Vector3f,
pub time: Float,
pub face_index: i32,
// Material
pub material: Ptr<Material>,
pub area_light: Ptr<Light>,
// Medium interface
pub medium_interface: MediumInterface,
// Path state
pub pixel_index: u32,
pub lambda: SampledWavelengths,
pub beta: SampledSpectrum,
pub r_u: SampledSpectrum,
// For next-event estimation
// pub r_l: SampledSpectrum,
pub any_non_specular_bounces: bool,
pub depth: u32,
pub eta_scale: Float,
pub dpdus: Vector3f ,
pub dpdvs: Vector3f,
pub dndus: Normal3f,
pub dndvs: Normal3f
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MaterialEvalWorkItemSoA {
pub p: SoABuffer<Point3f>,
pub p: SoABuffer<Point3fi>,
pub n: SoABuffer<Normal3f>,
pub ns: SoABuffer<Normal3f>,
pub dpdu: SoABuffer<Vector3f>,
@ -365,9 +361,15 @@ pub struct MaterialEvalWorkItemSoA {
pub lambda: SoABuffer<SampledWavelengths>,
pub beta: SoABuffer<SampledSpectrum>,
pub r_u: SoABuffer<SampledSpectrum>,
// pub r_l: SoABuffer<SampledSpectrum>,
pub any_non_specular_bounces: SoABuffer<u8>,
pub depth: SoABuffer<u32>,
pub eta_scale: SoABuffer<Float>,
pub dpdus: SoABuffer<Vector3f>,
pub dpdvs: SoABuffer<Vector3f>,
pub dndus: SoABuffer<Normal3f>,
pub dndvs: SoABuffer<Normal3f>
}
impl SoA for MaterialEvalWorkItemSoA {
@ -391,9 +393,14 @@ 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),
dpdus: alloc_soa_buffer(n, alloc),
dpdvs: alloc_soa_buffer(n, alloc),
dndus: alloc_soa_buffer(n, alloc),
dndvs: alloc_soa_buffer(n, alloc),
}
}
@ -415,9 +422,15 @@ 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),
dpdus: self.dpdus.get(i),
dpdvs: self.dpdvs.get(i),
dndus: self.dndus.get(i),
dndvs: self.dndvs.get(i),
}
}
@ -438,19 +451,22 @@ 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);
self.eta_scale.set(i, v.eta_scale);
self.dpdus.set(i, v.dpdus);
self.dpdvs.set(i, v.dpdvs);
self.dndus.set(i, v.dndus);
self.dndvs.set(i, v.dndvs);
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct ShadowRayWorkItem {
pub ray_o: Point3f,
pub ray_d: Vector3f,
pub ray_time: Float,
pub ray: Ray,
pub t_max: Float,
pub lambda: SampledWavelengths,
pub l_d: SampledSpectrum,
@ -462,9 +478,7 @@ pub struct ShadowRayWorkItem {
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ShadowRayWorkItemSoA {
pub ray_o: SoABuffer<Point3f>,
pub ray_d: SoABuffer<Vector3f>,
pub ray_time: SoABuffer<Float>,
pub ray: SoABuffer<Ray>,
pub t_max: SoABuffer<Float>,
pub lambda: SoABuffer<SampledWavelengths>,
pub l_d: SoABuffer<SampledSpectrum>,
@ -478,9 +492,7 @@ impl SoA for ShadowRayWorkItemSoA {
fn allocate(n: u32, alloc: &dyn SoAAllocator) -> Self {
Self {
ray_o: alloc_soa_buffer(n, alloc),
ray_d: alloc_soa_buffer(n, alloc),
ray_time: alloc_soa_buffer(n, alloc),
ray: alloc_soa_buffer(n, alloc),
t_max: alloc_soa_buffer(n, alloc),
lambda: alloc_soa_buffer(n, alloc),
l_d: alloc_soa_buffer(n, alloc),
@ -492,9 +504,7 @@ impl SoA for ShadowRayWorkItemSoA {
unsafe fn get(&self, i: usize) -> ShadowRayWorkItem {
ShadowRayWorkItem {
ray_o: self.ray_o.get(i),
ray_d: self.ray_d.get(i),
ray_time: self.ray_time.get(i),
ray: self.ray.get(i),
t_max: self.t_max.get(i),
lambda: self.lambda.get(i),
l_d: self.l_d.get(i),
@ -505,9 +515,7 @@ impl SoA for ShadowRayWorkItemSoA {
}
unsafe fn set(&self, i: usize, v: ShadowRayWorkItem) {
self.ray_o.set(i, v.ray_o);
self.ray_d.set(i, v.ray_d);
self.ray_time.set(i, v.ray_time);
self.ray.set(i, v.ray);
self.t_max.set(i, v.t_max);
self.lambda.set(i, v.lambda);
self.l_d.set(i, v.l_d);

View file

@ -106,8 +106,7 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
all_lights,
arena,
);
let mut renderer = CpuWavefrontRenderer(wf);
renderer.render();
wf.render();
} else {
eprintln!("RENDER: Path integrator backend");
let integrator = scene.create_integrator(

View file

@ -15,7 +15,7 @@ use crate::lights::sampler::create_light_sampler;
use crate::utils::parallel::{run_async, AsyncJob};
use crate::utils::parameters::{NamedTextures, ParameterDictionary, TextureParameterDictionary};
use crate::utils::resolve_filename;
use crate::wavefront::CpuAggregate;
use crate::wavefront::{CreateWavefront, CpuAggregate, CpuWavefrontRenderer};
use crate::{Arena, ArenaUpload, FileLoc};
use anyhow::{anyhow, Result};
use parking_lot::Mutex;
@ -725,81 +725,10 @@ impl BasicScene {
aggregate: Arc<Primitive>,
lights: Vec<Arc<Light>>,
arena: &Arena,
) -> WavefrontPathIntegrator<CpuAggregate> {
let entity = self.integrator.lock().clone().unwrap();
let max_depth = entity
.parameters
.get_one_int("maxdepth", 5)
.expect("Could not obtain depth value");
let regularize = entity
.parameters
.get_one_bool("regularize", false)
.expect("Could not obtain regularize flag value");
let spp = sampler.samples_per_pixel() as u32;
let film = camera.base().film;
let pixel_bounds = film.pixel_bounds();
let filter = Ptr::from(&film.base().filter);
let light_sampler = create_light_sampler("power", &lights, arena);
let res_x = pixel_bounds.diagonal().x() as u32;
let max_samples = 1024u32 * 1024;
let scanlines_per_pass = (max_samples / res_x).max(1);
let max_queue_size = res_x * scanlines_per_pass;
let mut infinite_lights = gvec();
for light in &lights {
if light.light_type().is_infinite() {
infinite_lights.push(arena.alloc(**light));
}
}
let cpu_aggregate = CpuAggregate::new(*aggregate);
WavefrontPathIntegrator {
aggregate: cpu_aggregate,
camera: (*camera).clone(),
sampler: (*sampler).clone(),
max_depth: max_depth.try_into().unwrap(),
film,
filter,
samples_per_pixel: spp,
regularize,
infinite_lights,
max_queue_size,
scanlines_per_pass,
light_sampler,
ray_queues: [
WorkQueue::new(
RayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
WorkQueue::new(
RayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
],
shadow_ray_queue: WorkQueue::new(
ShadowRayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
escaped_ray_queue: WorkQueue::new(
EscapedRayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
hit_area_light_queue: WorkQueue::new(
HitAreaLightWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
basic_eval_material_queue: WorkQueue::new(
MaterialEvalWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
universal_eval_material_queue: WorkQueue::new(
MaterialEvalWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
pixel_sample_state: PixelSampleState::allocate(max_queue_size, arena),
}
) -> CpuWavefrontRenderer {
let integrator_entity = self.integrator.lock().clone().unwrap();
let params = &integrator_entity.parameters;
CpuWavefrontRenderer::create(params.clone(), camera, sampler, aggregate, lights, arena)
}
// Getters

View file

@ -1,14 +1,14 @@
use crate::globals::get_options;
use rayon::prelude::*;
use shared::core::geometry::{Bounds3f, Ray, VectorLike};
use shared::core::interaction::InteractionTrait;
use shared::core::interaction::{InteractionTrait, SurfaceInteraction};
use shared::core::material::MaterialTrait;
use shared::core::primitive::{Primitive, PrimitiveTrait};
use shared::core::texture::BasicTextureEvaluator;
use shared::core::texture::TextureEvaluator;
use shared::wavefront::workitems::*;
use shared::wavefront::WavefrontAggregate;
use shared::Ptr;
use shared::{Float, Ptr};
pub struct CpuAggregate {
pub aggregate: Primitive,
@ -20,6 +20,13 @@ impl CpuAggregate {
}
}
// fn enqueue_after_intersection(
// r: RayWorkItem, ray_medium: Medium, t_max: Float, intr: SurfaceInteraction,
// mut medium_sample_queue: &MediumQueue, mut next_ray_queue: &RayQueue,
// mut hit_area_light_queue: &HitAreaLightQueue, mut basic_eval_mtl_q: &MaterialEvalQueue,
// mut universal_eval_mlt_q: MaterialEvalQueue) {
// }
impl WavefrontAggregate for CpuAggregate {
fn bounds(&self) -> Bounds3f {
self.aggregate.bounds()
@ -38,12 +45,12 @@ impl WavefrontAggregate for CpuAggregate {
) {
let n_rays = ray_q.size().min(max_rays as u32);
// Intersect _r_'s ray with the scene and enqueue resulting work
// Intersect ray with the scene and enqueue resulting work
(0..n_rays as usize).into_par_iter().for_each(|i| {
let r = unsafe { ray_q.get(i) };
let Some(si) = self.aggregate.intersect(&r.ray, None) else {
// EnqueueMiss - push to escaped queue with r's path state
// EnqueueMiss
escaped_ray_q.push(EscapedRayWorkItem {
ray_o: r.ray.o,
ray_d: r.ray.d,
@ -61,7 +68,7 @@ impl WavefrontAggregate for CpuAggregate {
let intr = &si.intr;
// Medium transition — re-push as indirect ray with same path state
// Medium transition
if intr.material.is_null() {
let mut next = r;
intr.spawn_ray(r.ray.d);
@ -90,17 +97,6 @@ impl WavefrontAggregate for CpuAggregate {
}
// Material eval queue dispatch
// let material = *intr.material.get().unwrap();
// let displacement = material.get_displacement();
// let eval_q = if material.can_evaluate_textures(&BasicTextureEvaluator)
// && (displacement.is_null()
// || BasicTextureEvaluator.can_evaluate(&[displacement], &[]))
// {
// basic_eval_mtl_q
// } else {
// universal_eval_mtl_q
// };
//
let material = *intr.material.get().unwrap();
let eval_q = if material.can_evaluate_textures(&BasicTextureEvaluator) {
basic_eval_mtl_q
@ -109,13 +105,13 @@ impl WavefrontAggregate for CpuAggregate {
};
eval_q.push(MaterialEvalWorkItem {
p: intr.p(),
p: intr.pi(),
n: intr.n(),
ns: intr.shading.n,
dpdu: intr.shading.dpdu,
dpdv: intr.shading.dpdv,
uv: intr.common.uv,
wo: -r.ray.d,
wo: intr.wo(),
time: r.ray.time,
face_index: intr.face_index,
material: intr.material,
@ -128,6 +124,10 @@ impl WavefrontAggregate for CpuAggregate {
any_non_specular_bounces: r.any_non_specular_bounces != 0,
depth: r.depth,
eta_scale: r.eta_scale,
dpdus: intr.shading.dpdu,
dpdvs: intr.shading.dpdv,
dndus: intr.shading.dndu,
dndvs: intr.shading.dndv,
});
});
}

View file

@ -1,5 +1,8 @@
use super::CpuAggregate;
use crate::globals::get_options;
use crate::lights::sampler::create_light_sampler;
use crate::Arena;
use crate::ParameterDictionary;
use crate::PbrtProgress;
use rayon::prelude::*;
use shared::core::bxdf::{FArgs, TransportMode};
@ -13,6 +16,7 @@ use shared::core::geometry::{
use shared::core::interaction::InteractionTrait;
use shared::core::light::{Light, LightSampleContext, LightTrait};
use shared::core::material::{MaterialEvalContext, MaterialTrait};
use shared::core::primitive::Primitive;
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
use shared::core::texture::{TextureEvalContext, UniversalTextureEvaluator};
use shared::lights::sampler::{LightSampler, LightSamplerTrait};
@ -22,8 +26,9 @@ use shared::utils::sampling::power_heuristic;
use shared::utils::soa::{SoA, SoAAllocator, WorkQueue};
use shared::wavefront::workitems::*;
use shared::wavefront::{WavefrontAggregate, WavefrontPathIntegrator, WavefrontRenderer};
use shared::Ptr;
use shared::{gvec, Ptr};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
pub struct CpuWavefrontRenderer(pub WavefrontPathIntegrator<CpuAggregate>);
@ -40,8 +45,95 @@ impl DerefMut for CpuWavefrontRenderer {
}
}
use std::sync::Mutex;
static M: Mutex<()> = Mutex::new(());
pub trait CreateWavefront
where
Self: Sized,
{
fn create(
parameters: ParameterDictionary,
camera: Arc<Camera>,
sampler: Arc<Sampler>,
aggregate: Arc<Primitive>,
lights: Vec<Arc<Light>>,
arena: &Arena,
) -> CpuWavefrontRenderer {
let max_depth = parameters
.get_one_int("maxdepth", 5)
.expect("Could not obtain depth value");
let regularize = parameters
.get_one_bool("regularize", false)
.expect("Could not obtain regularize flag value");
let spp = sampler.samples_per_pixel() as u32;
let film = camera.base().film;
let pixel_bounds = film.pixel_bounds();
let filter = Ptr::from(&film.base().filter);
let light_sampler = create_light_sampler("power", &lights, arena);
let res_x = pixel_bounds.diagonal().x() as u32;
let max_samples = 1024u32 * 1024;
let scanlines_per_pass = (max_samples / res_x).max(1);
let max_queue_size = res_x * scanlines_per_pass;
let mut infinite_lights = gvec();
for light in &lights {
if light.light_type().is_infinite() {
infinite_lights.push(arena.alloc(**light));
}
}
// for light in
let cpu_aggregate = CpuAggregate::new(*aggregate);
CpuWavefrontRenderer(WavefrontPathIntegrator {
aggregate: cpu_aggregate,
camera: (*camera).clone(),
sampler: (*sampler).clone(),
max_depth: max_depth.try_into().unwrap(),
film,
filter,
samples_per_pixel: spp,
regularize,
infinite_lights,
max_queue_size,
scanlines_per_pass,
light_sampler,
ray_queues: [
WorkQueue::new(
RayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
WorkQueue::new(
RayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
],
shadow_ray_queue: WorkQueue::new(
ShadowRayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
escaped_ray_queue: WorkQueue::new(
EscapedRayWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
hit_area_light_queue: WorkQueue::new(
HitAreaLightWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
basic_eval_material_queue: WorkQueue::new(
MaterialEvalWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
universal_eval_material_queue: WorkQueue::new(
MaterialEvalWorkItemSoA::allocate(max_queue_size, arena),
max_queue_size,
),
pixel_sample_state: PixelSampleState::allocate(max_queue_size, arena),
})
}
}
impl CreateWavefront for CpuWavefrontRenderer {}
impl CpuWavefrontRenderer {
pub fn render(&mut self) {
@ -125,8 +217,6 @@ impl CpuWavefrontRenderer {
sample_index: u32,
pixel_bounds: &Bounds2i,
) {
// For each pixel in the scanline range, generate a camera ray
// and push it to the ray queue. Initialize the PixelSampleState.
let filter = self.filter;
let film = self.film;
let camera = &self.camera;
@ -135,60 +225,68 @@ impl CpuWavefrontRenderer {
let ray_queue = &self.ray_queues[0];
let x_resolution = pixel_bounds.p_max.x() - pixel_bounds.p_min.x();
let n_scanlines = y1 - y0;
let total = (n_scanlines * x_resolution) as usize;
(0..total).into_par_iter().for_each(|idx| {
let dx = idx as i32 % x_resolution;
let dy = idx as i32 / x_resolution;
let p_pixel = Point2i::new(pixel_bounds.p_min.x() + dx, y0 + dy);
let pixel_index = idx as u32;
let pi = idx;
// Iterate the whole queue, exactly like pbrt's ParallelFor(maxQueueSize).
// The loop index IS the pixelSampleState key; pPixel is derived from it,
// and every later kernel addresses state by this same absolute index.
(0..self.max_queue_size as usize)
.into_par_iter()
.for_each(|pixel_index| {
let p_pixel = Point2i::new(
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);
if !pixel_bounds.contains_exclusive(p_pixel) {
return;
}
// Skipped pixels contribute nothing; their slots are simply never
// populated, and update_film filters them by the same bounds test.
if !pixel_bounds.contains_exclusive(p_pixel) {
return;
}
let mut sampler = sampler_proto.clone();
sampler.start_pixel_sample(p_pixel, sample_index as i32, Some(0));
let mut sampler = sampler_proto.clone();
sampler.start_pixel_sample(p_pixel, sample_index as i32, Some(0));
let lu = sampler.get1d();
let lambda = film.sample_wavelengths(lu);
let camera_sample = get_camera_sample(&mut sampler, p_pixel, &filter);
let lu = sampler.get1d();
let lambda = film.sample_wavelengths(lu);
let camera_sample = get_camera_sample(&mut sampler, p_pixel, &filter);
pixel_sample_state.l.set(pi, SampledSpectrum::new(0.0));
pixel_sample_state.lambda.set(pi, lambda);
pixel_sample_state
.filter_weight
.set(pi, camera_sample.filter_weight);
pixel_sample_state.p_film.set(pi, camera_sample.p_film);
pixel_sample_state.p_pixel.set(pi, p_pixel);
pixel_sample_state
.l
.set(pixel_index, SampledSpectrum::new(0.0));
pixel_sample_state.lambda.set(pixel_index, lambda);
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
.camera_ray_weight
.set(pixel_index, SampledSpectrum::new(0.0));
return;
};
let Some(camera_ray) = camera.generate_ray(camera_sample, &lambda) else {
pixel_sample_state
.camera_ray_weight
.set(pi, SampledSpectrum::new(0.0));
return;
};
.set(pixel_index, camera_ray.weight);
pixel_sample_state
.camera_ray_weight
.set(pi, camera_ray.weight);
ray_queue.push(RayWorkItem {
ray: camera_ray.ray,
depth: 0,
pixel_index,
lambda,
beta: SampledSpectrum::new(1.0),
r_u: SampledSpectrum::new(1.0),
r_l: SampledSpectrum::new(1.0),
prev_intr_ctx: LightSampleContext::default(),
eta_scale: 1.0,
specular_bounce: 0,
any_non_specular_bounces: 0,
ray_queue.push(RayWorkItem {
ray: camera_ray.ray,
depth: 0,
pixel_index: pixel_index as u32,
lambda,
beta: SampledSpectrum::new(1.0),
r_u: SampledSpectrum::new(1.0),
r_l: SampledSpectrum::new(1.0),
prev_intr_ctx: LightSampleContext::default(),
eta_scale: 1.0,
specular_bounce: 0,
any_non_specular_bounces: 0,
});
});
});
}
/// Evaluate infinite lights.
@ -209,7 +307,7 @@ impl CpuWavefrontRenderer {
let ray = Ray::new(w.ray_o, w.ray_d, None, Ptr::null());
let le = light.le(&ray, &w.lambda);
if le.is_black() {
return;
continue;
}
if w.depth == 0 || w.specular_bounce {
@ -289,8 +387,7 @@ impl CpuWavefrontRenderer {
let next_ray_queue = &self.ray_queues[next];
let regularize = self.regularize;
// (0..n as usize).into_par_iter().for_each(|i| {
for i in 0..n as usize {
(0..n as usize).into_par_iter().for_each(|i| {
let w = unsafe { queue.storage.get(i) };
let pi = w.pixel_index as usize;
let rs = pixel_sample_state.samples.get(pi);
@ -302,7 +399,7 @@ impl CpuWavefrontRenderer {
let tex_eval = UniversalTextureEvaluator;
let ctx = MaterialEvalContext {
texture: TextureEvalContext {
p: w.p,
p: w.p.into(),
dpdx: Vector3f::zero(),
dpdy: Vector3f::zero(),
n: w.n,
@ -315,14 +412,14 @@ impl CpuWavefrontRenderer {
},
wo: w.wo,
ns: w.ns,
dpdus: w.dpdu,
dpdus: w.dpdus,
};
let lambda = w.lambda;
let mut bsdf = material.get_bsdf(&tex_eval, &ctx, &lambda);
if bsdf.flags().is_empty() {
return;
}
if self.regularize && w.any_non_specular_bounces {
if regularize && w.any_non_specular_bounces {
bsdf.regularize();
}
@ -345,7 +442,7 @@ impl CpuWavefrontRenderer {
}
let rr_beta = (beta * eta_scale / r_u.average()).max_component_value();
if rr_beta < 1.0 && w.depth >= 1 {
if rr_beta < 1.0 && w.depth > 1 {
let q = (1.0 - rr_beta).max(0.0_f32);
if rs.indirect.rr < q {
beta = SampledSpectrum::new(0.0);
@ -355,10 +452,10 @@ impl CpuWavefrontRenderer {
}
if !beta.is_black() {
let ray = Ray::spawn(&Point3fi::new_from_point(w.p), &w.n, w.time, wi);
let ray = Ray::spawn(&w.p, &w.n, w.time, wi);
let any_non_specular = !bs.is_specular() || w.any_non_specular_bounces;
let ctx = LightSampleContext {
pi: Point3fi::new_from_point(w.p),
pi: w.p,
n: w.n,
ns,
};
@ -379,17 +476,16 @@ impl CpuWavefrontRenderer {
}
}
// Direct lighting — independent
// Direct lighting
let flags = bsdf.flags();
if flags.is_non_specular() {
let light_ctx = LightSampleContext {
pi: Point3fi::new_from_point(w.p),
pi: w.p,
n: w.n,
ns,
};
if let Some(sampled_light) = self
.light_sampler
.sample_with_context(&light_ctx, rs.direct.uc)
if let Some(sampled_light) =
light_sampler.sample_with_context(&light_ctx, rs.direct.uc)
{
if let Some(ls) =
sampled_light
@ -412,20 +508,22 @@ impl CpuWavefrontRenderer {
let r_l = w.r_u * light_pdf;
let ld = beta * ls.l;
let ray_o = Ray::offset_origin(
&Point3fi::new_from_point(w.p),
let ray_o = Ray::spawn_to_interaction(
&w.p,
&w.n,
&wi,
w.time,
&ls.p_light.pi(),
&ls.p_light.n(),
);
let t_max = (1.0 - 1e-4)
* (Point3f::from(ls.p_light.p()) - ray_o).norm()
* (Point3f::from(ls.p_light.p()) - ray_o.o).norm()
/ wi.norm();
self.shadow_ray_queue.push(ShadowRayWorkItem {
ray_o,
ray_d: wi,
shadow_ray_queue.push(ShadowRayWorkItem {
ray_o: ray_o.o,
ray_d: ray_o.d,
ray_time: w.time,
t_max,
t_max: 1.0 - 1e-4,
lambda,
l_d: ld,
r_u,
@ -438,31 +536,27 @@ impl CpuWavefrontRenderer {
}
}
}
}
// });
});
}
fn update_film(&self, y0: i32, y1: i32, pixel_bounds: &Bounds2i) {
let x_resolution = pixel_bounds.p_max.x() - pixel_bounds.p_min.x();
let n_scanlines = y1 - y0;
let total = (n_scanlines * x_resolution) as usize;
fn update_film(&self, _y0: i32, _y1: i32, pixel_bounds: &Bounds2i) {
(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);
if !pixel_bounds.contains_exclusive(p_pixel) {
return;
}
(0..total).into_par_iter().for_each(|idx| {
let pi = idx;
let p_pixel = self.pixel_sample_state.p_pixel.get(pi);
if !pixel_bounds.contains_exclusive(p_pixel) {
return;
}
let l = self.pixel_sample_state.l.get(pixel_index);
let camera_weight = self.pixel_sample_state.camera_ray_weight.get(pixel_index);
let weighted_l = l * camera_weight;
let lambda = self.pixel_sample_state.lambda.get(pixel_index);
let filter_weight = self.pixel_sample_state.filter_weight.get(pixel_index);
let l = self.pixel_sample_state.l.get(pi);
let camera_weight = self.pixel_sample_state.camera_ray_weight.get(pi);
let weighted_l = l * camera_weight;
let lambda = self.pixel_sample_state.lambda.get(pi);
let filter_weight = self.pixel_sample_state.filter_weight.get(pi);
self.film
.add_sample(p_pixel, weighted_l, &lambda, None, filter_weight);
});
self.film
.add_sample(p_pixel, weighted_l, &lambda, None, filter_weight);
});
}
fn generate_ray_samples(&mut self, depth: u32, sample_index: u32) {
@ -474,7 +568,6 @@ impl CpuWavefrontRenderer {
let sampler_proto = &self.sampler;
(0..n as usize).into_par_iter().for_each(|i| {
let _g = M.lock().unwrap();
let w = unsafe { ray_queue.storage.get(i) };
let pi = w.pixel_index as usize;
let p_pixel = pixel_sample_state.p_pixel.get(pi);

View file

@ -2,3 +2,4 @@ pub mod aggregate;
pub mod integrator;
pub use aggregate::CpuAggregate;
pub use integrator::{CreateWavefront, CpuWavefrontRenderer};