Still broken
This commit is contained in:
parent
f18aed2c91
commit
66032abf76
7 changed files with 246 additions and 218 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ pub mod aggregate;
|
|||
pub mod integrator;
|
||||
|
||||
pub use aggregate::CpuAggregate;
|
||||
pub use integrator::{CreateWavefront, CpuWavefrontRenderer};
|
||||
|
|
|
|||
Loading…
Reference in a new issue