Compare commits

...

5 commits

42 changed files with 905 additions and 552 deletions

View file

@ -76,3 +76,17 @@ wrong_self_convention = "allow"
[profile.release] [profile.release]
debug = true debug = true
# Renders run through `cargo test`, whose profile inherits from `dev`. Cargo's
# default there is opt-level = 0, which costs ~15x on ray throughput.
[profile.dev]
opt-level = 1
# Applies to dependencies only -- Cargo excludes workspace members from "*".
[profile.dev.package."*"]
opt-level = 3
# `shared` is a workspace member, so it needs naming explicitly. It holds the
# geometry/BSDF/sampling math, so it wants full optimisation.
[profile.dev.package.shared]
opt-level = 3

View file

@ -4,9 +4,8 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.100"
bitflags = "2.10.0" bitflags = "2.10.0"
half = "2.7.1" half = { version = "2.7.1", default-features = false }
bytemuck = { version = "1.24.0", features = ["derive"] } bytemuck = { version = "1.24.0", features = ["derive"] }
enum_dispatch = "0.3.13" enum_dispatch = "0.3.13"
ash = { version = "0.38", optional = true } ash = { version = "0.38", optional = true }

View file

@ -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::{
abs_cos_theta, cos_theta, same_hemisphere, Normal3f, Point2f, Vector3f, VectorLike, Normal3f, Point2f, Vector3f, VectorLike, abs_cos_theta, cos_theta, same_hemisphere,
}; };
use crate::core::scattering::{ use crate::core::scattering::{
fr_complex_from_spectrum, fr_dielectric, reflect, refract, TrowbridgeReitzDistribution, TrowbridgeReitzDistribution, fr_complex_from_spectrum, fr_dielectric, reflect, refract,
}; };
use crate::spectra::SampledSpectrum; use crate::spectra::SampledSpectrum;
use crate::utils::math::square; use crate::utils::math::square;
@ -362,7 +362,6 @@ impl BxDFTrait for ThinDielectricBxDF {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
fn regularize(&mut self) {
todo!() fn regularize(&mut self) {}
}
} }

View file

@ -73,4 +73,118 @@ impl BxDFTrait for DiffuseBxDF {
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct DiffuseTransmissionBxDF; pub struct DiffuseTransmissionBxDF {
pub r: SampledSpectrum,
pub t: SampledSpectrum,
}
impl DiffuseTransmissionBxDF {
pub fn new(r: SampledSpectrum, t: SampledSpectrum) -> Self {
Self { r, t }
}
}
impl BxDFTrait for DiffuseTransmissionBxDF {
fn flags(&self) -> BxDFFlags {
let r_flags = if !self.r.is_black() {
BxDFFlags::DIFFUSE_REFLECTION
} else {
BxDFFlags::UNSET
};
let t_flags = if !self.t.is_black() {
BxDFFlags::DIFFUSE_TRANSMISSION
} else {
BxDFFlags::UNSET
};
r_flags | t_flags
}
fn f(&self, wo: Vector3f, wi: Vector3f, _mode: TransportMode) -> SampledSpectrum {
if !same_hemisphere(wo, wi) {
return self.r * INV_PI;
}
self.t * INV_PI
}
fn sample_f(&self, wo: Vector3f, uc: Float, u: Point2f, f_args: FArgs) -> Option<BSDFSample> {
let reflection_flags =
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::REFLECTION.bits());
let transmission_flags =
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::TRANSMISSION.bits());
let pr = if !f_args.sample_flags.contains(reflection_flags) {
0.
} else {
self.r.max_component_value()
};
let pt = if !f_args.sample_flags.contains(transmission_flags) {
0.
} else {
self.t.max_component_value()
};
if (pr == 0.) && (pt == 0.) {
return None;
}
let mut wi = sample_cosine_hemisphere(u);
if wo.z() < 0. {
wi[2] *= -1.;
}
let pdf = cosine_hemisphere_pdf(abs_cos_theta(wi)) * pr / (pr + pt);
let flags = if uc < pr / (pr + pt) {
BxDFFlags::DIFFUSE_REFLECTION
} else {
BxDFFlags::DIFFUSE_TRANSMISSION
};
let bsdf = BSDFSample {
f: self.r * INV_PI,
wi,
pdf,
flags,
..Default::default()
};
Some(bsdf)
}
fn pdf(&self, wo: Vector3f, wi: Vector3f, f_args: FArgs) -> Float {
let reflection_flags =
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::REFLECTION.bits());
let transmission_flags =
BxDFReflTransFlags::from_bits_truncate(BxDFReflTransFlags::TRANSMISSION.bits());
let pr = if !f_args.sample_flags.contains(reflection_flags) {
0.
} else {
self.r.max_component_value()
};
let pt = if !f_args.sample_flags.contains(transmission_flags) {
0.
} else {
self.t.max_component_value()
};
if (pr == 0.) && (pt == 0.) {
return 0.;
}
let cos_factor = cosine_hemisphere_pdf(abs_cos_theta(wi));
if same_hemisphere(wo, wi) {
return pr / (pr + pt) * cos_factor;
} else {
return pt / (pr + pt) * cos_factor;
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn regularize(&mut self) {}
}

View file

@ -146,6 +146,7 @@ pub trait BxDFTrait: Any {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum BxDF { pub enum BxDF {
Diffuse(DiffuseBxDF), Diffuse(DiffuseBxDF),
DiffuseTransmission(DiffuseTransmissionBxDF),
Dielectric(DielectricBxDF), Dielectric(DielectricBxDF),
ThinDielectric(ThinDielectricBxDF), ThinDielectric(ThinDielectricBxDF),
Conductor(ConductorBxDF), Conductor(ConductorBxDF),

View file

@ -8,7 +8,7 @@ use core::fmt;
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,
}; };
use anyhow::{Result, bail}; use crate::utils::error::{Error, Result};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
@ -686,7 +686,7 @@ impl ColorEncoding {
match name { match name {
"sRGB" | "srgb" => Ok(ColorEncoding::SRGB(SRGBEncoding)), "sRGB" | "srgb" => Ok(ColorEncoding::SRGB(SRGBEncoding)),
"linear" => Ok(ColorEncoding::Linear(LinearEncoding)), "linear" => Ok(ColorEncoding::Linear(LinearEncoding)),
_ => bail!("Unknown color encoding: {}", name), _ => Err(Error::UnknownColorEncoding),
} }
} }
} }

View file

@ -2,7 +2,7 @@ use crate::core::color::{ColorEncoding, ColorEncodingTrait, LINEAR};
use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i}; use crate::core::geometry::{Bounds2f, Point2f, Point2fi, Point2i};
use crate::utils::math::{f16_to_f32_software, lerp, square}; use crate::utils::math::{f16_to_f32_software, lerp, square};
use crate::{gvec_with_capacity, Float, GVec, Ptr}; use crate::{gvec_with_capacity, Float, GVec, Ptr};
use anyhow::{bail, Result}; use crate::utils::error::{Error, Result};
use core::hash; use core::hash;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
@ -23,7 +23,7 @@ impl WrapMode {
"black" => Ok(WrapMode::Black), "black" => Ok(WrapMode::Black),
"repeat" => Ok(WrapMode::Repeat), "repeat" => Ok(WrapMode::Repeat),
"octahedralsphere" => Ok(WrapMode::OctahedralSphere), "octahedralsphere" => Ok(WrapMode::OctahedralSphere),
_ => bail!("{:?}: wrap mode unknown", name), _ => Err(Error::UnknownWrapMode),
} }
} }
} }
@ -503,7 +503,7 @@ impl FilterFunction {
"trilinear" => Ok(FilterFunction::Trilinear), "trilinear" => Ok(FilterFunction::Trilinear),
"bilinear" => Ok(FilterFunction::Bilinear), "bilinear" => Ok(FilterFunction::Bilinear),
"point" => Ok(FilterFunction::Point), "point" => Ok(FilterFunction::Point),
_ => bail!("Filter function unknown"), _ => Err(Error::UnknownFilterFunction),
} }
} }
} }

View file

@ -2,6 +2,7 @@ use crate::materials::*;
use core::ops::Deref; use core::ops::Deref;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use crate::Float;
use crate::bxdfs::{ use crate::bxdfs::{
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
}; };
@ -13,15 +14,12 @@ use crate::core::image::{Image, WrapMode, WrapMode2D};
use crate::core::interaction::{Interaction, InteractionTrait, ShadingGeom, SurfaceInteraction}; use crate::core::interaction::{Interaction, InteractionTrait, ShadingGeom, SurfaceInteraction};
use crate::core::scattering::TrowbridgeReitzDistribution; use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{ use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext, TextureEvaluator};
FloatTexture, SpectrumTexture, TextureEvalContext, TextureEvaluator,
};
use crate::materials::*; use crate::materials::*;
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr;
use crate::utils::hash::hash_float; use crate::utils::hash::hash_float;
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::utils::Ptr;
use crate::Float;
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, Copy)] #[derive(Clone, Debug, Copy)]
@ -162,7 +160,7 @@ pub trait MaterialTrait {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF; ) -> BSDF;
fn get_bssrdf<T: TextureEvaluator>( fn get_bssrdf<T: TextureEvaluator>(

View file

@ -2,15 +2,15 @@ use crate::core::filter::FilterTrait;
use crate::core::geometry::{Bounds2f, Point2f, Point2i, Vector2f}; use crate::core::geometry::{Bounds2f, Point2f, Point2i, Vector2f};
use crate::core::pbrt::{Float, ONE_MINUS_EPSILON, PI, PI_OVER_2, PI_OVER_4}; use crate::core::pbrt::{Float, ONE_MINUS_EPSILON, PI, PI_OVER_2, PI_OVER_4};
use crate::utils::math::{ use crate::utils::math::{
clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int, BinaryPermuteScrambler, DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler,
PRIME_TABLE_SIZE, Scrambler, clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int,
owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2, owen_scrambled_radical_inverse, permutation_element, radical_inverse, round_up_pow2,
scrambled_radical_inverse, sobol_interval_to_index, sobol_sample, BinaryPermuteScrambler, scrambled_radical_inverse, sobol_interval_to_index, sobol_sample,
DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, Scrambler, PRIME_TABLE_SIZE,
}; };
use crate::utils::rng::Rng; use crate::utils::rng::Rng;
use crate::utils::sobol::N_SOBOL_DIMENSIONS; use crate::utils::sobol::N_SOBOL_DIMENSIONS;
use crate::utils::{hash::*, sobol}; use crate::utils::{hash::*, sobol};
use crate::{gvec, GVec, Ptr}; use crate::{GVec, Ptr, gvec};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
#[repr(C)] #[repr(C)]
@ -530,6 +530,18 @@ pub struct ZSobolSampler {
dim: u32, dim: u32,
} }
/// pbrt writes `0x55555555u * dimension` -- a 32-bit unsigned product that wraps.
#[inline]
fn scramble_seed(dim: u32) -> u64 {
0x5555_5555u32.wrapping_mul(dim) as u64
}
/// pbrt's `Hash(dimension, seed)`: both are `int`, so exactly 8 packed bytes.
#[inline]
fn dim_seed_hash(dim: u32, seed: u64) -> u64 {
hash_buffer(&[dim, seed as u32], 0)
}
impl ZSobolSampler { impl ZSobolSampler {
pub fn new( pub fn new(
samples_per_pixel: i32, samples_per_pixel: i32,
@ -537,10 +549,12 @@ impl ZSobolSampler {
randomize: RandomizeStrategy, randomize: RandomizeStrategy,
seed: Option<u64>, seed: Option<u64>,
) -> Self { ) -> Self {
let log2_samples_per_pixel = log2_int(samples_per_pixel as Float) as u32; // pbrt calls the integer Log2Int overload; the float one disagrees for
// non-power-of-two sample counts.
let log2_samples_per_pixel = (samples_per_pixel.max(1) as u32).ilog2();
let res = round_up_pow2(full_resolution.x().max(full_resolution.y())); let res = round_up_pow2(full_resolution.x().max(full_resolution.y()));
let log4_samples_per_pixel = log2_samples_per_pixel.div_ceil(2); let log4_samples_per_pixel = log2_samples_per_pixel.div_ceil(2);
let n_base4_digits = log2_int(res as Float) as u32 + log4_samples_per_pixel as u32; let n_base4_digits = (res.max(1) as u32).ilog2() + log4_samples_per_pixel;
Self { Self {
randomize, randomize,
seed: seed.unwrap_or(0), seed: seed.unwrap_or(0),
@ -590,7 +604,7 @@ impl ZSobolSampler {
let higher_digits = self.morton_index >> (digit_shift + 2); let higher_digits = self.morton_index >> (digit_shift + 2);
let mix_input = higher_digits ^ (0x55555555 * self.dim as u64); let mix_input = higher_digits ^ scramble_seed(self.dim);
let p = (mix_bits(mix_input) >> 24) % 24; let p = (mix_bits(mix_input) >> 24) % 24;
digit = PERMUTATIONS[p as usize][digit as usize] as u64; digit = PERMUTATIONS[p as usize][digit as usize] as u64;
@ -599,8 +613,9 @@ impl ZSobolSampler {
} }
if pow2_samples { if pow2_samples {
let lsb = self.morton_index & 1; let digit = self.morton_index & 1;
sample_index |= lsb; sample_index |=
digit ^ (mix_bits((self.morton_index >> 1) ^ scramble_seed(self.dim)) & 1);
} }
sample_index sample_index
@ -609,8 +624,9 @@ impl ZSobolSampler {
impl SamplerTrait for ZSobolSampler { impl SamplerTrait for ZSobolSampler {
fn samples_per_pixel(&self) -> i32 { fn samples_per_pixel(&self) -> i32 {
todo!() 1 << self.log2_samples_per_pixel
} }
fn start_pixel_sample(&mut self, p: Point2i, sample_index: i32, dim: Option<u32>) { fn start_pixel_sample(&mut self, p: Point2i, sample_index: i32, dim: Option<u32>) {
self.dim = dim.unwrap_or(0); self.dim = dim.unwrap_or(0);
self.morton_index = (encode_morton_2(p.x() as u32, p.y() as u32) self.morton_index = (encode_morton_2(p.x() as u32, p.y() as u32)
@ -620,31 +636,25 @@ impl SamplerTrait for ZSobolSampler {
fn get1d(&mut self) -> Float { fn get1d(&mut self) -> Float {
let sample_index = self.get_sample_index(); let sample_index = self.get_sample_index();
let hash_input = [self.dim as u64, self.seed];
let hash = hash_buffer(&hash_input, 0) as u32;
self.dim += 1; self.dim += 1;
if self.randomize == RandomizeStrategy::None { let hash = dim_seed_hash(self.dim, self.seed) as u32;
return sobol_sample(sample_index, self.dim, NoRandomizer); // Always Sobol dimension 0 -- decorrelation comes from the hash.
}
match self.randomize { match self.randomize {
RandomizeStrategy::None => sobol_sample(sample_index, 0, NoRandomizer),
RandomizeStrategy::PermuteDigits => { RandomizeStrategy::PermuteDigits => {
sobol_sample(sample_index, self.dim, BinaryPermuteScrambler::new(hash)) sobol_sample(sample_index, 0, BinaryPermuteScrambler::new(hash))
} }
RandomizeStrategy::FastOwen => { RandomizeStrategy::FastOwen => {
sobol_sample(sample_index, self.dim, FastOwenScrambler::new(hash)) sobol_sample(sample_index, 0, FastOwenScrambler::new(hash))
} }
RandomizeStrategy::Owen => { RandomizeStrategy::Owen => sobol_sample(sample_index, 0, OwenScrambler::new(hash)),
sobol_sample(sample_index, self.dim, OwenScrambler::new(hash))
}
RandomizeStrategy::None => unreachable!(),
} }
} }
fn get2d(&mut self) -> Point2f { fn get2d(&mut self) -> Point2f {
let sample_index = self.get_sample_index(); let sample_index = self.get_sample_index();
self.dim += 2; self.dim += 2;
let hash_input = [self.dim as u64, self.seed]; let hash = dim_seed_hash(self.dim, self.seed);
let hash = hash_buffer(&hash_input, 0);
let sample_hash = [hash as u32, (hash >> 32) as u32]; let sample_hash = [hash as u32, (hash >> 32) as u32];
if self.randomize == RandomizeStrategy::None { if self.randomize == RandomizeStrategy::None {
return Point2f::new( return Point2f::new(
@ -675,16 +685,92 @@ impl SamplerTrait for ZSobolSampler {
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct MLTSampler; struct PrimarySample {
value: Float,
last_mod_iteration: i64,
value_backup: Float,
mod_backup: i64,
}
impl PrimarySample {
fn backup(&mut self) {
self.value_backup = self.value;
self.mod_backup = self.last_mod_iteration;
}
fn restore(&mut self) {
self.value = self.value_backup;
self.last_mod_iteration = self.mod_backup;
}
}
#[derive(Debug, Clone)]
pub struct MLTSampler {
mutations_per_pixel: i32,
rng: Rng,
sigma: Float,
large_step_prob: Float,
stream_count: i32,
x: GVec<PrimarySample>,
current_iter: i64,
large_step: bool,
last_large_step_iter: i64,
stream_ind: i32,
sample_ind: i32,
seed: u64,
}
impl MLTSampler {
pub fn new(
mutations_per_pixel: i32,
rng_seq_ind: i32,
sigma: Float,
large_step_prob: Float,
stream_count: i32,
seed: u64,
) -> Self {
Self {
mutations_per_pixel,
rng: Rng::new(mix_bits(rng_seq_ind.try_into().unwrap()) ^ mix_bits(seed)),
seed,
sigma,
large_step_prob,
stream_count,
x: gvec(),
current_iter: 0,
large_step: true,
last_large_step_iter: 0,
stream_ind: 0,
sample_ind: 0,
}
}
pub fn get_next_index(&mut self) -> i32 {
self.sample_ind += 1;
self.stream_ind + self.stream_count * self.sample_ind
}
}
impl SamplerTrait for MLTSampler { impl SamplerTrait for MLTSampler {
fn samples_per_pixel(&self) -> i32 { fn samples_per_pixel(&self) -> i32 {
todo!() self.mutations_per_pixel
} }
fn start_pixel_sample(&mut self, _p: Point2i, _sample_index: i32, _dim: Option<u32>) {
todo!() fn start_pixel_sample(&mut self, p: Point2i, sample_index: i32, dim: Option<u32>) {
let hash_input = [p.x() as u64, p.y() as u64, self.seed];
let sequence_index = hash_buffer(&hash_input, 0);
self.rng.set_sequence(sequence_index);
self.rng
.advance((sample_index as u64) * 65536 + (dim.unwrap_or(0) as u64));
} }
fn get1d(&mut self) -> Float { fn get1d(&mut self) -> Float {
todo!() #[cfg(not(any(feature = "cuda", feature = "vulkan")))]
{
return 0.;
}
let ind = self.get_next_index();
} }
fn get2d(&mut self) -> Point2f { fn get2d(&mut self) -> Point2f {
todo!() todo!()

View file

@ -71,7 +71,7 @@ impl MaterialTrait for CoatedDiffuseMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
let r = SampledSpectrum::clamp( let r = SampledSpectrum::clamp(
&tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda), &tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda),
@ -220,7 +220,7 @@ impl MaterialTrait for CoatedConductorMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
let mut iurough = tex_eval.evaluate_float(&self.interface_uroughness, ctx); let mut iurough = tex_eval.evaluate_float(&self.interface_uroughness, ctx);
let mut ivrough = tex_eval.evaluate_float(&self.interface_vroughness, ctx); let mut ivrough = tex_eval.evaluate_float(&self.interface_vroughness, ctx);
@ -234,7 +234,6 @@ impl MaterialTrait for CoatedConductorMaterial {
let mut ieta = self.interface_eta.evaluate(lambda[0]); let mut ieta = self.interface_eta.evaluate(lambda[0]);
if self.interface_eta.is_constant() { if self.interface_eta.is_constant() {
let mut lambda = *lambda;
lambda.terminate_secondary_inplace(); lambda.terminate_secondary_inplace();
} }

View file

@ -60,7 +60,7 @@ impl MaterialTrait for HairMaterial {
&self, &self,
_tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
todo!() todo!()
} }
@ -103,7 +103,7 @@ impl MaterialTrait for MeasuredMaterial {
&self, &self,
_tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
// MeasuredBxDF::new(&self.brdf, lambda) // MeasuredBxDF::new(&self.brdf, lambda)
todo!() todo!()
@ -157,7 +157,7 @@ impl MaterialTrait for SubsurfaceMaterial {
&self, &self,
_tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
todo!() todo!()
} }

View file

@ -10,8 +10,8 @@ use crate::core::scattering::TrowbridgeReitzDistribution;
use crate::core::spectrum::{Spectrum, SpectrumTrait}; use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator}; use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::clamp;
use crate::utils::Ptr; use crate::utils::Ptr;
use crate::utils::math::clamp;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -55,7 +55,7 @@ impl MaterialTrait for ConductorMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
let mut u_rough = tex_eval.evaluate_float(&self.u_roughness, ctx); let mut u_rough = tex_eval.evaluate_float(&self.u_roughness, ctx);
let mut v_rough = tex_eval.evaluate_float(&self.v_roughness, ctx); let mut v_rough = tex_eval.evaluate_float(&self.v_roughness, ctx);
@ -88,7 +88,7 @@ impl MaterialTrait for ConductorMaterial {
fn get_bssrdf<T>( fn get_bssrdf<T>(
&self, &self,
tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {

View file

@ -1,5 +1,7 @@
use crate::Ptr;
use crate::bxdfs::{ use crate::bxdfs::{
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF,
ThinDielectricBxDF,
}; };
use crate::core::bsdf::BSDF; use crate::core::bsdf::BSDF;
use crate::core::bssrdf::BSSRDF; use crate::core::bssrdf::BSSRDF;
@ -11,7 +13,6 @@ use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator}; use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -29,11 +30,11 @@ impl MaterialTrait for DielectricMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
let mut sampled_eta = self.eta.evaluate(lambda[0]); let mut sampled_eta = self.eta.evaluate(lambda[0]);
if !self.eta.is_constant() { if !self.eta.is_constant() {
lambda.terminate_secondary(); lambda.terminate_secondary_inplace();
} }
if sampled_eta == 0.0 { if sampled_eta == 0.0 {
@ -92,18 +93,29 @@ impl MaterialTrait for ThinDielectricMaterial {
fn get_bsdf<T: TextureEvaluator>( fn get_bsdf<T: TextureEvaluator>(
&self, &self,
_tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
todo!() let mut sampled_eta = self.eta.evaluate(lambda[0]);
if !self.eta.is_constant() {
lambda.terminate_secondary_inplace();
} }
if sampled_eta == 0. {
sampled_eta = 1.;
}
let bxdf = BxDF::ThinDielectric(ThinDielectricBxDF::new(sampled_eta));
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
}
fn get_bssrdf<T>( fn get_bssrdf<T>(
&self, &self,
_tex_eval: &T, _tex_eval: &T,
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
todo!() None
} }
fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool { fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {

View file

@ -1,5 +1,8 @@
use crate::Float;
use crate::Ptr;
use crate::bxdfs::{ use crate::bxdfs::{
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
DiffuseTransmissionBxDF, HairBxDF,
}; };
use crate::core::bsdf::BSDF; use crate::core::bsdf::BSDF;
use crate::core::bssrdf::BSSRDF; use crate::core::bssrdf::BSSRDF;
@ -11,8 +14,6 @@ use crate::core::spectrum::{Spectrum, SpectrumTrait};
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator}; use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
use crate::spectra::{SampledSpectrum, SampledWavelengths}; use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::Float;
use crate::Ptr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@ -27,7 +28,7 @@ impl MaterialTrait for DiffuseMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
let spec = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda); let spec = tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda);
let r = SampledSpectrum::clamp(&spec, 0., 1.); let r = SampledSpectrum::clamp(&spec, 0., 1.);
@ -41,7 +42,7 @@ impl MaterialTrait for DiffuseMaterial {
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
todo!() None
} }
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool { fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool {
@ -64,21 +65,33 @@ impl MaterialTrait for DiffuseMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DiffuseTransmissionMaterial { pub struct DiffuseTransmissionMaterial {
pub image: Ptr<Image>, pub normal_map: Ptr<Image>,
pub displacement: Ptr<FloatTexture>, pub displacement: Ptr<FloatTexture>,
pub reflectance: Ptr<FloatTexture>, pub reflectance: Ptr<SpectrumTexture>,
pub transmittance: Ptr<FloatTexture>, pub transmittance: Ptr<SpectrumTexture>,
pub scale: Float, pub scale: Float,
} }
impl MaterialTrait for DiffuseTransmissionMaterial { impl MaterialTrait for DiffuseTransmissionMaterial {
fn get_bsdf<T: TextureEvaluator>( fn get_bsdf<T: TextureEvaluator>(
&self, &self,
_tex_eval: &T, tex_eval: &T,
_ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
todo!() let r = SampledSpectrum::clamp(
&(self.scale * tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda)),
0.,
1.,
);
let t = SampledSpectrum::clamp(
&(self.scale * tex_eval.evaluate_spectrum(&self.transmittance, ctx, lambda)),
0.,
1.,
);
let bxdf = BxDF::DiffuseTransmission(DiffuseTransmissionBxDF::new(r, t));
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
} }
fn get_bssrdf<T>( fn get_bssrdf<T>(
&self, &self,
@ -86,15 +99,15 @@ impl MaterialTrait for DiffuseTransmissionMaterial {
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
todo!() None
} }
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool { fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool {
tex_eval.can_evaluate(&[self.reflectance, self.transmittance], &[]) tex_eval.can_evaluate(&[], &[self.reflectance, self.transmittance])
} }
fn get_normal_map(&self) -> Option<&Image> { fn get_normal_map(&self) -> Option<&Image> {
self.image.get() self.normal_map.get()
} }
fn get_displacement(&self) -> Ptr<FloatTexture> { fn get_displacement(&self) -> Ptr<FloatTexture> {

View file

@ -47,7 +47,7 @@ impl MaterialTrait for MixMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
) -> BSDF { ) -> BSDF {
if let Some(mat) = self.choose_material(tex_eval, ctx) { if let Some(mat) = self.choose_material(tex_eval, ctx) {
mat.get_bsdf(tex_eval, ctx, lambda) mat.get_bsdf(tex_eval, ctx, lambda)

View file

@ -7,14 +7,17 @@ use crate::spectra::{SampledSpectrum, SampledWavelengths};
use crate::utils::{Ptr, math::square}; use crate::utils::{Ptr, math::square};
use num_traits::Float as NumFloat; use num_traits::Float as NumFloat;
fn checkerboard( #[repr(C)]
ctx: &TextureEvalContext, #[derive(Debug, Copy, Clone)]
map2d: Ptr<TextureMapping2D>, pub enum CheckerMap {
map3d: Ptr<TextureMapping3D>, D2(TextureMapping2D),
) -> Float { D3(TextureMapping3D),
}
fn checkerboard(ctx: &TextureEvalContext, checker_map: CheckerMap) -> Float {
let d = |x: Float| -> Float { let d = |x: Float| -> Float {
let y = x / 2. - (x / 2.).floor() - 0.5; let y = x / 2. - (x / 2.).floor() - 0.5;
return x / 2. + y * (1. - 2. * y.abs()); x / 2. + y * (1. - 2. * y.abs())
}; };
let bf = |x: Float, r: Float| -> Float { let bf = |x: Float, r: Float| -> Float {
@ -24,49 +27,53 @@ fn checkerboard(
(d(x + r) - 2. * d(x) + d(x - r)) / square(r) (d(x + r) - 2. * d(x) + d(x - r)) / square(r)
}; };
if !map2d.is_null() { match checker_map {
assert!(map3d.is_null()); CheckerMap::D2(map) => {
let c = map2d.map(&ctx); let c = map.map(ctx);
let ds = 1.5 * c.dsdx.abs().max(c.dsdy.abs()); let ds = 1.5 * c.dsdx.abs().max(c.dsdy.abs());
let dt = 1.5 * c.dtdx.abs().max(c.dtdy.abs()); let dt = 1.5 * c.dtdx.abs().max(c.dtdy.abs());
// Integrate product of 2D checkerboard function and triangle filter // Integrate product of 2D checkerboard function and triangle filter
0.5 - bf(c.st[0], ds) * bf(c.st[1], dt) / 2. 0.5 - bf(c.st[0], ds) * bf(c.st[1], dt) / 2.
} else { }
assert!(!map3d.is_null()); CheckerMap::D3(map) => {
let c = map3d.map(&ctx); let c = map.map(ctx);
let dx = 1.5 * c.dpdx.x().abs().max(c.dpdy.x().abs()); let dx = 1.5 * c.dpdx.x().abs().max(c.dpdy.x().abs());
let dy = 1.5 * c.dpdx.y().abs().max(c.dpdy.y().abs()); let dy = 1.5 * c.dpdx.y().abs().max(c.dpdy.y().abs());
let dz = 1.5 * c.dpdx.z().abs().max(c.dpdy.z().abs()); let dz = 1.5 * c.dpdx.z().abs().max(c.dpdy.z().abs());
0.5 - bf(c.p.x(), dx) * bf(c.p.y(), dy) * bf(c.p.z(), dz) 0.5 - bf(c.p.x(), dx) * bf(c.p.y(), dy) * bf(c.p.z(), dz)
} }
} }
}
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct FloatCheckerboardTexture { pub struct FloatCheckerboardTexture {
pub map2d: Ptr<TextureMapping2D>, pub map: CheckerMap,
pub map3d: Ptr<TextureMapping3D>,
pub tex: [Ptr<FloatTexture>; 2], pub tex: [Ptr<FloatTexture>; 2],
} }
impl FloatCheckerboardTexture { impl FloatCheckerboardTexture {
pub fn new(map: CheckerMap, tex: [Ptr<FloatTexture>; 2]) -> Self {
Self { map, tex }
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float { pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let w = checkerboard(&ctx, self.map2d, self.map3d); let w = checkerboard(ctx, self.map);
let mut t0 = 0.0; let mut t0 = 0.0;
let mut t1 = 0.0; let mut t1 = 0.0;
if w != 1.0 { if w != 1.0
if let Some(tex) = self.tex[0].get() { && let Some(tex) = self.tex[0].get()
{
t0 = tex.evaluate(ctx); t0 = tex.evaluate(ctx);
} }
}
if w != 0.0 { if w != 0.0
if let Some(tex) = self.tex[1].get() { && let Some(tex) = self.tex[1].get()
{
t1 = tex.evaluate(ctx); t1 = tex.evaluate(ctx);
} }
}
(1.0 - w) * t0 + w * t1 (1.0 - w) * t0 + w * t1
} }
@ -75,31 +82,34 @@ impl FloatCheckerboardTexture {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumCheckerboardTexture { pub struct SpectrumCheckerboardTexture {
pub map2d: Ptr<TextureMapping2D>, pub map: CheckerMap,
pub map3d: Ptr<TextureMapping3D>,
pub tex: [Ptr<SpectrumTexture>; 2], pub tex: [Ptr<SpectrumTexture>; 2],
} }
impl SpectrumCheckerboardTexture { impl SpectrumCheckerboardTexture {
pub fn new(map: CheckerMap, tex: [Ptr<SpectrumTexture>; 2]) -> Self {
Self { map, tex }
}
pub fn evaluate( pub fn evaluate(
&self, &self,
ctx: &TextureEvalContext, ctx: &TextureEvalContext,
lambda: &SampledWavelengths, lambda: &SampledWavelengths,
) -> SampledSpectrum { ) -> SampledSpectrum {
let w = checkerboard(ctx, self.map2d, self.map3d); let w = checkerboard(ctx, self.map);
let mut t0 = SampledSpectrum::new(0.); let mut t0 = SampledSpectrum::new(0.);
let mut t1 = SampledSpectrum::new(0.); let mut t1 = SampledSpectrum::new(0.);
if w != 1.0 { if w != 1.0
if let Some(tex) = self.tex[0].get() { && let Some(tex) = self.tex[0].get()
{
t0 = tex.evaluate(ctx, lambda); t0 = tex.evaluate(ctx, lambda);
} }
}
if w != 0.0 { if w != 0.0
if let Some(tex) = self.tex[1].get() { && let Some(tex) = self.tex[1].get()
{
t1 = tex.evaluate(ctx, lambda); t1 = tex.evaluate(ctx, lambda);
} }
}
t0 * (1.0 - w) + t1 * w t0 * (1.0 - w) + t1 * w
} }

View file

@ -1,8 +1,6 @@
use crate::Float; use crate::Float;
use crate::core::geometry::{Point2f, VectorLike}; use crate::core::geometry::{Point2f, VectorLike};
use crate::core::texture::{ use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D};
FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D,
};
use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths}; use crate::spectra::sampled::{SampledSpectrum, SampledWavelengths};
use crate::utils::Ptr; use crate::utils::Ptr;
use crate::utils::math::square; use crate::utils::math::square;
@ -22,18 +20,30 @@ fn inside_polka_dot(st: Point2f) -> bool {
return true; return true;
} }
} }
return false; false
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct FloatDotsTexture { pub struct FloatDotsTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub outside_dot: Ptr<FloatTexture>,
pub inside_dot: Ptr<FloatTexture>, pub inside_dot: Ptr<FloatTexture>,
pub outside_dot: Ptr<FloatTexture>,
} }
impl FloatDotsTexture { impl FloatDotsTexture {
pub fn new(
mapping: TextureMapping2D,
inside_dot: Ptr<FloatTexture>,
outside_dot: Ptr<FloatTexture>,
) -> Self {
Self {
mapping,
inside_dot,
outside_dot,
}
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float { pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let c = self.mapping.map(ctx); let c = self.mapping.map(ctx);
let target_texture = if inside_polka_dot(c.st) { let target_texture = if inside_polka_dot(c.st) {
@ -54,11 +64,22 @@ impl FloatDotsTexture {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumDotsTexture { pub struct SpectrumDotsTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub outside_dot: Ptr<SpectrumTexture>,
pub inside_dot: Ptr<SpectrumTexture>, pub inside_dot: Ptr<SpectrumTexture>,
pub outside_dot: Ptr<SpectrumTexture>,
} }
impl SpectrumDotsTexture { impl SpectrumDotsTexture {
pub fn new(
mapping: TextureMapping2D,
inside_dot: Ptr<SpectrumTexture>,
outside_dot: Ptr<SpectrumTexture>,
) -> Self {
Self {
mapping,
inside_dot,
outside_dot,
}
}
pub fn evaluate( pub fn evaluate(
&self, &self,
ctx: &TextureEvalContext, ctx: &TextureEvalContext,

View file

@ -5,11 +5,18 @@ use crate::utils::noise::fbm;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct FBmTexture { pub struct FBmTexture {
pub mapping: TextureMapping3D, pub mapping: TextureMapping3D,
pub omega: Float,
pub octaves: u32, pub octaves: u32,
pub omega: Float,
} }
impl FBmTexture { impl FBmTexture {
pub fn new(mapping: TextureMapping3D, octaves: u32, omega: Float) -> Self {
Self {
mapping,
omega,
octaves,
}
}
pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float { pub fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let c = self.mapping.map(ctx); let c = self.mapping.map(ctx);
fbm(c.p, c.dpdx, c.dpdy, self.omega, self.octaves) fbm(c.p, c.dpdx, c.dpdy, self.omega, self.octaves)

39
shared/src/utils/error.rs Normal file
View file

@ -0,0 +1,39 @@
//! Errors for the shared crate.
//!
//! `shared` is `#![no_std]` and is compiled for SPIR-V and CUDA, so it must not
//! depend on `anyhow` -- whose default features enable `std`. These variants are
//! `Copy` and allocation-free; the CPU-side caller holds the offending string and
//! the `FileLoc`, so it supplies those when reporting.
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
UnknownWrapMode,
UnknownFilterFunction,
UnknownColorEncoding,
/// `look_at` received an up vector parallel to the viewing direction.
DegenerateLookAt,
/// A transform matrix could not be inverted (pbrt's `InverseOrDie`).
SingularMatrix,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::UnknownWrapMode => "unknown wrap mode",
Self::UnknownFilterFunction => "unknown filter function",
Self::UnknownColorEncoding => "unknown color encoding",
Self::DegenerateLookAt => {
"LookAt: \"up\" vector and viewing direction are parallel"
}
Self::SingularMatrix => "matrix is not invertible",
})
}
}
// Stable in core since 1.81, and the same trait `std::error::Error` re-exports --
// so `?` and `anyhow::Context` keep working unchanged on the CPU side.
impl core::error::Error for Error {}
pub type Result<T> = core::result::Result<T, Error>;

View file

@ -2,6 +2,7 @@ pub mod alloc;
pub mod atomic; pub mod atomic;
pub mod complex; pub mod complex;
pub mod containers; pub mod containers;
pub mod error;
pub mod hash; pub mod hash;
pub mod interval; pub mod interval;
pub mod math; pub mod math;

View file

@ -1,3 +1,4 @@
use alloc::string::String;
use crate::Float; use crate::Float;
use crate::core::geometry::{Bounds2f, Bounds2i, Point2f, Point2i}; use crate::core::geometry::{Bounds2f, Bounds2i, Point2f, Point2i};
use core::ops::Deref; use core::ops::Deref;
@ -17,6 +18,7 @@ pub struct BasicPBRTOptions {
pub disable_wavelength_jitter: bool, pub disable_wavelength_jitter: bool,
pub disable_texture_filtering: bool, pub disable_texture_filtering: bool,
pub force_diffuse: bool, pub force_diffuse: bool,
pub record_pixel_statistics: bool,
pub use_gpu: bool, pub use_gpu: bool,
pub wavefront: bool, pub wavefront: bool,
pub interactive: bool, pub interactive: bool,
@ -33,6 +35,7 @@ impl Default for BasicPBRTOptions {
disable_wavelength_jitter: false, disable_wavelength_jitter: false,
disable_texture_filtering: false, disable_texture_filtering: false,
force_diffuse: false, force_diffuse: false,
record_pixel_statistics: false,
use_gpu: false, use_gpu: false,
wavefront: false, wavefront: false,
interactive: false, interactive: false,
@ -42,7 +45,7 @@ impl Default for BasicPBRTOptions {
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
pub struct PBRTOptions { pub struct PBRTOptions {
pub basic: BasicPBRTOptions, pub basic: BasicPBRTOptions,
@ -52,8 +55,8 @@ pub struct PBRTOptions {
pub image_file: &'static str, pub image_file: &'static str,
pub pixel_samples: Option<i32>, pub pixel_samples: Option<i32>,
pub gpu_device: Option<u32>, pub gpu_device: Option<u32>,
pub mse_reference_image: Option<&'static str>, pub mse_reference_image: Option<String>,
pub mse_reference_output: Option<&'static str>, pub mse_reference_output: Option<String>,
pub debug_start: Option<(Point2i, i32)>, pub debug_start: Option<(Point2i, i32)>,
pub quick_render: bool, pub quick_render: bool,
pub upgrade: bool, pub upgrade: bool,

View file

@ -14,7 +14,7 @@ use crate::core::interaction::{
}; };
use crate::utils::gpu_array_from_fn; use crate::utils::gpu_array_from_fn;
use crate::{gamma, Float}; use crate::{gamma, Float};
use anyhow::{bail, Context, Result}; use crate::utils::error::{Error, Result};
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -2125,15 +2125,7 @@ pub fn look_at(
// Initialize first three columns of viewing matrix // Initialize first three columns of viewing matrix
let dir = (look - pos).normalize(); let dir = (look - pos).normalize();
if Vector3f::from(up).normalize().cross(dir).norm() == 0. { if Vector3f::from(up).normalize().cross(dir).norm() == 0. {
bail!( return Err(Error::DegenerateLookAt);
"LookAt: \"up\" vector ({}, {}, {}) and viewing direction ({}, {}, {}) passed to LookAt are pointing in the same direction.",
up.x(),
up.y(),
up.z(),
dir.x(),
dir.y(),
dir.z()
);
} }
let right = Vector3f::from(up).normalize().cross(dir).normalize(); let right = Vector3f::from(up).normalize().cross(dir).normalize();
let new_up = dir.cross(right); let new_up = dir.cross(right);
@ -2150,8 +2142,6 @@ pub fn look_at(
world_from_camera[2][2] = dir.z(); world_from_camera[2][2] = dir.z();
world_from_camera[3][2] = 0.; world_from_camera[3][2] = 0.;
let camera_from_world = world_from_camera let camera_from_world = world_from_camera.inverse().ok_or(Error::SingularMatrix)?;
.inverse()
.context("Failed to inverse viewing matrix")?;
Ok(TransformGeneric::new(camera_from_world, world_from_camera)) Ok(TransformGeneric::new(camera_from_world, world_from_camera))
} }

View file

@ -1,4 +1,5 @@
use crate::globals::get_options; use crate::globals::get_options;
use shared::Ptr;
use shared::bxdfs::DiffuseBxDF; use shared::bxdfs::DiffuseBxDF;
use shared::core::bsdf::BSDF; use shared::core::bsdf::BSDF;
use shared::core::bssrdf::BSSRDF; use shared::core::bssrdf::BSSRDF;
@ -10,13 +11,12 @@ use shared::core::material::{Material, MaterialEvalContext, MaterialTrait};
use shared::core::sampler::{Sampler, SamplerTrait}; use shared::core::sampler::{Sampler, SamplerTrait};
use shared::core::texture::UniversalTextureEvaluator; use shared::core::texture::UniversalTextureEvaluator;
use shared::spectra::SampledWavelengths; use shared::spectra::SampledWavelengths;
use shared::Ptr;
pub trait InteractionGetter { pub trait InteractionGetter {
fn get_bsdf( fn get_bsdf(
&mut self, &mut self,
r: &Ray, r: &Ray,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
camera: &Camera, camera: &Camera,
sampler: &mut Sampler, sampler: &mut Sampler,
materials: &[Material], materials: &[Material],
@ -35,7 +35,7 @@ impl InteractionGetter for SurfaceInteraction {
fn get_bsdf( fn get_bsdf(
&mut self, &mut self,
r: &Ray, r: &Ray,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
camera: &Camera, camera: &Camera,
sampler: &mut Sampler, sampler: &mut Sampler,
materials: &[Material], materials: &[Material],
@ -98,7 +98,7 @@ impl InteractionGetter for MediumInteraction {
fn get_bsdf( fn get_bsdf(
&mut self, &mut self,
_r: &Ray, _r: &Ray,
_lambda: &SampledWavelengths, _lambda: &mut SampledWavelengths,
_camera: &Camera, _camera: &Camera,
_sampler: &mut Sampler, _sampler: &mut Sampler,
_materials: &[Material], _materials: &[Material],
@ -121,7 +121,7 @@ impl InteractionGetter for SimpleInteraction {
fn get_bsdf( fn get_bsdf(
&mut self, &mut self,
_r: &Ray, _r: &Ray,
_lambda: &SampledWavelengths, _lambda: &mut SampledWavelengths,
_camera: &Camera, _camera: &Camera,
_sampler: &mut Sampler, _sampler: &mut Sampler,
_materials: &[Material], _materials: &[Material],

View file

@ -1,18 +1,17 @@
use super::entities::*;
use super::BasicScene; use super::BasicScene;
use super::entities::*;
use crate::Arena;
use crate::spectra::get_colorspace_device; use crate::spectra::get_colorspace_device;
use crate::utils::error::FileLoc; use crate::utils::error::FileLoc;
use crate::utils::parameters::{ParameterDictionary, ParsedParameterVector}; use crate::utils::parameters::{ParameterDictionary, ParsedParameterVector};
use crate::utils::parser::{ParserError, ParserTarget}; use crate::utils::parser::{AtLoc, ParserError, ParserTarget};
use crate::Arena; use shared::Float;
use anyhow::Context;
use shared::core::camera::CameraTransform; use shared::core::camera::CameraTransform;
use shared::core::geometry::Vector3f; use shared::core::geometry::Vector3f;
use shared::spectra::RGBColorSpace; use shared::spectra::RGBColorSpace;
use shared::utils::options::RenderingCoordinateSystem; use shared::utils::options::{PBRTOptions, RenderingCoordinateSystem};
use shared::utils::transform; use shared::utils::transform;
use shared::utils::transform::{AnimatedTransform, Transform}; use shared::utils::transform::{AnimatedTransform, Transform};
use shared::Float;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::sync::Arc; use std::sync::Arc;
@ -24,6 +23,16 @@ fn normalize_utf8(input: &str) -> String {
input.nfc().collect::<String>() input.nfc().collect::<String>()
} }
/// pbrt's `normalizeArg` (util/args.h:22): downcase and drop `-`/`_` so option
/// names can be written a little loosely.
fn normalize_arg(input: &str) -> String {
input
.chars()
.filter(|c| *c != '-' && *c != '_')
.flat_map(|c| c.to_lowercase())
.collect()
}
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
struct TransformSet { struct TransformSet {
t: [Transform; MAX_TRANSFORMS], t: [Transform; MAX_TRANSFORMS],
@ -125,6 +134,11 @@ pub struct BasicSceneBuilder {
named_material_names: HashSet<String>, named_material_names: HashSet<String>,
medium_names: HashSet<String>, medium_names: HashSet<String>,
/// `Option` directives accumulate here during parsing. The global options are
/// a `OnceLock` written after the parse, so they cannot be mutated in place
/// the way pbrt mutates its global `Options`.
pending_options: PBRTOptions,
current_camera: Option<CameraSceneEntity>, current_camera: Option<CameraSceneEntity>,
current_film: Option<SceneEntity>, current_film: Option<SceneEntity>,
current_integrator: Option<SceneEntity>, current_integrator: Option<SceneEntity>,
@ -177,6 +191,7 @@ impl BasicSceneBuilder {
spectrum_texture_names: HashSet::new(), spectrum_texture_names: HashSet::new(),
named_material_names: HashSet::new(), named_material_names: HashSet::new(),
medium_names: HashSet::new(), medium_names: HashSet::new(),
pending_options: PBRTOptions::default(),
current_camera: Some(CameraSceneEntity { current_camera: Some(CameraSceneEntity {
base: SceneEntity { base: SceneEntity {
name: "perspective".into(), name: "perspective".into(),
@ -211,6 +226,12 @@ impl BasicSceneBuilder {
} }
} }
/// Options gathered from the scene's `Option` directives. Callers merge these
/// with any command-line options and pass the result to `init_pbrt`.
pub fn options(&self) -> &PBRTOptions {
&self.pending_options
}
fn for_active_transforms<F>(&mut self, f: F) fn for_active_transforms<F>(&mut self, f: F)
where where
F: Fn(&Transform) -> Transform, F: Fn(&Transform) -> Transform,
@ -254,12 +275,6 @@ impl BasicSceneBuilder {
} }
} }
impl From<anyhow::Error> for ParserError {
fn from(e: anyhow::Error) -> Self {
ParserError::Generic(e.to_string(), FileLoc::default())
}
}
impl ParserTarget for BasicSceneBuilder { impl ParserTarget for BasicSceneBuilder {
fn reverse_orientation(&mut self, loc: FileLoc) -> Result<(), ParserError> { fn reverse_orientation(&mut self, loc: FileLoc) -> Result<(), ParserError> {
self.verify_world("ReverseOrientation", &loc)?; self.verify_world("ReverseOrientation", &loc)?;
@ -329,8 +344,7 @@ impl ParserTarget for BasicSceneBuilder {
uz: Float, uz: Float,
loc: FileLoc, loc: FileLoc,
) -> Result<(), ParserError> { ) -> Result<(), ParserError> {
let t = transform::look_at((ex, ey, ez), (lx, ly, lz), (ux, uy, uz)) let t = transform::look_at((ex, ey, ez), (lx, ly, lz), (ux, uy, uz)).at(&loc)?;
.with_context(|| format!("at {}", loc))?;
self.for_active_transforms(|cur| cur * &t); self.for_active_transforms(|cur| cur * &t);
Ok(()) Ok(())
} }
@ -447,8 +461,65 @@ impl ParserTarget for BasicSceneBuilder {
Ok(()) Ok(())
} }
fn option(&mut self, _name: &str, _value: &str, _loc: FileLoc) -> Result<(), ParserError> { fn option(&mut self, name: &str, value: &str, loc: FileLoc) -> Result<(), ParserError> {
todo!() let bad = |what: &str| {
Err(ParserError::Generic(
format!("{value:?}: expected {what} for option {name:?}"),
loc.clone(),
))
};
let as_bool = |b: &mut bool| match value {
"true" => {
*b = true;
Ok(())
}
"false" => {
*b = false;
Ok(())
}
_ => bad("\"true\" or \"false\""),
};
let opts = &mut self.pending_options;
match normalize_arg(name).as_str() {
"disablepixeljitter" => as_bool(&mut opts.basic.disable_pixel_jitter)?,
"disabletexturefiltering" => as_bool(&mut opts.basic.disable_texture_filtering)?,
"disablewavelengthjitter" => as_bool(&mut opts.basic.disable_wavelength_jitter)?,
"forcediffuse" => as_bool(&mut opts.basic.force_diffuse)?,
"pixelstats" => as_bool(&mut opts.basic.record_pixel_statistics)?,
"wavefront" => as_bool(&mut opts.basic.wavefront)?,
"displacementedgescale" => match value.parse::<Float>() {
Ok(v) => opts.displacement_edge_scale = v,
Err(_) => return bad("a floating-point value"),
},
"seed" => match value.parse::<i32>() {
Ok(v) => opts.basic.seed = v,
Err(_) => return bad("an integer"),
},
// The tokenizer has already dequoted these, so unlike pbrt we do not
// re-check for surrounding quotes.
"msereferenceimage" => {
opts.mse_reference_image = Some(value.to_string())
}
"msereferenceout" => {
opts.mse_reference_output = Some(value.to_string())
}
"rendercoordsys" => {
opts.basic.rendering_space = match value {
"camera" => RenderingCoordinateSystem::Camera,
"cameraworld" => RenderingCoordinateSystem::CameraWorld,
"world" => RenderingCoordinateSystem::World,
_ => return bad("\"camera\", \"cameraworld\" or \"world\""),
}
}
_ => {
return Err(ParserError::Generic(
format!("{name:?}: unknown option"),
loc,
));
}
}
Ok(())
} }
fn pixel_filter( fn pixel_filter(
@ -534,7 +605,8 @@ impl ParserTarget for BasicSceneBuilder {
params, params,
&self.graphics_state.medium_attributes, &self.graphics_state.medium_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
let render_from_object = self.render_from_object(); let render_from_object = self.render_from_object();
let entity = MediumSceneEntity { let entity = MediumSceneEntity {
base: SceneEntity { base: SceneEntity {
@ -702,7 +774,8 @@ impl ParserTarget for BasicSceneBuilder {
params.clone(), params.clone(),
&self.graphics_state.texture_attributes, &self.graphics_state.texture_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
if type_name != "float" && type_name != "spectrum" { if type_name != "float" && type_name != "spectrum" {
return Err(ParserError::Generic( return Err(ParserError::Generic(
@ -762,7 +835,8 @@ impl ParserTarget for BasicSceneBuilder {
params, params,
&self.graphics_state.material_attributes, &self.graphics_state.material_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
let entity = SceneEntity { let entity = SceneEntity {
name: name.to_string(), name: name.to_string(),
loc, loc,
@ -794,7 +868,8 @@ impl ParserTarget for BasicSceneBuilder {
params, params,
&self.graphics_state.material_attributes, &self.graphics_state.material_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
// pbrt stores an empty entity name here: the material type comes from the // pbrt stores an empty entity name here: the material type comes from the
// "type" parameter (scene.cpp:719). // "type" parameter (scene.cpp:719).
@ -827,7 +902,8 @@ impl ParserTarget for BasicSceneBuilder {
params.clone(), params.clone(),
&self.graphics_state.medium_attributes, &self.graphics_state.medium_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
let render_from_light = self.render_from_object(); let render_from_light = self.render_from_object();
@ -874,7 +950,8 @@ impl ParserTarget for BasicSceneBuilder {
params.clone(), params.clone(),
&self.graphics_state.shape_attributes, &self.graphics_state.shape_attributes,
self.graphics_state.color_space.clone(), self.graphics_state.color_space.clone(),
)?; )
.at(&loc)?;
let render_from_object = self.render_from_object_at(0); let render_from_object = self.render_from_object_at(0);
let object_from_render = render_from_object.inverse(); let object_from_render = render_from_object.inverse();

View file

@ -1,15 +1,16 @@
use crate::textures::*; use crate::textures::*;
use crate::utils::{MIPMap, MIPMapFilterOptions, TextureParameterDictionary}; use crate::utils::{MIPMap, MIPMapFilterOptions, TextureParameterDictionary};
use crate::{Arena, FileLoc}; use crate::{Arena, FileLoc};
use anyhow::{anyhow, Result}; use anyhow::{Result, anyhow};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use shared::Float;
use shared::core::color::ColorEncoding; use shared::core::color::ColorEncoding;
use shared::core::geometry::Vector3f; use shared::core::geometry::Vector3f;
use shared::core::image::WrapMode; use shared::core::image::WrapMode;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::core::texture::{ use shared::core::texture::{
CylindricalMapping, PlanarMapping, SphericalMapping, TextureEvalContext, TextureMapping2D, CylindricalMapping, PlanarMapping, PointTransformMapping, SphericalMapping,
UVMapping, TextureEvalContext, TextureMapping2D, TextureMapping3D, UVMapping,
}; };
use shared::spectra::{SampledSpectrum, SampledWavelengths}; use shared::spectra::{SampledSpectrum, SampledWavelengths};
use shared::textures::{ use shared::textures::{
@ -18,22 +19,10 @@ use shared::textures::{
SpectrumConstantTexture, SpectrumDotsTexture, WindyTexture, WrinkledTexture, SpectrumConstantTexture, SpectrumDotsTexture, WindyTexture, WrinkledTexture,
}; };
use shared::utils::Transform; use shared::utils::Transform;
use shared::Float;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock}; use std::sync::{Arc, Mutex, OnceLock};
#[enum_dispatch]
pub trait FloatTextureTrait {
fn evaluate(&self, ctx: &TextureEvalContext) -> Float;
}
#[enum_dispatch]
pub trait SpectrumTextureTrait {
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum;
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[enum_dispatch(FloatTextureTrait)]
pub enum FloatTexture { pub enum FloatTexture {
Constant(FloatConstantTexture), Constant(FloatConstantTexture),
Checkerboard(FloatCheckerboardTexture), Checkerboard(FloatCheckerboardTexture),
@ -49,19 +38,12 @@ pub enum FloatTexture {
Bilerp(FloatBilerpTexture), Bilerp(FloatBilerpTexture),
} }
impl Default for FloatTexture { impl Default for FloatTexture {
fn default() -> Self { fn default() -> Self {
FloatTexture::Constant(FloatConstantTexture::new(1.0)) FloatTexture::Constant(FloatConstantTexture::new(1.0))
} }
} }
impl FloatTextureTrait for Arc<FloatTexture> {
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
self.as_ref().evaluate(ctx)
}
}
pub trait CreateFloatTexture { pub trait CreateFloatTexture {
fn create( fn create(
render_from_texture: Transform, render_from_texture: Transform,
@ -101,7 +83,6 @@ impl FloatTexture {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[enum_dispatch(SpectrumTextureTrait)]
pub enum SpectrumTexture { pub enum SpectrumTexture {
Constant(SpectrumConstantTexture), Constant(SpectrumConstantTexture),
Checkerboard(SpectrumCheckerboardTexture), Checkerboard(SpectrumCheckerboardTexture),
@ -120,6 +101,7 @@ pub trait CreateSpectrumTexture {
parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
spectrum_type: SpectrumType, spectrum_type: SpectrumType,
loc: FileLoc, loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture>; ) -> Result<SpectrumTexture>;
} }
@ -130,29 +112,29 @@ impl SpectrumTexture {
params: TextureParameterDictionary, params: TextureParameterDictionary,
spectrum_type: SpectrumType, spectrum_type: SpectrumType,
loc: FileLoc, loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<Self> { ) -> Result<Self> {
match name { match name {
"constant" => { "constant" => {
SpectrumConstantTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumConstantTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"scale" => { "scale" => {
SpectrumScaledTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumScaledTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"mix" => SpectrumMixTexture::create(render_from_texture, params, spectrum_type, loc), "mix" => SpectrumMixTexture::create(render_from_texture, params, spectrum_type, loc, arena),
"directionmix" => { "directionmix" => {
SpectrumDirectionMixTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumDirectionMixTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"bilerp" => { "bilerp" => {
SpectrumBilerpTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumBilerpTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"imagemap" => { "imagemap" => {
SpectrumImageTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumImageTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"checkerboard" => { "checkerboard" => {
SpectrumCheckerboardTexture::create(render_from_texture, params, spectrum_type, loc) SpectrumCheckerboardTexture::create(render_from_texture, params, spectrum_type, loc, arena)
} }
"dots" => SpectrumDotsTexture::create(render_from_texture, params, spectrum_type, loc), "dots" => SpectrumDotsTexture::create(render_from_texture, params, spectrum_type, loc, arena),
_ => Err(anyhow!( _ => Err(anyhow!(
"Spectrum texture type '{}' unknown at {}", "Spectrum texture type '{}' unknown at {}",
name, name,
@ -162,12 +144,6 @@ impl SpectrumTexture {
} }
} }
impl SpectrumTextureTrait for Arc<SpectrumTexture> {
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
self.as_ref().evaluate(ctx, lambda)
}
}
pub trait CreateTextureMapping { pub trait CreateTextureMapping {
fn create( fn create(
params: &TextureParameterDictionary, params: &TextureParameterDictionary,
@ -221,6 +197,21 @@ impl CreateTextureMapping for TextureMapping2D {
} }
} }
impl CreateTextureMapping for TextureMapping3D {
fn create(
params: &TextureParameterDictionary,
render_from_texture: &Transform,
loc: &FileLoc,
) -> Result<Self>
where
Self: Sized,
{
let mapping = PointTransformMapping::new(render_from_texture.inverse());
Ok(TextureMapping3D::PointTransform(mapping))
}
}
pub static TEXTURE_CACHE: OnceLock<Mutex<HashMap<TexInfo, Arc<MIPMap>>>> = OnceLock::new(); pub static TEXTURE_CACHE: OnceLock<Mutex<HashMap<TexInfo, Arc<MIPMap>>>> = OnceLock::new();
pub fn get_texture_cache() -> &'static Mutex<HashMap<TexInfo, Arc<MIPMap>>> { pub fn get_texture_cache() -> &'static Mutex<HashMap<TexInfo, Arc<MIPMap>>> {

View file

@ -35,7 +35,7 @@ pub trait RayIntegratorTrait {
fn li( fn li(
&self, &self,
ray: Ray, ray: Ray,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
visible_surface: bool, visible_surface: bool,
arena: &Arena, arena: &Arena,
@ -69,7 +69,8 @@ impl CreateIntegrator for PathIntegrator {
let _max_depth = parameters.get_one_int("maxdepth", 5)?; let _max_depth = parameters.get_one_int("maxdepth", 5)?;
let _regularize = parameters.get_one_bool("regularize", false)?; let _regularize = parameters.get_one_bool("regularize", false)?;
let light_sampler = create_light_sampler("power", &lights, arena); let light_sampler = create_light_sampler("power", &lights, arena);
let integrator = PathIntegrator::new(aggregate, lights, camera, light_sampler, config, materials); let integrator =
PathIntegrator::new(aggregate, lights, camera, light_sampler, config, materials);
Ok(integrator) Ok(integrator)
} }
} }

View file

@ -1,10 +1,10 @@
use super::RayIntegratorTrait;
use super::base::IntegratorBase; use super::base::IntegratorBase;
use super::constants::*; use super::constants::*;
use super::state::PathState; use super::state::PathState;
use super::RayIntegratorTrait;
use crate::core::interaction::InteractionGetter;
use crate::Arena; use crate::Arena;
use shared::core::bsdf::{BSDFSample, BSDF}; use crate::core::interaction::InteractionGetter;
use shared::core::bsdf::{BSDF, BSDFSample};
use shared::core::bxdf::{BxDFFlags, FArgs, TransportMode}; use shared::core::bxdf::{BxDFFlags, FArgs, TransportMode};
use shared::core::camera::Camera; use shared::core::camera::Camera;
use shared::core::film::VisibleSurface; use shared::core::film::VisibleSurface;
@ -72,7 +72,6 @@ pub struct PathIntegrator {
materials: Vec<Material>, materials: Vec<Material>,
} }
impl PathIntegrator { impl PathIntegrator {
pub fn new( pub fn new(
aggregate: Arc<Primitive>, aggregate: Arc<Primitive>,
@ -208,7 +207,7 @@ impl RayIntegratorTrait for PathIntegrator {
fn li( fn li(
&self, &self,
mut ray: Ray, mut ray: Ray,
lambda: &SampledWavelengths, lambda: &mut SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
want_visible: bool, want_visible: bool,
_arena: &Arena, _arena: &Arena,
@ -247,7 +246,9 @@ impl RayIntegratorTrait for PathIntegrator {
} }
// Get BSDF // Get BSDF
let Some(mut bsdf) = isect.get_bsdf(&ray, lambda, &self.camera, sampler, &self.materials) else { let Some(mut bsdf) =
isect.get_bsdf(&ray, lambda, &self.camera, sampler, &self.materials)
else {
state.specular_bounce = true; state.specular_bounce = true;
isect.skip_intersection(&mut ray, t_hit); isect.skip_intersection(&mut ray, t_hit);
continue; continue;

View file

@ -1,5 +1,5 @@
use super::base::IntegratorBase;
use super::RayIntegratorTrait; use super::RayIntegratorTrait;
use super::base::IntegratorBase;
use crate::core::camera::InitMetadata; use crate::core::camera::InitMetadata;
use crate::core::film::FilmTrait; use crate::core::film::FilmTrait;
use crate::core::image::{HostImage, ImageIO, ImageMetadata}; use crate::core::image::{HostImage, ImageIO, ImageMetadata};
@ -7,12 +7,12 @@ use crate::globals::get_options;
use crate::spectra::get_spectra_context; use crate::spectra::get_spectra_context;
use crate::{Arena, PbrtProgress}; use crate::{Arena, PbrtProgress};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use shared::Float;
use shared::core::camera::{Camera, CameraTrait}; use shared::core::camera::{Camera, CameraTrait};
use shared::core::geometry::{Bounds2i, Point2i}; use shared::core::geometry::{Bounds2i, Point2i};
use shared::core::sampler::get_camera_sample; use shared::core::sampler::get_camera_sample;
use shared::core::sampler::{Sampler, SamplerTrait}; use shared::core::sampler::{Sampler, SamplerTrait};
use shared::spectra::SampledSpectrum; use shared::spectra::SampledSpectrum;
use shared::Float;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
@ -214,7 +214,7 @@ pub fn evaluate_pixel_sample<T: RayIntegratorTrait>(
lu = 0.5; lu = 0.5;
} }
let lambda = camera.get_film().sample_wavelengths(lu); let mut lambda = camera.get_film().sample_wavelengths(lu);
let film = camera.get_film(); let film = camera.get_film();
let filter = film.get_filter(); let filter = film.get_filter();
let camera_sample = get_camera_sample(sampler, pixel, filter); let camera_sample = get_camera_sample(sampler, pixel, filter);
@ -229,7 +229,7 @@ pub fn evaluate_pixel_sample<T: RayIntegratorTrait>(
let initialize_visible_surface = film.uses_visible_surface(); let initialize_visible_surface = film.uses_visible_surface();
let (mut l, visible_surface) = integrator.li( let (mut l, visible_surface) = integrator.li(
camera_ray.ray, camera_ray.ray,
&lambda, &mut lambda,
sampler, sampler,
initialize_visible_surface, initialize_visible_surface,
arena, arena,

View file

@ -1,51 +1,61 @@
use crate::Arena; use crate::Arena;
use crate::core::texture::{ use crate::core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTextureTrait, SpectrumTexture, CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture, SpectrumTexture,
SpectrumTextureTrait,
}; };
use crate::utils::{FileLoc, TextureParameterDictionary};
use anyhow::Result; use anyhow::Result;
use shared::core::texture::{SpectrumType, TextureEvalContext}; use shared::core::spectrum::Spectrum;
use shared::{ use shared::core::texture::{SpectrumType, TextureMapping2D};
spectra::{SampledSpectrum, SampledWavelengths}, use shared::spectra::ConstantSpectrum;
textures::{FloatBilerpTexture, SpectrumBilerpTexture}, use shared::textures::{FloatBilerpTexture, SpectrumBilerpTexture};
utils::Transform, use shared::utils::Transform;
};
use crate::{
core::texture::FloatTexture,
utils::{FileLoc, TextureParameterDictionary},
};
impl CreateFloatTexture for FloatBilerpTexture { impl CreateFloatTexture for FloatBilerpTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_loc: FileLoc, loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<FloatTexture> { ) -> Result<FloatTexture> {
todo!() let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
}
}
impl FloatTextureTrait for FloatBilerpTexture { let tex = FloatBilerpTexture::new(
fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float { map,
todo!() parameters.get_one_float("v00", 0.)?,
parameters.get_one_float("v01", 1.)?,
parameters.get_one_float("v10", 0.)?,
parameters.get_one_float("v11", 1.)?,
);
Ok(FloatTexture::Bilerp(tex))
} }
} }
impl CreateSpectrumTexture for SpectrumBilerpTexture { impl CreateSpectrumTexture for SpectrumBilerpTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, spectrum_type: SpectrumType,
_loc: FileLoc, loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
} let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
} let one = Spectrum::Constant(ConstantSpectrum::new(1.));
impl SpectrumTextureTrait for SpectrumBilerpTexture { let get = |name: &str, def: Spectrum| {
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum { let s = parameters
todo!() .get_one_spectrum(name, Some(def), spectrum_type)
.unwrap_or(def);
arena.alloc(s)
};
let tex = SpectrumBilerpTexture::new(
map,
get("v00", zero),
get("v01", one),
get("v10", zero),
get("v11", one),
);
Ok(SpectrumTexture::Bilerp(tex))
} }
} }

View file

@ -1,53 +1,79 @@
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::{Result, bail};
use shared::{ use shared::{
core::texture::SpectrumType, core::spectrum::Spectrum,
textures::{FloatCheckerboardTexture, SpectrumCheckerboardTexture}, core::texture::{SpectrumType, TextureMapping2D, TextureMapping3D},
spectra::ConstantSpectrum,
textures::{CheckerMap, FloatCheckerboardTexture, SpectrumCheckerboardTexture},
utils::Transform, utils::Transform,
}; };
use crate::{ use crate::{
core::texture::{ core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture,
SpectrumTexture, SpectrumTextureTrait, SpectrumTexture,
}, },
utils::{FileLoc, TextureParameterDictionary}, utils::{ArenaUpload, FileLoc, TextureParameterDictionary},
}; };
fn checker_map(
render_from_texture: Transform,
parameters: TextureParameterDictionary,
loc: FileLoc,
) -> Result<CheckerMap> {
match parameters.get_one_int("dimension", 2)? {
2 => Ok(CheckerMap::D2(TextureMapping2D::create(
&parameters,
&render_from_texture,
&loc,
)?)),
3 => Ok(CheckerMap::D3(TextureMapping3D::create(
&parameters,
&render_from_texture,
&loc,
)?)),
dim => bail!("{loc}: {dim} dimensional checkerboard texture not supported"),
}
}
impl CreateFloatTexture for FloatCheckerboardTexture { impl CreateFloatTexture for FloatCheckerboardTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_loc: FileLoc, loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<FloatTexture> { ) -> Result<FloatTexture> {
todo!() let tex1 = arena.upload(parameters.get_float_texture("tex1", 1.)?);
} let tex2 = arena.upload(parameters.get_float_texture("tex2", 0.)?);
} let map = checker_map(render_from_texture, parameters, loc)?;
let tex = FloatCheckerboardTexture::new(map, [tex1, tex2]);
impl FloatTextureTrait for FloatCheckerboardTexture { Ok(FloatTexture::Checkerboard(tex))
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
todo!()
} }
} }
impl CreateSpectrumTexture for SpectrumCheckerboardTexture { impl CreateSpectrumTexture for SpectrumCheckerboardTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, spectrum_type: SpectrumType,
_loc: FileLoc, loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
} let one = Spectrum::Constant(ConstantSpectrum::new(1.));
} let tex = |name: &str, def: Spectrum| {
arena.upload(
parameters
.get_spectrum_texture(name, Some(def), spectrum_type)
.expect("default supplied"),
)
};
impl SpectrumTextureTrait for SpectrumCheckerboardTexture { let tex1 = tex("tex1", one);
fn evaluate( let tex2 = tex("tex2", zero);
&self,
_ctx: &shared::core::texture::TextureEvalContext, let map = checker_map(render_from_texture, parameters, loc)?;
_lambda: &shared::spectra::SampledWavelengths, let tex = SpectrumCheckerboardTexture::new(map, [tex1, tex2]);
) -> shared::spectra::SampledSpectrum { Ok(SpectrumTexture::Checkerboard(tex))
todo!()
} }
} }

View file

@ -1,53 +1,46 @@
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
use shared::core::spectrum::Spectrum;
use shared::spectra::ConstantSpectrum;
use shared::{ use shared::{
core::texture::{SpectrumType, TextureEvalContext}, core::texture::SpectrumType,
textures::{FloatConstantTexture, SpectrumConstantTexture}, textures::{FloatConstantTexture, SpectrumConstantTexture},
utils::Transform, utils::Transform,
}; };
use crate::{ use crate::{
core::texture::{ core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, CreateFloatTexture, CreateSpectrumTexture, FloatTexture, SpectrumTexture },
SpectrumTexture, SpectrumTextureTrait, utils::{FileLoc, TextureParameterDictionary}
},
utils::{FileLoc, TextureParameterDictionary},
}; };
impl CreateFloatTexture for FloatConstantTexture { impl CreateFloatTexture for FloatConstantTexture {
fn create( fn create(
_render_from_texture: Transform, _render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena, _arena: &Arena,
) -> Result<FloatTexture> { ) -> Result<FloatTexture> {
todo!() let value = parameters.get_one_float("value", 1.)?;
} Ok(FloatTexture::Constant(FloatConstantTexture::new(value)))
}
impl FloatTextureTrait for FloatConstantTexture {
fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float {
todo!()
} }
} }
impl CreateSpectrumTexture for SpectrumConstantTexture { impl CreateSpectrumTexture for SpectrumConstantTexture {
fn create( fn create(
_render_from_texture: Transform, _render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, spectrum_type: SpectrumType,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() let one = Spectrum::Constant(ConstantSpectrum::new(1.));
let value = parameters
.get_one_spectrum("value", Some(one), spectrum_type)
.unwrap_or(one);
Ok(SpectrumTexture::Constant(SpectrumConstantTexture::new(
value,
)))
} }
} }
impl SpectrumTextureTrait for SpectrumConstantTexture {
fn evaluate(
&self,
_ctx: &TextureEvalContext,
_lambda: &shared::spectra::SampledWavelengths,
) -> shared::spectra::SampledSpectrum {
todo!()
}
}

View file

@ -1,53 +1,57 @@
use crate::Arena; use crate::{Arena, ArenaUpload};
use anyhow::Result; use anyhow::Result;
use shared::{ use shared::{
core::texture::SpectrumType, core::spectrum::Spectrum,
core::texture::{SpectrumType, TextureMapping2D},
spectra::ConstantSpectrum,
textures::{FloatDotsTexture, SpectrumDotsTexture}, textures::{FloatDotsTexture, SpectrumDotsTexture},
utils::Transform, utils::Transform,
}; };
use crate::{ use crate::{
core::texture::{ core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture,
SpectrumTexture, SpectrumTextureTrait, SpectrumTexture,
}, },
utils::{FileLoc, TextureParameterDictionary}, utils::{FileLoc, TextureParameterDictionary},
}; };
impl FloatTextureTrait for FloatDotsTexture {
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
todo!()
}
}
impl CreateFloatTexture for FloatDotsTexture { impl CreateFloatTexture for FloatDotsTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_loc: FileLoc, loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<FloatTexture> { ) -> Result<FloatTexture> {
todo!() let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
} let inside = parameters.get_float_texture("inside", 1.)?;
} let outside = parameters.get_float_texture("outside", 1.)?;
impl SpectrumTextureTrait for SpectrumDotsTexture { let tex = FloatDotsTexture::new(map, arena.upload(inside), arena.upload(outside));
fn evaluate(
&self, Ok(FloatTexture::Dots(tex))
_ctx: &shared::core::texture::TextureEvalContext,
_lambda: &shared::spectra::SampledWavelengths,
) -> shared::spectra::SampledSpectrum {
todo!()
} }
} }
impl CreateSpectrumTexture for SpectrumDotsTexture { impl CreateSpectrumTexture for SpectrumDotsTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, spectrum_type: SpectrumType,
_loc: FileLoc, loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
let zero = Spectrum::Constant(ConstantSpectrum::new(0.));
let one = Spectrum::Constant(ConstantSpectrum::new(1.));
let get = |name: &str, def: Spectrum| {
let t = parameters
.get_spectrum_texture(name, Some(def), spectrum_type)
.expect("default supplied");
arena.upload(t)
};
let tex = SpectrumDotsTexture::new(map, get("inside", one), get("outside", zero));
Ok(SpectrumTexture::Dots(tex))
} }
} }

View file

@ -1,26 +1,26 @@
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
use shared::core::texture::TextureEvalContext; use shared::core::texture::{TextureEvalContext, TextureMapping3D};
use shared::{textures::FBmTexture, utils::Transform}; use shared::{textures::FBmTexture, utils::Transform};
use crate::{ use crate::{
core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait}, core::texture::{CreateFloatTexture, CreateTextureMapping, FloatTexture},
utils::{FileLoc, TextureParameterDictionary}, utils::{FileLoc, TextureParameterDictionary},
}; };
impl CreateFloatTexture for FBmTexture { impl CreateFloatTexture for FBmTexture {
fn create( fn create(
_render_from_texture: Transform, render_from_texture: Transform,
_parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
_loc: FileLoc, loc: FileLoc,
_arena: &Arena, arena: &Arena,
) -> Result<FloatTexture> { ) -> Result<FloatTexture> {
todo!() let map = TextureMapping3D::create(&parameters, &render_from_texture, &loc)?;
} let tex = FBmTexture::new(
} map,
parameters.get_one_int("octaves", 5)?.try_into().unwrap(),
impl FloatTextureTrait for FBmTexture { parameters.get_one_float("roughness", 0.5)?,
fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float { );
todo!() Ok(FloatTexture::FBm(tex))
} }
} }

View file

@ -1,12 +1,11 @@
use crate::core::texture::{get_texture_cache, CreateTextureMapping, TexInfo}; use crate::core::texture::{get_texture_cache, CreateTextureMapping, TexInfo};
use crate::core::texture::{ use crate::core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, CreateFloatTexture, CreateSpectrumTexture, FloatTexture, SpectrumTexture
SpectrumTextureTrait,
}; };
use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions}; use crate::utils::mipmap::{MIPMap, MIPMapFilterOptions};
use crate::utils::{resolve_filename, FileLoc, TextureParameterDictionary}; use crate::utils::{resolve_filename, FileLoc, TextureParameterDictionary};
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::{Context, Result};
use shared::core::color::RGB; use shared::core::color::RGB;
use shared::core::color::{ColorEncoding, SRGBEncoding}; use shared::core::color::{ColorEncoding, SRGBEncoding};
use shared::core::geometry::Vector2f; use shared::core::geometry::Vector2f;
@ -15,7 +14,7 @@ use shared::core::spectrum::SpectrumTrait;
use shared::core::texture::{SpectrumType, TexCoord2D, TextureEvalContext, TextureMapping2D}; use shared::core::texture::{SpectrumType, TexCoord2D, TextureEvalContext, TextureMapping2D};
use shared::spectra::{ use shared::spectra::{
RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum, RGBAlbedoSpectrum, RGBIlluminantSpectrum, RGBUnboundedSpectrum, SampledSpectrum,
SampledWavelengths, SampledWavelengths
}; };
use shared::utils::Transform; use shared::utils::Transform;
use shared::Float; use shared::Float;
@ -28,7 +27,7 @@ pub struct ImageTextureBase {
pub filename: String, pub filename: String,
pub scale: Float, pub scale: Float,
pub invert: bool, pub invert: bool,
pub mipmap: Arc<MIPMap>, pub mipmap: Arc<MIPMap>
} }
impl ImageTextureBase { impl ImageTextureBase {
@ -45,7 +44,7 @@ impl ImageTextureBase {
filename: filename.clone(), filename: filename.clone(),
filter_options, filter_options,
wrap_mode, wrap_mode,
encoding, encoding
}; };
let cache_mutex = get_texture_cache(); let cache_mutex = get_texture_cache();
@ -58,7 +57,7 @@ impl ImageTextureBase {
filename, filename,
scale, scale,
invert, invert,
mipmap: mipmap.clone(), mipmap: mipmap.clone()
}; };
} }
} }
@ -79,7 +78,7 @@ impl ImageTextureBase {
filename, filename,
scale, scale,
invert, invert,
mipmap: stored_mipmap.clone(), mipmap: stored_mipmap.clone()
} }
} }
} }
@ -97,7 +96,7 @@ impl ImageTextureBase {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SpectrumImageTexture { pub struct SpectrumImageTexture {
pub base: ImageTextureBase, pub base: ImageTextureBase,
pub spectrum_type: SpectrumType, pub spectrum_type: SpectrumType
} }
impl SpectrumImageTexture { impl SpectrumImageTexture {
@ -124,58 +123,18 @@ impl SpectrumImageTexture {
Self { Self {
base, base,
spectrum_type, spectrum_type
} }
} }
} }
impl SpectrumTextureTrait for SpectrumImageTexture {
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
use std::sync::atomic::{AtomicU32, Ordering};
static PATH_IMG_COUNT: AtomicU32 = AtomicU32::new(0);
let pn = PATH_IMG_COUNT.fetch_add(1, Ordering::Relaxed);
let mut c = self.base.mapping.map(ctx);
c.st[1] = 1. - c.st[1];
let dst0 = Vector2f::new(c.dsdx, c.dtdx);
let dst1 = Vector2f::new(c.dsdy, c.dtdy);
let raw_rgb = self.base.mipmap.filter::<RGB>(c.st, dst0, dst1);
let rgb_unclamp = self.base.scale * raw_rgb;
let rgb = RGB::clamp_zero(&rgb_unclamp);
if pn < 5 {
eprintln!("PATH_IMG[{pn}] scale={:.6} raw_rgb[0]={:.6} rgb_after_scale[0]={:.6} \
st={:?} dst0={:?} dst1={:?} has_cs={}",
self.base.scale, raw_rgb[0], rgb_unclamp[0],
c.st, dst0, dst1,
self.base.mipmap.get_rgb_colorspace().is_some());
}
if let Some(cs) = self.base.mipmap.get_rgb_colorspace() {
match self.spectrum_type {
SpectrumType::Unbounded => {
return RGBUnboundedSpectrum::new(&cs, rgb).sample(lambda);
}
SpectrumType::Albedo => {
return RGBAlbedoSpectrum::new(&cs, rgb.clamp(0., 1.)).sample(lambda);
}
_ => return RGBIlluminantSpectrum::new(&cs, rgb).sample(lambda),
}
}
let result = SampledSpectrum::new(rgb[0]);
if pn < 5 {
eprintln!("PATH_IMG[{pn}] no-cs branch result[0]={:.6}", result[0]);
}
result
}
}
impl CreateSpectrumTexture for SpectrumImageTexture { impl CreateSpectrumTexture for SpectrumImageTexture {
fn create( fn create(
render_from_texture: Transform, render_from_texture: Transform,
parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
spectrum_type: SpectrumType, spectrum_type: SpectrumType,
loc: FileLoc, loc: FileLoc,
_arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
let mapping = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?; let mapping = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?;
@ -190,7 +149,7 @@ impl CreateSpectrumTexture for SpectrumImageTexture {
"repeat" => WrapMode::Repeat, "repeat" => WrapMode::Repeat,
"clamp" => WrapMode::Clamp, "clamp" => WrapMode::Clamp,
"black" => WrapMode::Black, "black" => WrapMode::Black,
_ => WrapMode::Repeat, _ => WrapMode::Repeat
}; };
let encoding = ColorEncoding::SRGB(SRGBEncoding); let encoding = ColorEncoding::SRGB(SRGBEncoding);
@ -212,7 +171,7 @@ impl CreateSpectrumTexture for SpectrumImageTexture {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FloatImageTexture { pub struct FloatImageTexture {
pub base: ImageTextureBase, pub base: ImageTextureBase
} }
impl FloatImageTexture { impl FloatImageTexture {
@ -234,26 +193,7 @@ impl FloatImageTexture {
scale, scale,
invert, invert,
encoding, encoding,
), )
}
}
}
impl FloatTextureTrait for FloatImageTexture {
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let mut c: TexCoord2D = self.base.mapping.map(ctx);
c.st[1] = 1. - c.st[1];
let v: Float = self.base.scale
* self.base.mipmap.filter::<Float>(
c.st,
Vector2f::new(c.dsdx, c.dtdx),
Vector2f::new(c.dsdy, c.dtdy),
);
if self.base.invert {
(1. - v).max(0.)
} else {
v
} }
} }
} }
@ -271,10 +211,10 @@ impl CreateFloatTexture for FloatImageTexture {
let mut filter_options = MIPMapFilterOptions::default(); let mut filter_options = MIPMapFilterOptions::default();
filter_options.max_anisotropy = max_aniso; filter_options.max_anisotropy = max_aniso;
let ff = FilterFunction::parse(&filter)?; let ff = FilterFunction::parse(&filter).with_context(|| format!("{:?}", filter))?;
filter_options.filter = ff; filter_options.filter = ff;
let wrap_string = parameters.get_one_string("wrap", "repeat")?; let wrap_string = parameters.get_one_string("wrap", "repeat")?;
let wrap_mode = WrapMode::parse(&wrap_string)?; let wrap_mode = WrapMode::parse(&wrap_string).with_context(|| format!("{:?}", wrap_string))?;
let scale = parameters.get_one_float("scale", 1.)?; let scale = parameters.get_one_float("scale", 1.)?;
let invert = parameters.get_one_bool("invert", false)?; let invert = parameters.get_one_bool("invert", false)?;
let filename = resolve_filename(&parameters.get_one_string("filename", "")?); let filename = resolve_filename(&parameters.get_one_string("filename", "")?);
@ -287,7 +227,8 @@ impl CreateFloatTexture for FloatImageTexture {
"linear" "linear"
}; };
let encoding_str = parameters.get_one_string("encoding", default_encoding)?; let encoding_str = parameters.get_one_string("encoding", default_encoding)?;
let encoding = ColorEncoding::from_name(&encoding_str)?; let encoding =
ColorEncoding::from_name(&encoding_str).with_context(|| format!("{:?}", encoding_str))?;
let tex = FloatImageTexture::new( let tex = FloatImageTexture::new(
mapping, mapping,

View file

@ -1,24 +1,19 @@
use crate::core::texture::{CreateSpectrumTexture, SpectrumTexture, SpectrumTextureTrait}; use crate::core::texture::{CreateSpectrumTexture, SpectrumTexture};
use crate::utils::{FileLoc, TextureParameterDictionary};
use crate::Arena;
use anyhow::Result;
use shared::Transform;
use shared::core::texture::SpectrumType; use shared::core::texture::SpectrumType;
use shared::textures::MarbleTexture; use shared::textures::MarbleTexture;
impl SpectrumTextureTrait for MarbleTexture {
fn evaluate(
&self,
_ctx: &shared::core::texture::TextureEvalContext,
_lambda: &shared::spectra::SampledWavelengths,
) -> shared::spectra::SampledSpectrum {
todo!()
}
}
impl CreateSpectrumTexture for MarbleTexture { impl CreateSpectrumTexture for MarbleTexture {
fn create( fn create(
_render_from_texture: shared::utils::Transform, _render_from_texture: Transform,
_parameters: crate::utils::TextureParameterDictionary, _parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, _spectrum_type: SpectrumType,
_loc: crate::utils::FileLoc, _loc: FileLoc,
) -> anyhow::Result<SpectrumTexture> { _arena: &Arena,
) -> Result<SpectrumTexture> {
todo!() todo!()
} }
} }

View file

@ -1,6 +1,5 @@
use crate::core::texture::{ use crate::core::texture::{
CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait, CreateSpectrumTexture, FloatTexture, SpectrumTexture };
};
use crate::utils::{FileLoc, TextureParameterDictionary}; use crate::utils::{FileLoc, TextureParameterDictionary};
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
@ -15,7 +14,7 @@ use std::sync::Arc;
pub struct FloatMixTexture { pub struct FloatMixTexture {
pub tex1: Arc<FloatTexture>, pub tex1: Arc<FloatTexture>,
pub tex2: Arc<FloatTexture>, pub tex2: Arc<FloatTexture>,
pub amount: Arc<FloatTexture>, pub amount: Arc<FloatTexture>
} }
impl FloatMixTexture { impl FloatMixTexture {
@ -41,26 +40,11 @@ impl FloatMixTexture {
} }
} }
impl FloatTextureTrait for FloatMixTexture {
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let amt = self.amount.evaluate(ctx);
let mut t1 = 0.;
let mut t2 = 0.;
if amt != 1. {
t1 = self.tex1.evaluate(ctx);
}
if amt != 0. {
t2 = self.tex2.evaluate(ctx);
}
(1. - amt) * t1 + amt * t2
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FloatDirectionMixTexture { pub struct FloatDirectionMixTexture {
pub tex1: Arc<FloatTexture>, pub tex1: Arc<FloatTexture>,
pub tex2: Arc<FloatTexture>, pub tex2: Arc<FloatTexture>,
pub dir: Vector3f, pub dir: Vector3f
} }
impl FloatDirectionMixTexture { impl FloatDirectionMixTexture {
@ -83,17 +67,11 @@ impl FloatDirectionMixTexture {
} }
} }
impl FloatTextureTrait for FloatDirectionMixTexture {
fn evaluate(&self, _ctx: &TextureEvalContext) -> Float {
todo!()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SpectrumMixTexture { pub struct SpectrumMixTexture {
pub tex1: Arc<SpectrumTexture>, pub tex1: Arc<SpectrumTexture>,
pub tex2: Arc<SpectrumTexture>, pub tex2: Arc<SpectrumTexture>,
pub amount: Arc<FloatTexture>, pub amount: Arc<FloatTexture>
} }
impl CreateSpectrumTexture for SpectrumMixTexture { impl CreateSpectrumTexture for SpectrumMixTexture {
@ -102,22 +80,17 @@ impl CreateSpectrumTexture for SpectrumMixTexture {
_parameters: TextureParameterDictionary, _parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, _spectrum_type: SpectrumType,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() todo!()
} }
} }
impl SpectrumTextureTrait for SpectrumMixTexture {
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
todo!()
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SpectrumDirectionMixTexture { pub struct SpectrumDirectionMixTexture {
pub tex1: Arc<SpectrumTexture>, pub tex1: Arc<SpectrumTexture>,
pub tex2: Arc<SpectrumTexture>, pub tex2: Arc<SpectrumTexture>,
pub dir: Vector3f, pub dir: Vector3f
} }
impl CreateSpectrumTexture for SpectrumDirectionMixTexture { impl CreateSpectrumTexture for SpectrumDirectionMixTexture {
@ -126,13 +99,9 @@ impl CreateSpectrumTexture for SpectrumDirectionMixTexture {
_parameters: TextureParameterDictionary, _parameters: TextureParameterDictionary,
_spectrum_type: SpectrumType, _spectrum_type: SpectrumType,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
todo!() todo!()
} }
} }
impl SpectrumTextureTrait for SpectrumDirectionMixTexture {
fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
todo!()
}
}

View file

@ -10,6 +10,7 @@ mod scaled;
mod windy; mod windy;
mod wrinkled; mod wrinkled;
pub use bilerp::*;
pub use image::*; pub use image::*;
pub use mix::*; pub use mix::*;
pub use scaled::*; pub use scaled::*;

View file

@ -1,5 +1,4 @@
use crate::core::texture::{CreateSpectrumTexture, FloatTexture, SpectrumTexture}; use crate::core::texture::{CreateSpectrumTexture, FloatTexture, SpectrumTexture};
use crate::core::texture::{FloatTextureTrait, SpectrumTextureTrait};
use crate::utils::{FileLoc, TextureParameterDictionary}; use crate::utils::{FileLoc, TextureParameterDictionary};
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
@ -13,7 +12,7 @@ use std::sync::Arc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FloatScaledTexture { pub struct FloatScaledTexture {
pub tex: Arc<FloatTexture>, pub tex: Arc<FloatTexture>,
pub scale: Arc<FloatTexture>, pub scale: Arc<FloatTexture>
} }
impl FloatScaledTexture { impl FloatScaledTexture {
@ -52,20 +51,10 @@ impl FloatScaledTexture {
} }
} }
impl FloatTextureTrait for FloatScaledTexture {
fn evaluate(&self, ctx: &TextureEvalContext) -> Float {
let sc = self.scale.evaluate(ctx);
if sc == 0. {
return 0.;
}
self.tex.evaluate(ctx)
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SpectrumScaledTexture { pub struct SpectrumScaledTexture {
pub tex: Arc<SpectrumTexture>, pub tex: Arc<SpectrumTexture>,
pub scale: Arc<FloatTexture>, pub scale: Arc<FloatTexture>
} }
impl CreateSpectrumTexture for SpectrumScaledTexture { impl CreateSpectrumTexture for SpectrumScaledTexture {
@ -74,6 +63,7 @@ impl CreateSpectrumTexture for SpectrumScaledTexture {
parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
spectrum_type: SpectrumType, spectrum_type: SpectrumType,
_loc: FileLoc, _loc: FileLoc,
_arena: &Arena,
) -> Result<SpectrumTexture> { ) -> Result<SpectrumTexture> {
let one = Spectrum::Constant(ConstantSpectrum::new(1.0)); let one = Spectrum::Constant(ConstantSpectrum::new(1.0));
let tex = parameters let tex = parameters
@ -95,17 +85,8 @@ impl CreateSpectrumTexture for SpectrumScaledTexture {
Ok(SpectrumTexture::Scaled(SpectrumScaledTexture { Ok(SpectrumTexture::Scaled(SpectrumScaledTexture {
tex, tex,
scale, scale
})) }))
} }
} }
impl SpectrumTextureTrait for SpectrumScaledTexture {
fn evaluate(&self, ctx: &TextureEvalContext, lambda: &SampledWavelengths) -> SampledSpectrum {
let sc = self.scale.evaluate(ctx);
if sc == 0. {
return SampledSpectrum::new(0.);
}
self.tex.evaluate(ctx, lambda) * sc
}
}

View file

@ -3,8 +3,8 @@ use anyhow::Result;
use shared::{textures::WindyTexture, utils::Transform}; use shared::{textures::WindyTexture, utils::Transform};
use crate::{ use crate::{
core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait}, core::texture::{CreateFloatTexture, FloatTexture },
utils::{FileLoc, TextureParameterDictionary}, utils::{FileLoc, TextureParameterDictionary}
}; };
impl CreateFloatTexture for WindyTexture { impl CreateFloatTexture for WindyTexture {
@ -18,8 +18,3 @@ impl CreateFloatTexture for WindyTexture {
} }
} }
impl FloatTextureTrait for WindyTexture {
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
todo!()
}
}

View file

@ -3,8 +3,8 @@ use anyhow::Result;
use shared::{textures::WrinkledTexture, utils::Transform}; use shared::{textures::WrinkledTexture, utils::Transform};
use crate::{ use crate::{
core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait}, core::texture::{CreateFloatTexture, FloatTexture },
utils::{FileLoc, TextureParameterDictionary}, utils::{FileLoc, TextureParameterDictionary}
}; };
impl CreateFloatTexture for WrinkledTexture { impl CreateFloatTexture for WrinkledTexture {
@ -18,8 +18,3 @@ impl CreateFloatTexture for WrinkledTexture {
} }
} }
impl FloatTextureTrait for WrinkledTexture {
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
todo!()
}
}

View file

@ -1,3 +1,4 @@
use thiserror::Error;
use anyhow::Result; use anyhow::Result;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use memmap2::Mmap; use memmap2::Mmap;
@ -247,17 +248,39 @@ impl Token {
} }
} }
#[derive(Debug)] #[derive(Debug, Error)]
pub enum ParserError { pub enum ParserError {
#[error("{0}")]
Io(String), Io(String),
#[error("unexpected end of file")]
UnexpectedEof, UnexpectedEof,
#[error("invalid UTF-8: {0}")]
InvalidUtf8(String), InvalidUtf8(String),
#[error("{1}: {0}")]
Generic(String, FileLoc), Generic(String, FileLoc),
#[error("{1}: expected an integer: {0}")]
ParseIntError(String, FileLoc), ParseIntError(String, FileLoc),
#[error("{1}: expected a float: {0}")]
ParseFloatError(String, FileLoc), ParseFloatError(String, FileLoc),
#[error("{1}: numeric overflow: {0}")]
NumericOverflow(String, FileLoc), NumericOverflow(String, FileLoc),
} }
/// Attach a source location to any foreign error, converting it into a
/// `ParserError`. This is the only sanctioned direction: typed errors are
/// produced *at* the boundary that knows the `FileLoc`, never recovered from an
/// erased `anyhow::Error` after the fact.
pub trait AtLoc<T> {
fn at(self, loc: &FileLoc) -> Result<T, ParserError>;
}
impl<T, E: std::fmt::Display> AtLoc<T> for Result<T, E> {
fn at(self, loc: &FileLoc) -> Result<T, ParserError> {
// `{:#}` renders anyhow's full context chain; harmless for plain errors.
self.map_err(|e| ParserError::Generic(format!("{e:#}"), loc.clone()))
}
}
pub enum TokenizerBuffer { pub enum TokenizerBuffer {
Ram(String), Ram(String),
Mapped(Mmap), Mapped(Mmap),

View file

@ -1,11 +1,12 @@
use super::CpuAggregate; use super::CpuAggregate;
use crate::globals::get_options;
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 crate::globals::get_options;
use crate::lights::sampler::create_light_sampler;
use log::debug; use log::debug;
use rayon::prelude::*; use rayon::prelude::*;
use shared::core::LightIdx;
use shared::core::bxdf::{FArgs, TransportMode}; use shared::core::bxdf::{FArgs, TransportMode};
use shared::core::camera::{Camera, CameraTrait}; use shared::core::camera::{Camera, CameraTrait};
use shared::core::film::VisibleSurface; use shared::core::film::VisibleSurface;
@ -18,24 +19,23 @@ use shared::core::interaction::InteractionTrait;
use shared::core::light::{Light, LightSampleContext, LightTrait}; use shared::core::light::{Light, LightSampleContext, LightTrait};
use shared::core::material::{Material, MaterialEvalContext, MaterialTrait}; use shared::core::material::{Material, MaterialEvalContext, MaterialTrait};
use shared::core::primitive::{Primitive, PrimitiveTrait}; use shared::core::primitive::{Primitive, PrimitiveTrait};
use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait}; use shared::core::sampler::{CameraSample, Sampler, SamplerTrait, get_camera_sample};
use shared::core::texture::{BasicTextureEvaluator, TextureEvalContext, UniversalTextureEvaluator}; use shared::core::texture::{BasicTextureEvaluator, TextureEvalContext, UniversalTextureEvaluator};
use shared::core::LightIdx;
use shared::lights::sampler::{LightSampler, LightSamplerTrait}; use shared::lights::sampler::{LightSampler, LightSamplerTrait};
use shared::spectra::{SampledSpectrum, SampledWavelengths}; use shared::spectra::{SampledSpectrum, SampledWavelengths};
use shared::textures::image::{
DIAG_IMG_COUNT, DIAG_IMG_PIXEL0_BITS, DIAG_IMG_RESULT0_BITS, DIAG_IMG_RGB0_BITS,
DIAG_IMG_SCALE_BITS,
};
use shared::utils::math::square; use shared::utils::math::square;
use shared::utils::sampling::power_heuristic; 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, gvec_from_slice, GVec, Ptr, SHADOW_EPSILON}; use shared::{GVec, Ptr, SHADOW_EPSILON, gvec, gvec_from_slice};
use shared::textures::image::{
DIAG_IMG_COUNT, DIAG_IMG_SCALE_BITS, DIAG_IMG_PIXEL0_BITS,
DIAG_IMG_RGB0_BITS, DIAG_IMG_RESULT0_BITS,
};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
static DIAG_EVAL_ENTER: AtomicU32 = AtomicU32::new(0); static DIAG_EVAL_ENTER: AtomicU32 = AtomicU32::new(0);
static DIAG_BSDF_EMPTY: AtomicU32 = AtomicU32::new(0); static DIAG_BSDF_EMPTY: AtomicU32 = AtomicU32::new(0);
@ -232,23 +232,39 @@ impl CpuWavefrontRenderer {
eprintln!("=== DIAG s=0 y0={} depth={} ===", y0, depth); eprintln!("=== DIAG s=0 y0={} depth={} ===", y0, depth);
eprintln!(" eval_enter={}", DIAG_EVAL_ENTER.load(Ordering::Relaxed)); eprintln!(" eval_enter={}", DIAG_EVAL_ENTER.load(Ordering::Relaxed));
eprintln!(" bsdf_empty={}", DIAG_BSDF_EMPTY.load(Ordering::Relaxed)); eprintln!(" bsdf_empty={}", DIAG_BSDF_EMPTY.load(Ordering::Relaxed));
eprintln!(" non_specular_skip={}", DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed)); eprintln!(
eprintln!(" sample_light_none={}", DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed)); " non_specular_skip={}",
eprintln!(" sample_li_none={}", DIAG_SAMPLE_LI_NONE.load(Ordering::Relaxed)); DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed)
);
eprintln!(
" sample_light_none={}",
DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed)
);
eprintln!(
" sample_li_none={}",
DIAG_SAMPLE_LI_NONE.load(Ordering::Relaxed)
);
eprintln!(" ls_l_black={}", DIAG_LS_L_BLACK.load(Ordering::Relaxed)); eprintln!(" ls_l_black={}", DIAG_LS_L_BLACK.load(Ordering::Relaxed));
eprintln!(" ls_pdf_zero={}", DIAG_LS_PDF_ZERO.load(Ordering::Relaxed)); eprintln!(" ls_pdf_zero={}", DIAG_LS_PDF_ZERO.load(Ordering::Relaxed));
eprintln!(" f_none={}", DIAG_F_NONE.load(Ordering::Relaxed)); eprintln!(" f_none={}", DIAG_F_NONE.load(Ordering::Relaxed));
eprintln!(" f_black={}", DIAG_F_BLACK.load(Ordering::Relaxed)); eprintln!(" f_black={}", DIAG_F_BLACK.load(Ordering::Relaxed));
eprintln!(" shadow_push={}", DIAG_SHADOW_PUSH.load(Ordering::Relaxed)); eprintln!(" shadow_push={}", DIAG_SHADOW_PUSH.load(Ordering::Relaxed));
eprintln!(" shadow_unoccluded={}", super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed)); eprintln!(
" shadow_unoccluded={}",
super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed)
);
let img_n = DIAG_IMG_COUNT.load(Ordering::Relaxed); let img_n = DIAG_IMG_COUNT.load(Ordering::Relaxed);
if img_n > 0 { if img_n > 0 {
let scale = f32::from_bits(DIAG_IMG_SCALE_BITS.load(Ordering::Relaxed)); let scale = f32::from_bits(DIAG_IMG_SCALE_BITS.load(Ordering::Relaxed));
let pixel0 = f32::from_bits(DIAG_IMG_PIXEL0_BITS.load(Ordering::Relaxed)); let pixel0 =
f32::from_bits(DIAG_IMG_PIXEL0_BITS.load(Ordering::Relaxed));
let rgb0 = f32::from_bits(DIAG_IMG_RGB0_BITS.load(Ordering::Relaxed)); let rgb0 = f32::from_bits(DIAG_IMG_RGB0_BITS.load(Ordering::Relaxed));
let result0 = f32::from_bits(DIAG_IMG_RESULT0_BITS.load(Ordering::Relaxed)); let result0 =
eprintln!(" img_tex_calls={} scale={:.6} pixel0={:.6} rgb0_pre_scale={:.6} result[0]={:.6}", f32::from_bits(DIAG_IMG_RESULT0_BITS.load(Ordering::Relaxed));
img_n, scale, pixel0, rgb0, result0); eprintln!(
" img_tex_calls={} scale={:.6} pixel0={:.6} rgb0_pre_scale={:.6} result[0]={:.6}",
img_n, scale, pixel0, rgb0, result0
);
} }
} }
} }
@ -263,15 +279,27 @@ impl CpuWavefrontRenderer {
eprintln!("=== NEE DIAG COUNTS ==="); eprintln!("=== NEE DIAG COUNTS ===");
eprintln!("eval_enter={}", DIAG_EVAL_ENTER.load(Ordering::Relaxed)); eprintln!("eval_enter={}", DIAG_EVAL_ENTER.load(Ordering::Relaxed));
eprintln!("bsdf_empty={}", DIAG_BSDF_EMPTY.load(Ordering::Relaxed)); eprintln!("bsdf_empty={}", DIAG_BSDF_EMPTY.load(Ordering::Relaxed));
eprintln!("non_specular_skip={}", DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed)); eprintln!(
eprintln!("sample_light_none={}", DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed)); "non_specular_skip={}",
eprintln!("sample_li_none={}", DIAG_SAMPLE_LI_NONE.load(Ordering::Relaxed)); DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed)
);
eprintln!(
"sample_light_none={}",
DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed)
);
eprintln!(
"sample_li_none={}",
DIAG_SAMPLE_LI_NONE.load(Ordering::Relaxed)
);
eprintln!("ls_l_black={}", DIAG_LS_L_BLACK.load(Ordering::Relaxed)); eprintln!("ls_l_black={}", DIAG_LS_L_BLACK.load(Ordering::Relaxed));
eprintln!("ls_pdf_zero={}", DIAG_LS_PDF_ZERO.load(Ordering::Relaxed)); eprintln!("ls_pdf_zero={}", DIAG_LS_PDF_ZERO.load(Ordering::Relaxed));
eprintln!("f_none={}", DIAG_F_NONE.load(Ordering::Relaxed)); eprintln!("f_none={}", DIAG_F_NONE.load(Ordering::Relaxed));
eprintln!("f_black={}", DIAG_F_BLACK.load(Ordering::Relaxed)); eprintln!("f_black={}", DIAG_F_BLACK.load(Ordering::Relaxed));
eprintln!("shadow_push={}", DIAG_SHADOW_PUSH.load(Ordering::Relaxed)); eprintln!("shadow_push={}", DIAG_SHADOW_PUSH.load(Ordering::Relaxed));
eprintln!("shadow_unoccluded={}", super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed)); eprintln!(
"shadow_unoccluded={}",
super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed)
);
} }
fn generate_camera_rays( fn generate_camera_rays(
@ -464,11 +492,19 @@ impl CpuWavefrontRenderer {
dpdu={:?} dpdv={:?} \ dpdu={:?} dpdv={:?} \
dpdus={:?} dpdvs={:?} \ dpdus={:?} dpdvs={:?} \
uv={:?} material={:?} area_light={:?} face_index={}", uv={:?} material={:?} area_light={:?} face_index={}",
w.pixel_index, w.depth, w.pixel_index,
w.p, w.n, w.ns, w.depth,
w.dpdu, w.dpdv, w.p,
w.dpdus, w.dpdvs, w.n,
w.uv, w.material, w.area_light, w.face_index, w.ns,
w.dpdu,
w.dpdv,
w.dpdus,
w.dpdvs,
w.uv,
w.material,
w.area_light,
w.face_index,
); );
} }
DIAG_EVAL_ENTER.fetch_add(1, Ordering::Relaxed); DIAG_EVAL_ENTER.fetch_add(1, Ordering::Relaxed);
@ -500,12 +536,12 @@ impl CpuWavefrontRenderer {
dpdus: w.dpdus, dpdus: w.dpdus,
}; };
let lambda = w.lambda; let mut lambda = w.lambda;
let mut bsdf = if use_universal { let mut bsdf = if use_universal {
material.get_bsdf(&UniversalTextureEvaluator, &ctx, &lambda) material.get_bsdf(&UniversalTextureEvaluator, &ctx, &mut lambda)
} else { } else {
material.get_bsdf(&BasicTextureEvaluator, &ctx, &lambda) material.get_bsdf(&BasicTextureEvaluator, &ctx, &mut lambda)
}; };
if lambda.secondary_terminated() { if lambda.secondary_terminated() {
@ -658,8 +694,16 @@ impl CpuWavefrontRenderer {
"NEE_D0[{n}] pixel={:?} ls.l={:?} ls.pdf={:.6} f={:?} \ "NEE_D0[{n}] pixel={:?} ls.l={:?} ls.pdf={:.6} f={:?} \
beta={:?} light_pdf={:.6} bsdf_pdf={:.6} \ beta={:?} light_pdf={:.6} bsdf_pdf={:.6} \
r_u={:?} r_l={:?} l_d={:?}", r_u={:?} r_l={:?} l_d={:?}",
w.pixel_index, ls.l, ls.pdf, f, beta, w.pixel_index,
light_pdf, bsdf_pdf, r_u, r_l, l_d ls.l,
ls.pdf,
f,
beta,
light_pdf,
bsdf_pdf,
r_u,
r_l,
l_d
); );
} }
} }