Fixed logic issues in BSDF sampling and pdf calculations, moving on to GPU integrators
This commit is contained in:
parent
3cb2086f6d
commit
0c62fbc3b5
25 changed files with 202 additions and 163 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::core::bsdf::BSDFSample;
|
use crate::core::bsdf::BSDFSample;
|
||||||
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
||||||
use crate::core::geometry::{
|
use crate::core::geometry::{
|
||||||
Normal3f, Point2f, Vector3f, VectorLike, abs_cos_theta, same_hemisphere,
|
abs_cos_theta, same_hemisphere, Normal3f, Point2f, Vector3f, VectorLike,
|
||||||
};
|
};
|
||||||
use crate::core::scattering::{TrowbridgeReitzDistribution, fr_complex_from_spectrum, reflect};
|
use crate::core::scattering::{fr_complex_from_spectrum, reflect, TrowbridgeReitzDistribution};
|
||||||
use crate::spectra::SampledSpectrum;
|
use crate::spectra::SampledSpectrum;
|
||||||
use crate::utils::sampling::{cosine_hemisphere_pdf, sample_cosine_hemisphere};
|
use crate::utils::sampling::{cosine_hemisphere_pdf, sample_cosine_hemisphere};
|
||||||
use crate::{Float, INV_PI};
|
use crate::{Float, INV_PI};
|
||||||
|
|
@ -84,7 +84,7 @@ impl BxDFTrait for ConductorBxDF {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let f_spectrum = fr_complex_from_spectrum(wo.dot(wi).abs(), self.eta, self.k);
|
let f_spectrum = fr_complex_from_spectrum(wo.dot(wm).abs(), self.eta, self.k);
|
||||||
let f = self.mf_distrib.d(wm) * f_spectrum * self.mf_distrib.g(wo, wi)
|
let f = self.mf_distrib.d(wm) * f_spectrum * self.mf_distrib.g(wo, wi)
|
||||||
/ (4. * cos_theta_i * cos_theta_o);
|
/ (4. * cos_theta_i * cos_theta_o);
|
||||||
|
|
||||||
|
|
@ -118,8 +118,7 @@ impl BxDFTrait for ConductorBxDF {
|
||||||
return SampledSpectrum::new(0.);
|
return SampledSpectrum::new(0.);
|
||||||
}
|
}
|
||||||
let wm_norm = wm.normalize();
|
let wm_norm = wm.normalize();
|
||||||
|
let f_spectrum = fr_complex_from_spectrum(wo.dot(wm_norm).abs(), self.eta, self.k);
|
||||||
let f_spectrum = fr_complex_from_spectrum(wo.dot(wm).abs(), self.eta, self.k);
|
|
||||||
self.mf_distrib.d(wm_norm) * f_spectrum * self.mf_distrib.g(wo, wi)
|
self.mf_distrib.d(wm_norm) * f_spectrum * self.mf_distrib.g(wo, wi)
|
||||||
/ (4. * cos_theta_i * cos_theta_o)
|
/ (4. * cos_theta_i * cos_theta_o)
|
||||||
}
|
}
|
||||||
|
|
@ -140,8 +139,9 @@ impl BxDFTrait for ConductorBxDF {
|
||||||
if wm.norm_squared() == 0. {
|
if wm.norm_squared() == 0. {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
let wm_corr = Normal3f::new(0., 0., 1.).face_forward(wm);
|
let wm_norm = Normal3f::from(wm.normalize());
|
||||||
self.mf_distrib.pdf(wo, wm_corr.into()) / (4. * wo.dot(wm).abs())
|
let wm_corr = wm_norm.face_forward(Vector3f::new(0., 0., 1.));
|
||||||
|
self.mf_distrib.pdf(wo, wm_corr.into()) / (4. * wo.dot(Vector3f::from(wm_norm)).abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regularize(&mut self) {
|
fn regularize(&mut self) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::core::bsdf::BSDFSample;
|
use crate::core::bsdf::BSDFSample;
|
||||||
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
||||||
use crate::core::geometry::{
|
use crate::core::geometry::{
|
||||||
Normal3f, Point2f, Vector3f, VectorLike, abs_cos_theta, cos_theta, same_hemisphere,
|
abs_cos_theta, cos_theta, same_hemisphere, Normal3f, Point2f, Vector3f, VectorLike,
|
||||||
};
|
};
|
||||||
use crate::core::scattering::{
|
use crate::core::scattering::{
|
||||||
TrowbridgeReitzDistribution, fr_complex_from_spectrum, fr_dielectric, reflect, refract,
|
fr_complex_from_spectrum, fr_dielectric, reflect, refract, TrowbridgeReitzDistribution,
|
||||||
};
|
};
|
||||||
use crate::spectra::SampledSpectrum;
|
use crate::spectra::SampledSpectrum;
|
||||||
use crate::utils::math::square;
|
use crate::utils::math::square;
|
||||||
|
|
@ -141,14 +141,11 @@ impl BxDFTrait for DielectricBxDF {
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflect {
|
if reflect {
|
||||||
self.mf_distrib.pdf(
|
self.mf_distrib.pdf(wo, wm.into()) / (4. * wo.dot(wm.into()).abs()) * pr / (pr + pt)
|
||||||
wo,
|
|
||||||
Vector3f::from(wm) / (4. * wo.dot(wm.into()).abs()) * pr / (pt + pr),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let denom = square(wi.dot(wm.into()) + wo.dot(wm.into()) / etap);
|
let denom = square(wi.dot(wm.into()) + wo.dot(wm.into()) / etap);
|
||||||
let dwm_dwi = wi.dot(wm.into()).abs() / denom;
|
let dwm_dwi = wi.dot(wm.into()).abs() / denom;
|
||||||
self.mf_distrib.pdf(wo, wm.into()) * dwm_dwi * pr / (pr + pt)
|
self.mf_distrib.pdf(wo, wm.into()) * dwm_dwi * pt / (pr + pt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ impl BxDFTrait for DiffuseBxDF {
|
||||||
|
|
||||||
fn pdf(&self, wo: Vector3f, wi: Vector3f, f_args: FArgs) -> Float {
|
fn pdf(&self, wo: Vector3f, wi: Vector3f, f_args: FArgs) -> Float {
|
||||||
let reflection_flags =
|
let reflection_flags =
|
||||||
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::ALL.bits());
|
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::REFLECTION.bits());
|
||||||
if !f_args.sample_flags.contains(reflection_flags) || !same_hemisphere(wo, wi) {
|
if !f_args.sample_flags.contains(reflection_flags) || !same_hemisphere(wo, wi) {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ use crate::core::bsdf::BSDFSample;
|
||||||
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
use crate::core::bxdf::{BxDFFlags, BxDFReflTransFlags, BxDFTrait, FArgs, TransportMode};
|
||||||
use crate::core::color::RGB;
|
use crate::core::color::RGB;
|
||||||
use crate::core::geometry::{
|
use crate::core::geometry::{
|
||||||
Frame, Normal3f, Point2f, Vector3f, VectorLike, abs_cos_theta, cos_theta, same_hemisphere,
|
abs_cos_theta, cos_theta, same_hemisphere, spherical_direction, spherical_theta, Frame,
|
||||||
spherical_direction, spherical_theta,
|
Normal3f, Point2f, Vector3f, VectorLike,
|
||||||
};
|
};
|
||||||
use crate::core::medium::{HGPhaseFunction, PhaseFunctionTrait};
|
use crate::core::medium::{HGPhaseFunction, PhaseFunctionTrait};
|
||||||
use crate::core::scattering::{
|
use crate::core::scattering::{
|
||||||
TrowbridgeReitzDistribution, fr_complex, fr_complex_from_spectrum, fr_dielectric, reflect,
|
fr_complex, fr_complex_from_spectrum, fr_dielectric, reflect, refract,
|
||||||
refract,
|
TrowbridgeReitzDistribution,
|
||||||
};
|
};
|
||||||
use crate::spectra::{
|
use crate::spectra::{
|
||||||
DeviceStandardColorSpaces, N_SPECTRUM_SAMPLES, RGBColorSpace, RGBUnboundedSpectrum,
|
DeviceStandardColorSpaces, RGBColorSpace, RGBUnboundedSpectrum, SampledSpectrum,
|
||||||
SampledSpectrum, SampledWavelengths,
|
SampledWavelengths, N_SPECTRUM_SAMPLES,
|
||||||
};
|
};
|
||||||
use crate::utils::hash::hash_buffer;
|
use crate::utils::hash::hash_buffer;
|
||||||
use crate::utils::math::{
|
use crate::utils::math::{
|
||||||
|
|
@ -24,8 +24,8 @@ use crate::utils::math::{
|
||||||
};
|
};
|
||||||
use crate::utils::rng::Rng;
|
use crate::utils::rng::Rng;
|
||||||
use crate::utils::sampling::{
|
use crate::utils::sampling::{
|
||||||
PiecewiseLinear2D, cosine_hemisphere_pdf, power_heuristic, sample_cosine_hemisphere,
|
cosine_hemisphere_pdf, power_heuristic, sample_cosine_hemisphere, sample_exponential,
|
||||||
sample_exponential, sample_trimmed_logistic, sample_uniform_hemisphere, uniform_hemisphere_pdf,
|
sample_trimmed_logistic, sample_uniform_hemisphere, uniform_hemisphere_pdf, PiecewiseLinear2D,
|
||||||
};
|
};
|
||||||
use crate::{Float, INV_2_PI, INV_4_PI, INV_PI, ONE_MINUS_EPSILON, PI, PI_OVER_2};
|
use crate::{Float, INV_2_PI, INV_4_PI, INV_PI, ONE_MINUS_EPSILON, PI, PI_OVER_2};
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
@ -173,6 +173,12 @@ where
|
||||||
mode,
|
mode,
|
||||||
sample_flags: BxDFReflTransFlags::TRANSMISSION,
|
sample_flags: BxDFReflTransFlags::TRANSMISSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let reverse_trans_args = FArgs {
|
||||||
|
mode: !mode,
|
||||||
|
sample_flags: BxDFReflTransFlags::TRANSMISSION,
|
||||||
|
};
|
||||||
|
|
||||||
let refl_args = FArgs {
|
let refl_args = FArgs {
|
||||||
mode,
|
mode,
|
||||||
sample_flags: BxDFReflTransFlags::REFLECTION,
|
sample_flags: BxDFReflTransFlags::REFLECTION,
|
||||||
|
|
@ -188,7 +194,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(wis) = exit_interface
|
let Some(wis) = exit_interface
|
||||||
.sample_f(wi, r(), Point2f::new(r(), r()), trans_args)
|
.sample_f(wi, r(), Point2f::new(r(), r()), reverse_trans_args)
|
||||||
.filter(|s| !s.f.is_black() && s.pdf > 0.0 && s.wi.z() != 0.0)
|
.filter(|s| !s.f.is_black() && s.pdf > 0.0 && s.wi.z() != 0.0)
|
||||||
else {
|
else {
|
||||||
return SampledSpectrum::new(0.0);
|
return SampledSpectrum::new(0.0);
|
||||||
|
|
@ -226,18 +232,21 @@ where
|
||||||
let sigma_t = 1.0;
|
let sigma_t = 1.0;
|
||||||
let dz = sample_exponential(r(), sigma_t / w.z().abs());
|
let dz = sample_exponential(r(), sigma_t / w.z().abs());
|
||||||
let zp = if w.z() > 0.0 { z + dz } else { z - dz };
|
let zp = if w.z() > 0.0 { z + dz } else { z - dz };
|
||||||
|
if zp == z {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if zp > 0.0 && zp < self.thickness {
|
if zp > 0.0 && zp < self.thickness {
|
||||||
// Handle scattering event in layered BSDF medium
|
// Handle scattering event in layered BSDF medium
|
||||||
let wt = if exit_interface.flags().is_specular() {
|
let wt = if !exit_interface.flags().is_specular() {
|
||||||
power_heuristic(1, wis.pdf, 1, phase.pdf(-w, wis.wi))
|
power_heuristic(1, wis.pdf, 1, phase.pdf(-w, -wis.wi))
|
||||||
} else {
|
} else {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
f += beta
|
f += beta
|
||||||
* self.albedo
|
* self.albedo
|
||||||
* phase.p(-wi, -wis.wi)
|
* phase.p(-w, -wis.wi)
|
||||||
* wt
|
* wt
|
||||||
* self.tr(zp - exit_z, wis.wi)
|
* self.tr(zp - exit_z, wis.wi)
|
||||||
* wis.f
|
* wis.f
|
||||||
|
|
@ -257,7 +266,7 @@ where
|
||||||
|
|
||||||
// Account for scattering through exit
|
// Account for scattering through exit
|
||||||
if (z < exit_z && w.z() > 0.0) || (z > exit_z && w.z() < 0.0) {
|
if (z < exit_z && w.z() > 0.0) || (z > exit_z && w.z() < 0.0) {
|
||||||
let f_exit = exit_interface.f(-w, -wi, mode);
|
let f_exit = exit_interface.f(-w, wi, mode);
|
||||||
if !f_exit.is_black() {
|
if !f_exit.is_black() {
|
||||||
let exit_pdf = exit_interface.pdf(-w, wi, trans_args);
|
let exit_pdf = exit_interface.pdf(-w, wi, trans_args);
|
||||||
let wt = power_heuristic(1, ps.pdf, 1, exit_pdf);
|
let wt = power_heuristic(1, ps.pdf, 1, exit_pdf);
|
||||||
|
|
@ -283,7 +292,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
// Hitting the non-exit surface -> Reflection
|
// Hitting the non-exit surface -> Reflection
|
||||||
if !non_exit_interface.flags().is_specular() {
|
if !non_exit_interface.flags().is_specular() {
|
||||||
let wt = if exit_interface.flags().is_specular() {
|
let wt = if !exit_interface.flags().is_specular() {
|
||||||
power_heuristic(
|
power_heuristic(
|
||||||
1,
|
1,
|
||||||
wis.pdf,
|
wis.pdf,
|
||||||
|
|
@ -308,7 +317,7 @@ where
|
||||||
.sample_f(-w, r(), Point2f::new(r(), r()), refl_args)
|
.sample_f(-w, r(), Point2f::new(r(), r()), refl_args)
|
||||||
.filter(|s| !s.f.is_black() && s.pdf > 0.0 && s.wi.z() != 0.0)
|
.filter(|s| !s.f.is_black() && s.pdf > 0.0 && s.wi.z() != 0.0)
|
||||||
else {
|
else {
|
||||||
continue;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
beta *= bs.f * abs_cos_theta(bs.wi) / bs.pdf;
|
beta *= bs.f * abs_cos_theta(bs.wi) / bs.pdf;
|
||||||
|
|
@ -319,7 +328,7 @@ where
|
||||||
let f_exit = exit_interface.f(-w, wi, mode);
|
let f_exit = exit_interface.f(-w, wi, mode);
|
||||||
if !f_exit.is_black() {
|
if !f_exit.is_black() {
|
||||||
let mut wt = 1.0;
|
let mut wt = 1.0;
|
||||||
if non_exit_interface.flags().is_specular() {
|
if !non_exit_interface.flags().is_specular() {
|
||||||
wt = power_heuristic(
|
wt = power_heuristic(
|
||||||
1,
|
1,
|
||||||
bs.pdf,
|
bs.pdf,
|
||||||
|
|
@ -476,7 +485,7 @@ where
|
||||||
}
|
}
|
||||||
pdf *= 1. - q;
|
pdf *= 1. - q;
|
||||||
}
|
}
|
||||||
if w.z() < 0. {
|
if w.z() == 0. {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,12 +493,15 @@ where
|
||||||
let sigma_t = 1.;
|
let sigma_t = 1.;
|
||||||
let dz = sample_exponential(r(), sigma_t / abs_cos_theta(w));
|
let dz = sample_exponential(r(), sigma_t / abs_cos_theta(w));
|
||||||
let zp = if w.z() > 0. { z + dz } else { z - dz };
|
let zp = if w.z() > 0. { z + dz } else { z - dz };
|
||||||
|
if zp == z {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if zp > 0. && zp < self.thickness {
|
if zp > 0. && zp < self.thickness {
|
||||||
let Some(ps) = phase
|
let Some(ps) = phase
|
||||||
.sample_p(-wo, Point2f::new(r(), r()))
|
.sample_p(-w, Point2f::new(r(), r()))
|
||||||
.filter(|s| s.pdf == 0. && s.wi.z() == 0.)
|
.filter(|s| s.pdf != 0. && s.wi.z() != 0.)
|
||||||
else {
|
else {
|
||||||
continue;
|
return None;
|
||||||
};
|
};
|
||||||
f *= self.albedo * ps.p;
|
f *= self.albedo * ps.p;
|
||||||
pdf *= ps.pdf;
|
pdf *= ps.pdf;
|
||||||
|
|
@ -518,7 +530,7 @@ where
|
||||||
// Sample interface BSDF to determine new path direction
|
// Sample interface BSDF to determine new path direction
|
||||||
let bs = interface
|
let bs = interface
|
||||||
.sample_f(-w, r(), Point2f::new(r(), r()), f_args)
|
.sample_f(-w, r(), Point2f::new(r(), r()), f_args)
|
||||||
.filter(|s| s.f.is_black() && s.pdf == 0. && s.wi.z() == 0.)?;
|
.filter(|s| !s.f.is_black() && s.pdf != 0. && s.wi.z() != 0.)?;
|
||||||
f *= bs.f;
|
f *= bs.f;
|
||||||
pdf *= bs.pdf;
|
pdf *= bs.pdf;
|
||||||
specular_path &= bs.is_specular();
|
specular_path &= bs.is_specular();
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ impl BSDF {
|
||||||
|
|
||||||
let sampling_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits());
|
let sampling_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits());
|
||||||
let wo = self.render_to_local(wo_render);
|
let wo = self.render_to_local(wo_render);
|
||||||
if wo.z() == 0.0 || !bxdf.flags().contains(sampling_flags) {
|
if wo.z() == 0.0 || !bxdf.flags().intersects(sampling_flags) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ impl BSDF {
|
||||||
let wo = self.render_to_local(wo_render);
|
let wo = self.render_to_local(wo_render);
|
||||||
let wi = self.render_to_local(wi_render);
|
let wi = self.render_to_local(wi_render);
|
||||||
|
|
||||||
if wo.z() == 0.0 || !self.bxdf.flags().contains(sample_flags) {
|
if wo.z() == 0.0 || !self.bxdf.flags().intersects(sample_flags) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
use super::{Normal3f, Point3f, Point3fi, Vector3f, VectorLike};
|
use super::{Normal3f, Point3f, Point3fi, Vector3f, VectorLike};
|
||||||
use crate::core::medium::Medium;
|
use crate::core::medium::Medium;
|
||||||
use crate::core::pbrt::Float;
|
|
||||||
use crate::utils::math::{next_float_down, next_float_up};
|
use crate::utils::math::{next_float_down, next_float_up};
|
||||||
use crate::utils::ptr::Ptr;
|
use crate::{gvec_with_capacity, Float, GVec, Ptr, SOA};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|
@ -124,3 +123,56 @@ pub struct RayDifferential {
|
||||||
pub rx_direction: Vector3f,
|
pub rx_direction: Vector3f,
|
||||||
pub ry_direction: Vector3f,
|
pub ry_direction: Vector3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RaySoA {
|
||||||
|
pub o: GVec<Point3f>,
|
||||||
|
pub d: GVec<Vector3f>,
|
||||||
|
pub time: GVec<Float>,
|
||||||
|
pub medium: GVec<Ptr<Medium>>,
|
||||||
|
pub has_differentials: GVec<bool>,
|
||||||
|
pub differential: GVec<RayDifferential>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoA for RaySoA {
|
||||||
|
type Item = Ray;
|
||||||
|
|
||||||
|
fn with_capacity(n: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
o: gvec_with_capacity(n),
|
||||||
|
d: gvec_with_capacity(n),
|
||||||
|
time: gvec_with_capacity(n),
|
||||||
|
medium: gvec_with_capacity(n),
|
||||||
|
has_differentials: gvec_with_capacity(n),
|
||||||
|
differential: gvec_with_capacity(n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.o.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_unchecked(&self, i: usize) -> Ray {
|
||||||
|
Ray {
|
||||||
|
o: *self.o.get_unchecked(i),
|
||||||
|
d: *self.d.get_unchecked(i),
|
||||||
|
time: *self.time.get_unchecked(i),
|
||||||
|
medium: *self.medium.get_unchecked(i),
|
||||||
|
has_differentials: *self.has_differentials.get_unchecked(i),
|
||||||
|
differential: *self.differential.get_unchecked(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn set_unchecked(&mut self, i: usize, v: Ray) {
|
||||||
|
*self.o.get_unchecked_mut(i) = v.o;
|
||||||
|
*self.d.get_unchecked_mut(i) = v.d;
|
||||||
|
*self.time.get_unchecked_mut(i) = v.time;
|
||||||
|
*self.medium.get_unchecked_mut(i) = v.medium;
|
||||||
|
*self.has_differentials.get_unchecked_mut(i) = v.has_differentials;
|
||||||
|
*self.differential.get_unchecked_mut(i) = v.differential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoAElement for Ray {
|
||||||
|
type SoA = RaySoA;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::core::geometry::{
|
use crate::core::geometry::{
|
||||||
Normal3f, Point2f, Vector2f, Vector3f, VectorLike, abs_cos_theta, cos_phi, cos2_theta, sin_phi,
|
abs_cos_theta, cos2_theta, cos_phi, sin_phi, tan2_theta, Normal3f, Point2f, Vector2f, Vector3f,
|
||||||
tan2_theta,
|
VectorLike,
|
||||||
};
|
};
|
||||||
use crate::core::pbrt::{Float, PI};
|
use crate::core::pbrt::{Float, PI};
|
||||||
use crate::spectra::{N_SPECTRUM_SAMPLES, SampledSpectrum};
|
use crate::spectra::{SampledSpectrum, N_SPECTRUM_SAMPLES};
|
||||||
use crate::utils::math::{clamp, lerp, safe_sqrt, square};
|
use crate::utils::math::{clamp, lerp, safe_sqrt, square};
|
||||||
use crate::utils::sampling::sample_uniform_disk_polar;
|
use crate::utils::sampling::sample_uniform_disk_polar;
|
||||||
use num_traits::Float as NumFloat;
|
use num_traits::Float as NumFloat;
|
||||||
|
|
@ -18,7 +18,11 @@ pub struct TrowbridgeReitzDistribution {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrowbridgeReitzDistribution {
|
impl TrowbridgeReitzDistribution {
|
||||||
pub fn new(alpha_x: Float, alpha_y: Float) -> Self {
|
pub fn new(mut alpha_x: Float, mut alpha_y: Float) -> Self {
|
||||||
|
if alpha_x.max(alpha_y) >= 1e-3 {
|
||||||
|
alpha_x = alpha_x.max(1e-4);
|
||||||
|
alpha_y = alpha_y.max(1e-4);
|
||||||
|
}
|
||||||
Self { alpha_x, alpha_y }
|
Self { alpha_x, alpha_y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,8 +32,13 @@ impl TrowbridgeReitzDistribution {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
let cos4_theta = square(cos2_theta(wm));
|
let cos4_theta = square(cos2_theta(wm));
|
||||||
|
|
||||||
|
if cos4_theta < 1e-16 {
|
||||||
|
return 0.;
|
||||||
|
}
|
||||||
let e =
|
let e =
|
||||||
tan2_theta * (square(cos_phi(wm) / self.alpha_x) + square(sin_phi(wm) / self.alpha_y));
|
tan2_theta * (square(cos_phi(wm) / self.alpha_x) + square(sin_phi(wm) / self.alpha_y));
|
||||||
|
|
||||||
1.0 / (PI * self.alpha_x * self.alpha_y * cos4_theta * square(1. + e))
|
1.0 / (PI * self.alpha_x * self.alpha_y * cos4_theta * square(1. + e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +60,7 @@ impl TrowbridgeReitzDistribution {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn g1(&self, w: Vector3f) -> Float {
|
pub fn g1(&self, w: Vector3f) -> Float {
|
||||||
1. / (1. / self.lambda(w))
|
1. / (1. + self.lambda(w))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn d_from_w(&self, w: Vector3f, wm: Vector3f) -> Float {
|
pub fn d_from_w(&self, w: Vector3f, wm: Vector3f) -> Float {
|
||||||
|
|
@ -76,7 +85,7 @@ impl TrowbridgeReitzDistribution {
|
||||||
let mut p = sample_uniform_disk_polar(u);
|
let mut p = sample_uniform_disk_polar(u);
|
||||||
let h = (1. - square(p.x())).sqrt();
|
let h = (1. - square(p.x())).sqrt();
|
||||||
p[1] = lerp((1. + wh.z()) / 2., h, p.y());
|
p[1] = lerp((1. + wh.z()) / 2., h, p.y());
|
||||||
let pz = 0_f32.max(1. - Vector2f::from(p).norm_squared());
|
let pz = (1. - Vector2f::from(p).norm_squared()).max(0.).sqrt();
|
||||||
let nh = p.x() * t1 + p.y() * t2 + pz * wh;
|
let nh = p.x() * t1 + p.y() * t2 + pz * wh;
|
||||||
Vector3f::new(
|
Vector3f::new(
|
||||||
self.alpha_x * nh.x(),
|
self.alpha_x * nh.x(),
|
||||||
|
|
@ -158,7 +167,7 @@ pub fn fr_complex(cos_theta_i: Float, eta: Complex) -> Float {
|
||||||
let r_parl = (eta * cos_corr - cos2_theta_t) / (eta * cos_corr + cos2_theta_t);
|
let r_parl = (eta * cos_corr - cos2_theta_t) / (eta * cos_corr + cos2_theta_t);
|
||||||
let r_perp = (cos_corr - eta * cos2_theta_t) / (cos_corr + eta * cos2_theta_t);
|
let r_perp = (cos_corr - eta * cos2_theta_t) / (cos_corr + eta * cos2_theta_t);
|
||||||
|
|
||||||
(r_parl.norm() + r_perp.norm()) / 2.
|
(square(r_parl.norm()) + square(r_perp.norm())) / 2.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fr_complex_from_spectrum(
|
pub fn fr_complex_from_spectrum(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@ pub mod shapes;
|
||||||
pub mod spectra;
|
pub mod spectra;
|
||||||
pub mod textures;
|
pub mod textures;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod wavefront;
|
||||||
|
|
||||||
pub use core::pbrt::*;
|
pub use core::pbrt::*;
|
||||||
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, leak, GBox, GVec};
|
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, leak, GBox, GVec};
|
||||||
pub use utils::{Array2D, PBRTOptions, Ptr, Transform};
|
pub use utils::{Array2D, PBRTOptions, Ptr, Transform, SOA};
|
||||||
|
pub use wavefront::{WavefrontAggregate, WorkQueue};
|
||||||
|
|
|
||||||
|
|
@ -320,7 +320,6 @@ impl TriangleShape {
|
||||||
determinant: Float,
|
determinant: Float,
|
||||||
degenerate_uv: bool,
|
degenerate_uv: bool,
|
||||||
) {
|
) {
|
||||||
// Interpolate vertex normals if they exist
|
|
||||||
let ns = if let Some(normals) = self.get_shading_normals() {
|
let ns = if let Some(normals) = self.get_shading_normals() {
|
||||||
let n = ti.b0 * normals[0] + ti.b1 * normals[1] + ti.b2 * normals[2];
|
let n = ti.b0 * normals[0] + ti.b1 * normals[1] + ti.b2 * normals[2];
|
||||||
if n.norm_squared() > 0.0 {
|
if n.norm_squared() > 0.0 {
|
||||||
|
|
@ -332,7 +331,6 @@ impl TriangleShape {
|
||||||
isect.n()
|
isect.n()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Interpolate tangents if they exist
|
|
||||||
let mut ss = if let Some(tangents) = self.get_tangents() {
|
let mut ss = if let Some(tangents) = self.get_tangents() {
|
||||||
let s = ti.b0 * tangents[0] + ti.b1 * tangents[1] + ti.b2 * tangents[2];
|
let s = ti.b0 * tangents[0] + ti.b1 * tangents[1] + ti.b2 * tangents[2];
|
||||||
if s.norm_squared() > 0.0 {
|
if s.norm_squared() > 0.0 {
|
||||||
|
|
@ -344,7 +342,6 @@ impl TriangleShape {
|
||||||
dpdu_geom
|
dpdu_geom
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure shading tangent (ss) is perpendicular to shading normal (ns)
|
|
||||||
let mut ts = ns.cross(ss.into());
|
let mut ts = ns.cross(ss.into());
|
||||||
if ts.norm_squared() > 0.0 {
|
if ts.norm_squared() > 0.0 {
|
||||||
ss = ts.cross(ns.into()).into();
|
ss = ts.cross(ns.into()).into();
|
||||||
|
|
@ -354,7 +351,6 @@ impl TriangleShape {
|
||||||
ts = t.into();
|
ts = t.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// How does the normal change as we move across UVs?
|
|
||||||
let (dndu, dndv) = if let Some(normals) = self.get_shading_normals() {
|
let (dndu, dndv) = if let Some(normals) = self.get_shading_normals() {
|
||||||
if degenerate_uv {
|
if degenerate_uv {
|
||||||
let dn = (normals[2] - normals[0]).cross(normals[1] - normals[0]);
|
let dn = (normals[2] - normals[0]).cross(normals[1] - normals[0]);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::core::pbrt::Float;
|
use crate::core::pbrt::Float;
|
||||||
use crate::core::spectrum::{SpectrumTrait, StandardSpectra};
|
use crate::core::spectrum::{SpectrumTrait, StandardSpectra};
|
||||||
use crate::utils::gpu_array_from_fn;
|
use crate::utils::gpu_array_from_fn;
|
||||||
use crate::utils::math::{clamp, lerp};
|
use crate::utils::math::{clamp, lerp, square};
|
||||||
use core::ops::{
|
use core::ops::{
|
||||||
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
|
||||||
};
|
};
|
||||||
|
|
@ -342,7 +342,7 @@ impl SampledWavelengths {
|
||||||
|
|
||||||
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];
|
||||||
lambda[0] = lerp(u, lambda_min, lambda_min);
|
lambda[0] = lerp(u, lambda_min, lambda_max);
|
||||||
let delta = (lambda_max - lambda_min) / N_SPECTRUM_SAMPLES as Float;
|
let delta = (lambda_max - lambda_min) / N_SPECTRUM_SAMPLES as Float;
|
||||||
for i in 1..N_SPECTRUM_SAMPLES {
|
for i in 1..N_SPECTRUM_SAMPLES {
|
||||||
lambda[i] = lambda[i - 1] + delta;
|
lambda[i] = lambda[i - 1] + delta;
|
||||||
|
|
@ -357,14 +357,14 @@ impl SampledWavelengths {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_visible_wavelengths(u: Float) -> Float {
|
pub fn sample_visible_wavelengths(u: Float) -> Float {
|
||||||
538.0 - 138.888889 * Float::atanh(0.85691062 - 1.82750197 * u)
|
(538.0_f64 - 138.888889_f64 * (0.85691062_f64 - 1.82750197_f64 * u as f64).atanh()) as Float
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visible_wavelengths_pdf(lambda: Float) -> Float {
|
pub fn visible_wavelengths_pdf(lambda: Float) -> Float {
|
||||||
if !(360.0..830.0).contains(&lambda) {
|
if !(360.0..830.0).contains(&lambda) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
0.0039398042 / (Float::cosh(0.0072 * (lambda - 538.0))).sqrt()
|
(0.0039398042_f64 / (0.0072_f64 * (lambda as f64 - 538.0)).cosh().powi(2)) as Float
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_visible(u: Float) -> Self {
|
pub fn sample_visible(u: Float) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use alloc::vec::Vec;
|
||||||
use core::alloc::{AllocError, Allocator, Layout};
|
use core::alloc::{AllocError, Allocator, Layout};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
// CPU fallback, delegates to Global
|
// CPU fallback to GlobalAllocator
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct SystemAlloc;
|
pub struct SystemAlloc;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ pub use options::PBRTOptions;
|
||||||
pub use ptr::Ptr;
|
pub use ptr::Ptr;
|
||||||
pub use transform::{AnimatedTransform, Transform, TransformGeneric};
|
pub use transform::{AnimatedTransform, Transform, TransformGeneric};
|
||||||
pub use containers::Array2D;
|
pub use containers::Array2D;
|
||||||
|
pub use soa::SOA:
|
||||||
|
|
||||||
use crate::Float;
|
use crate::Float;
|
||||||
use core::sync::atomic::{AtomicU32, Ordering};
|
use core::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ impl<T: ?Sized> PartialEq for Ptr<T> {
|
||||||
|
|
||||||
impl<T: ?Sized> PartialOrd for Ptr<T> {
|
impl<T: ?Sized> PartialOrd for Ptr<T> {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
Some(self.ptr.cmp(&other.ptr))
|
Some(self.ptr.cast::<()>().cmp(&other.ptr.cast::<()>()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
15
shared/src/utils/soa.rs
Normal file
15
shared/src/utils/soa.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
pub trait SoA: Clone {
|
||||||
|
type Item: Copy;
|
||||||
|
fn with_capacity(n: usize) -> Self;
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_unchecked(&self, i: usize) -> Self::Item;
|
||||||
|
unsafe fn set_unchecked(&mut self, i: usize, v: Self::Item);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SoAElement: Copy {
|
||||||
|
type SoA: SoA<Item = Self>;
|
||||||
|
}
|
||||||
|
|
@ -17,9 +17,6 @@ pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> {
|
||||||
let media = scene.create_media();
|
let media = scene.create_media();
|
||||||
let textures = scene.create_textures(arena);
|
let textures = scene.create_textures(arena);
|
||||||
let (named_materials, materials) = scene.create_materials(&textures, arena)?;
|
let (named_materials, materials) = scene.create_materials(&textures, arena)?;
|
||||||
for (i, m) in materials.iter().enumerate() {
|
|
||||||
eprintln!("materials[{}]: {:?}", i, std::mem::discriminant(m));
|
|
||||||
}
|
|
||||||
let lights = scene.create_lights(&textures, arena);
|
let lights = scene.create_lights(&textures, arena);
|
||||||
|
|
||||||
let have_scattering = {
|
let have_scattering = {
|
||||||
|
|
|
||||||
|
|
@ -701,7 +701,7 @@ impl BasicScene {
|
||||||
sampler,
|
sampler,
|
||||||
aggregate,
|
aggregate,
|
||||||
lights,
|
lights,
|
||||||
PathConfig::SIMPLE,
|
PathConfig::FULL,
|
||||||
arena,
|
arena,
|
||||||
)
|
)
|
||||||
.expect("Integrator creation failed"),
|
.expect("Integrator creation failed"),
|
||||||
|
|
@ -779,6 +779,8 @@ impl BasicScene {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eprintln!("shape '{}' n={}", entity.base.name, created_shapes.len());
|
||||||
|
|
||||||
let mtl = resolve_material(
|
let mtl = resolve_material(
|
||||||
&entity.material,
|
&entity.material,
|
||||||
named_materials,
|
named_materials,
|
||||||
|
|
@ -967,10 +969,6 @@ impl BasicScene {
|
||||||
primitives
|
primitives
|
||||||
}
|
}
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// Private — texture helper
|
|
||||||
// =======================================================================
|
|
||||||
|
|
||||||
fn add_texture_generic<T, F>(
|
fn add_texture_generic<T, F>(
|
||||||
&self,
|
&self,
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -1105,9 +1103,6 @@ impl BasicScene {
|
||||||
Err(anyhow!("{} requested but not initialized!", name))
|
Err(anyhow!("{} requested but not initialized!", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// =======================================================================
|
|
||||||
// GPU path stubs — to be implemented with wavefront integrator
|
|
||||||
// =======================================================================
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn upload_shapes(
|
fn upload_shapes(
|
||||||
|
|
|
||||||
|
|
@ -120,31 +120,6 @@ pub enum SpectrumTexture {
|
||||||
DirectionMix(SpectrumDirectionMixTexture),
|
DirectionMix(SpectrumDirectionMixTexture),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumTexture {
|
|
||||||
fn upload_spectrum_image(
|
|
||||||
inner: &SpectrumImageTexture,
|
|
||||||
arena: &Arena,
|
|
||||||
) -> GPUSpectrumImageTexture {
|
|
||||||
let tex_obj = arena.get_texture_object(&inner.base.mipmap);
|
|
||||||
GPUSpectrumImageTexture {
|
|
||||||
mapping: inner.base.mapping,
|
|
||||||
tex_obj,
|
|
||||||
scale: inner.base.scale,
|
|
||||||
invert: inner.base.invert,
|
|
||||||
is_single_channel: inner.base.mipmap.is_single_channel(),
|
|
||||||
color_space: arena.alloc(
|
|
||||||
inner
|
|
||||||
.base
|
|
||||||
.mipmap
|
|
||||||
.color_space
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(crate::spectra::default_colorspace),
|
|
||||||
),
|
|
||||||
spectrum_type: inner.spectrum_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CreateSpectrumTexture {
|
pub trait CreateSpectrumTexture {
|
||||||
fn create(
|
fn create(
|
||||||
render_from_texture: Transform,
|
render_from_texture: Transform,
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
pub mod context;
|
|
||||||
|
|
||||||
pub use context::{
|
|
||||||
GPU_STATE, GpuContext, GpuState, gpu_init, gpu_state, gpu_state_or_panic, gpu_thread_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod wavefront;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum GpuError {
|
|
||||||
#[error("CUDA driver error: {0}")]
|
|
||||||
Driver(#[from] cudarc::driver::DriverError),
|
|
||||||
#[error("No GPU context initialized")]
|
|
||||||
NoContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gpu_unwrap() -> &'static GpuContext {
|
|
||||||
context::GPU_STATE.get().expect("GPU not initialized")
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
// use crate::core::scene::BasicScene;
|
|
||||||
// use crate::{
|
|
||||||
// EscapedRayQueue, GetBSSRDFAndProbeRayQueue, HitAreaLightQueue, MaterialEvalQueue,
|
|
||||||
// MediumSampleQueue, MediumScatterQueue, PixelSampleStateStorage, RayQueue, ShadowRayQueue,
|
|
||||||
// SubsurfaceScatterQueue,
|
|
||||||
// };
|
|
||||||
// use shared::core::camera::Camera;
|
|
||||||
// use shared::core::film::Film;
|
|
||||||
// use shared::core::filter::Filter;
|
|
||||||
// use shared::core::light::Light;
|
|
||||||
// use shared::core::sampler::Sampler;
|
|
||||||
// use shared::lights::sampler::LightSampler;
|
|
||||||
// use std::sync::Arc;
|
|
||||||
//
|
|
||||||
// pub struct WavefrontPathIntegrator {
|
|
||||||
// pub film: Film,
|
|
||||||
// pub filter: Filter,
|
|
||||||
// pub sampler: Sampler,
|
|
||||||
// pub camera: Arc<Camera>,
|
|
||||||
// pub light_sampler: LightSampler,
|
|
||||||
// pub infinite_lights: Option<Vec<Arc<Light>>>,
|
|
||||||
// pub max_depth: i32,
|
|
||||||
// pub samples_per_pixel: i32,
|
|
||||||
// pub regularize: bool,
|
|
||||||
// pub scanlines_per_pixel: i32,
|
|
||||||
// pub max_queue_size: i32,
|
|
||||||
// pub pixel_sample_state: PixelSampleStateStorage,
|
|
||||||
// pub ray_queue: [RayQueue; 2],
|
|
||||||
// pub hit_area_light_queue: HitAreaLightQueue,
|
|
||||||
// pub shadow_ray_queue: ShadowRayQueue,
|
|
||||||
// pub escaped_ray_queue: Option<EscapedRayQueue>,
|
|
||||||
// pub basic_material_queue: Option<MaterialEvalQueue>,
|
|
||||||
// pub universal_material_queue: Option<MaterialEvalQueue>,
|
|
||||||
// pub medium_sample_queue: Option<MediumSampleQueue>,
|
|
||||||
// pub medium_scatter_queue: Option<MediumScatterQueue>,
|
|
||||||
// pub bssrf_queue: Option<GetBSSRDFAndProbeRayQueue>,
|
|
||||||
// pub subsurface_queue: Option<SubsurfaceScatterQueue>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[cfg(feature = "use_gpu")]
|
|
||||||
impl WavefrontPathIntegrator {
|
|
||||||
pub fn new(scene: BasicScene) -> Self {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -82,7 +82,6 @@ pub fn render<T>(
|
||||||
) where
|
) where
|
||||||
T: RayIntegratorTrait + Sync,
|
T: RayIntegratorTrait + Sync,
|
||||||
{
|
{
|
||||||
println!("RENDER CALLED");
|
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
if let Some((p_pixel, sample_index)) = options.debug_start {
|
if let Some((p_pixel, sample_index)) = options.debug_start {
|
||||||
let s_index = sample_index as usize;
|
let s_index = sample_index as usize;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ pub mod shapes;
|
||||||
pub mod spectra;
|
pub mod spectra;
|
||||||
pub mod textures;
|
pub mod textures;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod wavefront;
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
|
||||||
pub mod gpu;
|
|
||||||
pub use utils::{Arena, FileLoc, ParameterDictionary, Upload, ArenaUpload};
|
pub use utils::{Arena, FileLoc, ParameterDictionary, Upload, ArenaUpload};
|
||||||
|
pub const MAX_TAGS = 16;
|
||||||
|
|
|
||||||
|
|
@ -695,6 +695,7 @@ impl ParameterDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_file_spectrum(&self, param: &ParsedParameter) -> Vec<Spectrum> {
|
fn extract_file_spectrum(&self, param: &ParsedParameter) -> Vec<Spectrum> {
|
||||||
|
eprintln!("extract_file_spectrum: param='{}' files={:?}", param.name, param.strings);
|
||||||
param
|
param
|
||||||
.strings
|
.strings
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -894,6 +895,7 @@ impl TextureParameterDictionary {
|
||||||
|
|
||||||
p.looked_up.store(true, Ordering::Relaxed);
|
p.looked_up.store(true, Ordering::Relaxed);
|
||||||
let tex_name = &p.strings[0];
|
let tex_name = &p.strings[0];
|
||||||
|
eprintln!("looking up texture '{}'", tex_name);
|
||||||
|
|
||||||
if let Some(nt) = &self.textures {
|
if let Some(nt) = &self.textures {
|
||||||
let map = match stype {
|
let map = match stype {
|
||||||
|
|
|
||||||
11
src/wavefront/aggregate.rs
Normal file
11
src/wavefront/aggregate.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use shared::core::geometry::Bounds3f;
|
||||||
|
use super::{RayQueue, EscapedRayQueue, HitAreaLightQueue, MaterialEvalQueue, MediumSampleQueue, SubsurfaceScatterQueue};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub trait WavefrontAggregate {
|
||||||
|
fn bounds(&self) -> Bounds3f;
|
||||||
|
fn intersect_closest(max_rays: usize, ray_q: &mut RayQueue, hit_area_light_q: &mut HitAreaLightQueue, basic_mlt_q: &mut MaterialEvalQueue, universal_mtl_q: &mut MaterialEvalQueue, medium_sample_q: &mut MediumSampleQueue);
|
||||||
|
fn intersect_shadow(max_rays: usize, shadow_ray_q: &mut ShadowRayQueue, pixel_sample_state: &mut SOA<PixelSampleState>);
|
||||||
|
fn intersect_shadow_tr(max_rays: usize, shadow_ray_q: &mut ShadowRayQueue, pixel_sample_state: &mut SOA<PixelSampleState>);
|
||||||
|
fn intersect_one_random(max_rays: usize, subsurface_scatte_q: &mut SubsurfaceScatterQueue);
|
||||||
|
}
|
||||||
38
src/wavefront/integrator.rs
Normal file
38
src/wavefront/integrator.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::MAX_TAGS;
|
||||||
|
use shared::{Ptr, GVec};
|
||||||
|
use shared::core::film::Film;
|
||||||
|
use shared::core::color::RGB;
|
||||||
|
use shared::core::filter::Filter;
|
||||||
|
use shared::core::light::Light;
|
||||||
|
use shared::core::sampler::Filter;
|
||||||
|
use shared::wavefront::{WavefrontAggregate, RayQueue, MediumSampleQueue, EscapedRayQueue, HitAreaLightQueue, MaterialEvalQueue, ShadowRayQueue, GetBSSRDFAndProbeRayQueue, SubsurfaceScatterQueue};
|
||||||
|
|
||||||
|
pub struct WavefrontPathIntegrator {
|
||||||
|
pub init_visible_surface: bool,
|
||||||
|
pub have_subsurface: bool,
|
||||||
|
pub have_media: bool,
|
||||||
|
pub have_basic_eval_material: [bool; MAX_TAGS + 1],
|
||||||
|
pub have_universal_eval_material: [bool; MAX_TAGS + 1],
|
||||||
|
pub filter: Filter,
|
||||||
|
pub film: Film,
|
||||||
|
pub sampler: Sampler,
|
||||||
|
pub camera: Camera,
|
||||||
|
pub infinite_lights: GVec<Light>,
|
||||||
|
pub max_depth: usize,
|
||||||
|
pub sampler_per_pixel: usize,
|
||||||
|
pub regularize: bool,
|
||||||
|
pub scanlines_per_pixel: usize,
|
||||||
|
pub max_queue_size: usize,
|
||||||
|
pub medium_sample_queue: Ptr<MediumSampleQueue>,
|
||||||
|
pub medium_scatter_queue: Ptr<MediumScatterQueue>,
|
||||||
|
pub escaped_ray_queue: Ptr<EscapedRayQueue>,
|
||||||
|
pub hit_area_light_queue: Ptr<HitAreaLightQueue>,
|
||||||
|
pub basic_eval_material_queue: Ptr<MaterialEvalQueue>,
|
||||||
|
pub universal_eval_material_queue: Ptr<MaterialEvalQueue>,
|
||||||
|
pub shadow_ray_queue: Ptr<ShadowRayQueue>,
|
||||||
|
pub bssrdf_eval_queue: PTr<GetBSSRDFAndProbeRayQueue>,
|
||||||
|
pub subsurface_scatter_queue: Ptr<SubsurfaceScatterQueue>,
|
||||||
|
pub display_rgb: Ptr<RGB>,
|
||||||
|
pub display_rgb_host: Ptr<RGB,
|
||||||
|
|
||||||
|
}
|
||||||
4
src/wavefront/mod.rs
Normal file
4
src/wavefront/mod.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod integrator;
|
||||||
|
pub mod aggregate;
|
||||||
|
|
||||||
|
pub use aggregate::WavefrontAggregate;
|
||||||
Loading…
Reference in a new issue