Still broken
This commit is contained in:
parent
66032abf76
commit
3fda37fcd1
7 changed files with 114 additions and 65 deletions
|
|
@ -118,10 +118,7 @@ impl BSDF {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn regularize(&mut self) {
|
pub fn regularize(&mut self) {
|
||||||
if !self.is_valid() {
|
self.bxdf.regularize();
|
||||||
let bxdf = &mut self.bxdf;
|
|
||||||
bxdf.regularize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,13 @@ pub enum Material {
|
||||||
Mix(MixMaterial),
|
Mix(MixMaterial),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Material {
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn is_conductor(&self) -> bool {
|
||||||
|
matches!(self, Material::Conductor(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: THIS IS A HACK JUST FOR TESTING
|
// TODO: THIS IS A HACK JUST FOR TESTING
|
||||||
impl PartialEq for Material {
|
impl PartialEq for Material {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -539,14 +539,14 @@ impl ShapeTrait for TriangleShape {
|
||||||
|
|
||||||
fn intersect(&self, ray: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
fn intersect(&self, ray: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
|
||||||
let [p0, p1, p2] = self.get_points();
|
let [p0, p1, p2] = self.get_points();
|
||||||
let tri_isect = self.intersect_triangle(ray, t_max.unwrap_or(0.), p0, p1, p2)?;
|
let tri_isect = self.intersect_triangle(ray, t_max.unwrap_or(Float::INFINITY), p0, p1, p2)?;
|
||||||
let intr = self.interaction_from_intersection(tri_isect, ray.time, -ray.d);
|
let intr = self.interaction_from_intersection(tri_isect, ray.time, -ray.d);
|
||||||
Some(ShapeIntersection::new(intr, tri_isect.t))
|
Some(ShapeIntersection::new(intr, tri_isect.t))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersect_p(&self, ray: &Ray, t_max: Option<Float>) -> bool {
|
fn intersect_p(&self, ray: &Ray, t_max: Option<Float>) -> bool {
|
||||||
let [p0, p1, p2] = self.get_points();
|
let [p0, p1, p2] = self.get_points();
|
||||||
let tri_isect = self.intersect_triangle(ray, t_max.unwrap_or(0.), p0, p1, p2);
|
let tri_isect = self.intersect_triangle(ray, t_max.unwrap_or(Float::INFINITY), p0, p1, p2);
|
||||||
tri_isect.is_some()
|
tri_isect.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,15 @@ impl SampledWavelengths {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate_secondary_inplace(&mut self) {}
|
pub fn terminate_secondary_inplace(&mut self) {
|
||||||
|
if self.secondary_terminated() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.pdf[0] /= N_SPECTRUM_SAMPLES as Float;
|
||||||
|
for i in 1..N_SPECTRUM_SAMPLES {
|
||||||
|
self.pdf[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sample_uniform(u: Float, lambda_min: Float, lambda_max: Float) -> Self {
|
pub fn sample_uniform(u: Float, lambda_min: Float, lambda_max: Float) -> Self {
|
||||||
let mut lambda = [0.0; N_SPECTRUM_SAMPLES];
|
let mut lambda = [0.0; N_SPECTRUM_SAMPLES];
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,14 @@ pub fn evaluate_pixel_sample<T: RayIntegratorTrait>(
|
||||||
eprintln!(" camera_sample.p_film: {:?}", camera_sample.p_film);
|
eprintln!(" camera_sample.p_film: {:?}", camera_sample.p_film);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"PATH p=({},{}) l={:?} lambda={:?} fw={}",
|
||||||
|
pixel.x(),
|
||||||
|
pixel.y(),
|
||||||
|
l,
|
||||||
|
lambda,
|
||||||
|
camera_sample.filter_weight,
|
||||||
|
);
|
||||||
film.add_sample(
|
film.add_sample(
|
||||||
pixel,
|
pixel,
|
||||||
l,
|
l,
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,6 @@ impl WavefrontAggregate for CpuAggregate {
|
||||||
// Medium transition
|
// Medium transition
|
||||||
if intr.material.is_null() {
|
if intr.material.is_null() {
|
||||||
let mut next = r;
|
let mut next = r;
|
||||||
intr.spawn_ray(r.ray.d);
|
|
||||||
next.ray = intr.spawn_ray(r.ray.d);
|
next.ray = intr.spawn_ray(r.ray.d);
|
||||||
next_ray_q.push(next);
|
next_ray_q.push(next);
|
||||||
return;
|
return;
|
||||||
|
|
@ -143,7 +142,7 @@ impl WavefrontAggregate for CpuAggregate {
|
||||||
(0..n_rays as usize).into_par_iter().for_each(|i| {
|
(0..n_rays as usize).into_par_iter().for_each(|i| {
|
||||||
let work = unsafe { shadow_ray_q.get(i) };
|
let work = unsafe { shadow_ray_q.get(i) };
|
||||||
|
|
||||||
let ray = Ray::new(work.ray_o, work.ray_d, Some(work.ray_time), Ptr::null());
|
let ray = Ray::new(work.ray.o, work.ray.d, Some(work.ray.time), Ptr::null());
|
||||||
if !self.aggregate.intersect_p(&ray, Some(work.t_max)) {
|
if !self.aggregate.intersect_p(&ray, Some(work.t_max)) {
|
||||||
let pi = work.pixel_index as usize;
|
let pi = work.pixel_index as usize;
|
||||||
let ld = work.l_d / (work.r_u + work.r_l).average();
|
let ld = work.l_d / (work.r_u + work.r_l).average();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use crate::lights::sampler::create_light_sampler;
|
||||||
use crate::Arena;
|
use crate::Arena;
|
||||||
use crate::ParameterDictionary;
|
use crate::ParameterDictionary;
|
||||||
use crate::PbrtProgress;
|
use crate::PbrtProgress;
|
||||||
|
use log::debug;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use shared::core::bxdf::{FArgs, TransportMode};
|
use shared::core::bxdf::{FArgs, TransportMode};
|
||||||
use shared::core::camera::{Camera, CameraTrait};
|
use shared::core::camera::{Camera, CameraTrait};
|
||||||
|
|
@ -18,7 +19,7 @@ use shared::core::light::{Light, LightSampleContext, LightTrait};
|
||||||
use shared::core::material::{MaterialEvalContext, MaterialTrait};
|
use shared::core::material::{MaterialEvalContext, MaterialTrait};
|
||||||
use shared::core::primitive::Primitive;
|
use shared::core::primitive::Primitive;
|
||||||
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
|
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
|
||||||
use shared::core::texture::{TextureEvalContext, UniversalTextureEvaluator};
|
use shared::core::texture::{BasicTextureEvaluator, TextureEvalContext, UniversalTextureEvaluator};
|
||||||
use shared::lights::sampler::{LightSampler, LightSamplerTrait};
|
use shared::lights::sampler::{LightSampler, LightSamplerTrait};
|
||||||
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
use shared::spectra::{SampledSpectrum, SampledWavelengths};
|
||||||
use shared::utils::math::square;
|
use shared::utils::math::square;
|
||||||
|
|
@ -26,7 +27,7 @@ use shared::utils::sampling::power_heuristic;
|
||||||
use shared::utils::soa::{SoA, SoAAllocator, WorkQueue};
|
use shared::utils::soa::{SoA, SoAAllocator, WorkQueue};
|
||||||
use shared::wavefront::workitems::*;
|
use shared::wavefront::workitems::*;
|
||||||
use shared::wavefront::{WavefrontAggregate, WavefrontPathIntegrator, WavefrontRenderer};
|
use shared::wavefront::{WavefrontAggregate, WavefrontPathIntegrator, WavefrontRenderer};
|
||||||
use shared::{gvec, Ptr};
|
use shared::{gvec, Ptr, SHADOW_EPSILON};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -74,6 +75,8 @@ where
|
||||||
let scanlines_per_pass = (max_samples / res_x).max(1);
|
let scanlines_per_pass = (max_samples / res_x).max(1);
|
||||||
let max_queue_size = res_x * scanlines_per_pass;
|
let max_queue_size = res_x * scanlines_per_pass;
|
||||||
|
|
||||||
|
eprintln!("wavefront got {} lights", lights.len());
|
||||||
|
|
||||||
let mut infinite_lights = gvec();
|
let mut infinite_lights = gvec();
|
||||||
for light in &lights {
|
for light in &lights {
|
||||||
if light.light_type().is_infinite() {
|
if light.light_type().is_infinite() {
|
||||||
|
|
@ -81,6 +84,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eprintln!("infinite_lights len = {}", infinite_lights.len());
|
||||||
|
|
||||||
// for light in
|
// for light in
|
||||||
|
|
||||||
let cpu_aggregate = CpuAggregate::new(*aggregate);
|
let cpu_aggregate = CpuAggregate::new(*aggregate);
|
||||||
|
|
@ -396,7 +401,9 @@ impl CpuWavefrontRenderer {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let tex_eval = UniversalTextureEvaluator;
|
let _is_cond = material.is_conductor();
|
||||||
|
|
||||||
|
// GetMaterialEvalContext
|
||||||
let ctx = MaterialEvalContext {
|
let ctx = MaterialEvalContext {
|
||||||
texture: TextureEvalContext {
|
texture: TextureEvalContext {
|
||||||
p: w.p.into(),
|
p: w.p.into(),
|
||||||
|
|
@ -414,8 +421,19 @@ impl CpuWavefrontRenderer {
|
||||||
ns: w.ns,
|
ns: w.ns,
|
||||||
dpdus: w.dpdus,
|
dpdus: w.dpdus,
|
||||||
};
|
};
|
||||||
|
|
||||||
let lambda = w.lambda;
|
let lambda = w.lambda;
|
||||||
let mut bsdf = material.get_bsdf(&tex_eval, &ctx, &lambda);
|
|
||||||
|
let mut bsdf = if use_universal {
|
||||||
|
material.get_bsdf(&UniversalTextureEvaluator, &ctx, &lambda)
|
||||||
|
} else {
|
||||||
|
material.get_bsdf(&BasicTextureEvaluator, &ctx, &lambda)
|
||||||
|
};
|
||||||
|
|
||||||
|
if lambda.secondary_terminated() {
|
||||||
|
pixel_sample_state.lambda.set(pi, lambda);
|
||||||
|
}
|
||||||
|
|
||||||
if bsdf.flags().is_empty() {
|
if bsdf.flags().is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -446,6 +464,7 @@ impl CpuWavefrontRenderer {
|
||||||
let q = (1.0 - rr_beta).max(0.0_f32);
|
let q = (1.0 - rr_beta).max(0.0_f32);
|
||||||
if rs.indirect.rr < q {
|
if rs.indirect.rr < q {
|
||||||
beta = SampledSpectrum::new(0.0);
|
beta = SampledSpectrum::new(0.0);
|
||||||
|
debug!("Path terminated with RR");
|
||||||
} else {
|
} else {
|
||||||
beta /= 1.0 - q;
|
beta /= 1.0 - q;
|
||||||
}
|
}
|
||||||
|
|
@ -479,62 +498,73 @@ impl CpuWavefrontRenderer {
|
||||||
// Direct lighting
|
// Direct lighting
|
||||||
let flags = bsdf.flags();
|
let flags = bsdf.flags();
|
||||||
if flags.is_non_specular() {
|
if flags.is_non_specular() {
|
||||||
let light_ctx = LightSampleContext {
|
let mut light_ctx = LightSampleContext {
|
||||||
pi: w.p,
|
pi: w.p,
|
||||||
n: w.n,
|
n: w.n,
|
||||||
ns,
|
ns,
|
||||||
};
|
};
|
||||||
if let Some(sampled_light) =
|
|
||||||
light_sampler.sample_with_context(&light_ctx, rs.direct.uc)
|
|
||||||
{
|
|
||||||
if let Some(ls) =
|
|
||||||
sampled_light
|
|
||||||
.light
|
|
||||||
.sample_li(&light_ctx, rs.direct.u, &lambda, true)
|
|
||||||
{
|
|
||||||
if !ls.l.is_black() && ls.pdf > 0.0 {
|
|
||||||
let wi = ls.wi;
|
|
||||||
if let Some(f) = bsdf.f(wo, wi, TransportMode::Radiance) {
|
|
||||||
if !f.is_black() {
|
|
||||||
let beta = w.beta * f * wi.abs_dot(ns.into());
|
|
||||||
let light_pdf = ls.pdf * sampled_light.p;
|
|
||||||
let bsdf_pdf =
|
|
||||||
if sampled_light.light.light_type().is_delta_light() {
|
|
||||||
0.0
|
|
||||||
} else {
|
|
||||||
bsdf.pdf(wo, wi, FArgs::default())
|
|
||||||
};
|
|
||||||
let r_u = w.r_u * bsdf_pdf;
|
|
||||||
let r_l = w.r_u * light_pdf;
|
|
||||||
let ld = beta * ls.l;
|
|
||||||
|
|
||||||
let ray_o = Ray::spawn_to_interaction(
|
if flags.is_reflective() && !flags.is_transmissive() {
|
||||||
&w.p,
|
light_ctx.pi = Point3fi::new_from_point(Ray::offset_origin(&w.p, &w.n, &(-wo)));
|
||||||
&w.n,
|
} else if flags.is_transmissive() && flags.is_reflective() {
|
||||||
w.time,
|
light_ctx.pi = Point3fi::new_from_point(Ray::offset_origin(&w.p, &w.n, &(-wo)));
|
||||||
&ls.p_light.pi(),
|
|
||||||
&ls.p_light.n(),
|
|
||||||
);
|
|
||||||
let t_max = (1.0 - 1e-4)
|
|
||||||
* (Point3f::from(ls.p_light.p()) - ray_o.o).norm()
|
|
||||||
/ wi.norm();
|
|
||||||
|
|
||||||
shadow_ray_queue.push(ShadowRayWorkItem {
|
|
||||||
ray_o: ray_o.o,
|
|
||||||
ray_d: ray_o.d,
|
|
||||||
ray_time: w.time,
|
|
||||||
t_max: 1.0 - 1e-4,
|
|
||||||
lambda,
|
|
||||||
l_d: ld,
|
|
||||||
r_u,
|
|
||||||
r_l,
|
|
||||||
pixel_index: w.pixel_index,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Some(sampled_light) =
|
||||||
|
light_sampler.sample_with_context(&light_ctx, rs.direct.uc)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(ls) =
|
||||||
|
sampled_light
|
||||||
|
.light
|
||||||
|
.sample_li(&light_ctx, rs.direct.u, &lambda, true)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ls.l.is_black() || ls.pdf <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wi = ls.wi;
|
||||||
|
let Some(f) = bsdf.f(wo, wi, TransportMode::Radiance) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if f.is_black() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let beta = w.beta * f * wi.abs_dot(ns.into());
|
||||||
|
let light_pdf = ls.pdf * sampled_light.p;
|
||||||
|
let bsdf_pdf = if sampled_light.light.light_type().is_delta_light() {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
bsdf.pdf(wo, wi, FArgs::default())
|
||||||
|
};
|
||||||
|
let r_u = w.r_u * bsdf_pdf;
|
||||||
|
let r_l = w.r_u * light_pdf;
|
||||||
|
let l_d = beta * ls.l;
|
||||||
|
|
||||||
|
let ray = Ray::spawn_to_interaction(
|
||||||
|
&w.p,
|
||||||
|
&w.n,
|
||||||
|
w.time,
|
||||||
|
&ls.p_light.pi(),
|
||||||
|
&ls.p_light.n(),
|
||||||
|
);
|
||||||
|
|
||||||
|
shadow_ray_queue.push(ShadowRayWorkItem {
|
||||||
|
ray,
|
||||||
|
t_max: 1.0 - SHADOW_EPSILON,
|
||||||
|
lambda,
|
||||||
|
l_d,
|
||||||
|
r_u,
|
||||||
|
r_l,
|
||||||
|
pixel_index: w.pixel_index,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -563,19 +593,19 @@ impl CpuWavefrontRenderer {
|
||||||
let current = (depth % 2) as usize;
|
let current = (depth % 2) as usize;
|
||||||
let ray_queue = &self.ray_queues[current];
|
let ray_queue = &self.ray_queues[current];
|
||||||
let n = ray_queue.size();
|
let n = ray_queue.size();
|
||||||
let dimension = 6 + 7 * depth;
|
|
||||||
let pixel_sample_state = &self.pixel_sample_state;
|
let pixel_sample_state = &self.pixel_sample_state;
|
||||||
let sampler_proto = &self.sampler;
|
let sampler_proto = &self.sampler;
|
||||||
|
|
||||||
(0..n as usize).into_par_iter().for_each(|i| {
|
(0..n as usize).into_par_iter().for_each(|i| {
|
||||||
let w = unsafe { ray_queue.storage.get(i) };
|
let w = unsafe { ray_queue.storage.get(i) };
|
||||||
|
let dimension = 6 + 7 * w.depth;
|
||||||
let pi = w.pixel_index as usize;
|
let pi = w.pixel_index as usize;
|
||||||
let p_pixel = pixel_sample_state.p_pixel.get(pi);
|
let p_pixel = pixel_sample_state.p_pixel.get(pi);
|
||||||
|
|
||||||
let mut sampler = sampler_proto.clone();
|
let mut sampler = sampler_proto.clone();
|
||||||
sampler.start_pixel_sample(p_pixel, sample_index as i32, Some(dimension));
|
sampler.start_pixel_sample(p_pixel, sample_index as i32, Some(dimension));
|
||||||
|
|
||||||
self.pixel_sample_state.samples.set(
|
pixel_sample_state.samples.set(
|
||||||
pi,
|
pi,
|
||||||
RaySamples {
|
RaySamples {
|
||||||
direct: DirectSamples {
|
direct: DirectSamples {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue