Compare commits

..

No commits in common. "7c35f9b1805dcf8862757fb99caf995cc3cde344" and "1b8ca71b0ebba1d7a57736ccc2a90e6a9ce14f77" have entirely different histories.

42 changed files with 557 additions and 910 deletions

View file

@ -76,17 +76,3 @@ 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,8 +4,9 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.100"
bitflags = "2.10.0" bitflags = "2.10.0"
half = { version = "2.7.1", default-features = false } half = "2.7.1"
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::{
Normal3f, Point2f, Vector3f, VectorLike, abs_cos_theta, cos_theta, same_hemisphere, abs_cos_theta, cos_theta, same_hemisphere, Normal3f, Point2f, Vector3f, VectorLike,
}; };
use crate::core::scattering::{ use crate::core::scattering::{
TrowbridgeReitzDistribution, fr_complex_from_spectrum, fr_dielectric, reflect, refract, fr_complex_from_spectrum, fr_dielectric, reflect, refract, TrowbridgeReitzDistribution,
}; };
use crate::spectra::SampledSpectrum; use crate::spectra::SampledSpectrum;
use crate::utils::math::square; use crate::utils::math::square;
@ -362,6 +362,7 @@ impl BxDFTrait for ThinDielectricBxDF {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
fn regularize(&mut self) {
fn regularize(&mut self) {} todo!()
}
} }

View file

@ -73,118 +73,4 @@ 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,7 +146,6 @@ 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 crate::utils::error::{Error, Result}; use anyhow::{Result, bail};
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)),
_ => Err(Error::UnknownColorEncoding), _ => bail!("Unknown color encoding: {}", name),
} }
} }
} }

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 crate::utils::error::{Error, Result}; use anyhow::{bail, 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),
_ => Err(Error::UnknownWrapMode), _ => bail!("{:?}: wrap mode unknown", name),
} }
} }
} }
@ -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),
_ => Err(Error::UnknownFilterFunction), _ => bail!("Filter function unknown"),
} }
} }
} }

View file

@ -2,7 +2,6 @@ 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,
}; };
@ -14,12 +13,15 @@ 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::{FloatTexture, SpectrumTexture, TextureEvalContext, TextureEvaluator}; use crate::core::texture::{
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)]
@ -160,7 +162,7 @@ pub trait MaterialTrait {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &mut SampledWavelengths, lambda: &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::{
BinaryPermuteScrambler, DigitPermutation, FastOwenScrambler, NoRandomizer, OwenScrambler, clamp, encode_morton_2, inverse_radical_inverse, lerp, log2_int,
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, scrambled_radical_inverse, sobol_interval_to_index, sobol_sample, BinaryPermuteScrambler,
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, Ptr, gvec}; use crate::{gvec, GVec, Ptr};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
#[repr(C)] #[repr(C)]
@ -530,18 +530,6 @@ 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,
@ -549,12 +537,10 @@ impl ZSobolSampler {
randomize: RandomizeStrategy, randomize: RandomizeStrategy,
seed: Option<u64>, seed: Option<u64>,
) -> Self { ) -> Self {
// pbrt calls the integer Log2Int overload; the float one disagrees for let log2_samples_per_pixel = log2_int(samples_per_pixel as Float) as u32;
// 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 = (res.max(1) as u32).ilog2() + log4_samples_per_pixel; let n_base4_digits = log2_int(res as Float) as u32 + log4_samples_per_pixel as u32;
Self { Self {
randomize, randomize,
seed: seed.unwrap_or(0), seed: seed.unwrap_or(0),
@ -604,7 +590,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 ^ scramble_seed(self.dim); let mix_input = higher_digits ^ (0x55555555 * self.dim as u64);
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;
@ -613,9 +599,8 @@ impl ZSobolSampler {
} }
if pow2_samples { if pow2_samples {
let digit = self.morton_index & 1; let lsb = self.morton_index & 1;
sample_index |= sample_index |= lsb;
digit ^ (mix_bits((self.morton_index >> 1) ^ scramble_seed(self.dim)) & 1);
} }
sample_index sample_index
@ -624,9 +609,8 @@ impl ZSobolSampler {
impl SamplerTrait for ZSobolSampler { impl SamplerTrait for ZSobolSampler {
fn samples_per_pixel(&self) -> i32 { fn samples_per_pixel(&self) -> i32 {
1 << self.log2_samples_per_pixel todo!()
} }
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)
@ -636,25 +620,31 @@ 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;
let hash = dim_seed_hash(self.dim, self.seed) as u32; if self.randomize == RandomizeStrategy::None {
// Always Sobol dimension 0 -- decorrelation comes from the hash. return sobol_sample(sample_index, self.dim, NoRandomizer);
}
match self.randomize { match self.randomize {
RandomizeStrategy::None => sobol_sample(sample_index, 0, NoRandomizer),
RandomizeStrategy::PermuteDigits => { RandomizeStrategy::PermuteDigits => {
sobol_sample(sample_index, 0, BinaryPermuteScrambler::new(hash)) sobol_sample(sample_index, self.dim, BinaryPermuteScrambler::new(hash))
} }
RandomizeStrategy::FastOwen => { RandomizeStrategy::FastOwen => {
sobol_sample(sample_index, 0, FastOwenScrambler::new(hash)) sobol_sample(sample_index, self.dim, FastOwenScrambler::new(hash))
} }
RandomizeStrategy::Owen => sobol_sample(sample_index, 0, OwenScrambler::new(hash)), RandomizeStrategy::Owen => {
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 = dim_seed_hash(self.dim, self.seed); let hash_input = [self.dim as u64, 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(
@ -685,92 +675,16 @@ impl SamplerTrait for ZSobolSampler {
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
struct PrimarySample { pub struct MLTSampler;
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 {
self.mutations_per_pixel todo!()
} }
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>) { todo!()
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 {
#[cfg(not(any(feature = "cuda", feature = "vulkan")))] todo!()
{
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: &mut SampledWavelengths, lambda: &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: &mut SampledWavelengths, lambda: &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,6 +234,7 @@ 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: &mut SampledWavelengths, _lambda: &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: &mut SampledWavelengths, _lambda: &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: &mut SampledWavelengths, _lambda: &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::Ptr;
use crate::utils::math::clamp; use crate::utils::math::clamp;
use crate::utils::Ptr;
#[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: &mut SampledWavelengths, lambda: &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,7 +1,5 @@
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;
@ -13,6 +11,7 @@ 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)]
@ -30,11 +29,11 @@ impl MaterialTrait for DielectricMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &mut SampledWavelengths, lambda: &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_inplace(); lambda.terminate_secondary();
} }
if sampled_eta == 0.0 { if sampled_eta == 0.0 {
@ -93,29 +92,18 @@ 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: &mut SampledWavelengths, _lambda: &SampledWavelengths,
) -> BSDF { ) -> BSDF {
let mut sampled_eta = self.eta.evaluate(lambda[0]); todo!()
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> {
None todo!()
} }
fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool { fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {

View file

@ -1,8 +1,5 @@
use crate::Float;
use crate::Ptr;
use crate::bxdfs::{ use crate::bxdfs::{
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF, HairBxDF,
DiffuseTransmissionBxDF, HairBxDF,
}; };
use crate::core::bsdf::BSDF; use crate::core::bsdf::BSDF;
use crate::core::bssrdf::BSSRDF; use crate::core::bssrdf::BSSRDF;
@ -14,6 +11,8 @@ 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)]
@ -28,7 +27,7 @@ impl MaterialTrait for DiffuseMaterial {
&self, &self,
tex_eval: &T, tex_eval: &T,
ctx: &MaterialEvalContext, ctx: &MaterialEvalContext,
lambda: &mut SampledWavelengths, lambda: &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.);
@ -42,7 +41,7 @@ impl MaterialTrait for DiffuseMaterial {
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
None todo!()
} }
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool { fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool {
@ -65,33 +64,21 @@ impl MaterialTrait for DiffuseMaterial {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct DiffuseTransmissionMaterial { pub struct DiffuseTransmissionMaterial {
pub normal_map: Ptr<Image>, pub image: Ptr<Image>,
pub displacement: Ptr<FloatTexture>, pub displacement: Ptr<FloatTexture>,
pub reflectance: Ptr<SpectrumTexture>, pub reflectance: Ptr<FloatTexture>,
pub transmittance: Ptr<SpectrumTexture>, pub transmittance: Ptr<FloatTexture>,
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: &mut SampledWavelengths, _lambda: &SampledWavelengths,
) -> BSDF { ) -> BSDF {
let r = SampledSpectrum::clamp( todo!()
&(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,
@ -99,15 +86,15 @@ impl MaterialTrait for DiffuseTransmissionMaterial {
_ctx: &MaterialEvalContext, _ctx: &MaterialEvalContext,
_lambda: &SampledWavelengths, _lambda: &SampledWavelengths,
) -> Option<BSSRDF> { ) -> Option<BSSRDF> {
None todo!()
} }
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.normal_map.get() self.image.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: &mut SampledWavelengths, lambda: &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,17 +7,14 @@ 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;
#[repr(C)] fn checkerboard(
#[derive(Debug, Copy, Clone)] ctx: &TextureEvalContext,
pub enum CheckerMap { map2d: Ptr<TextureMapping2D>,
D2(TextureMapping2D), map3d: Ptr<TextureMapping3D>,
D3(TextureMapping3D), ) -> Float {
}
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;
x / 2. + y * (1. - 2. * y.abs()) return x / 2. + y * (1. - 2. * y.abs());
}; };
let bf = |x: Float, r: Float| -> Float { let bf = |x: Float, r: Float| -> Float {
@ -27,53 +24,49 @@ fn checkerboard(ctx: &TextureEvalContext, checker_map: CheckerMap) -> Float {
(d(x + r) - 2. * d(x) + d(x - r)) / square(r) (d(x + r) - 2. * d(x) + d(x - r)) / square(r)
}; };
match checker_map { if !map2d.is_null() {
CheckerMap::D2(map) => { assert!(map3d.is_null());
let c = map.map(ctx); let c = map2d.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 {
CheckerMap::D3(map) => { assert!(!map3d.is_null());
let c = map.map(ctx); let c = map3d.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 map: CheckerMap, pub map2d: Ptr<TextureMapping2D>,
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.map); let w = checkerboard(&ctx, self.map2d, self.map3d);
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 {
&& let Some(tex) = self.tex[0].get() if let Some(tex) = self.tex[0].get() {
{
t0 = tex.evaluate(ctx); t0 = tex.evaluate(ctx);
} }
}
if w != 0.0 if w != 0.0 {
&& let Some(tex) = self.tex[1].get() if 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
} }
@ -82,34 +75,31 @@ impl FloatCheckerboardTexture {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumCheckerboardTexture { pub struct SpectrumCheckerboardTexture {
pub map: CheckerMap, pub map2d: Ptr<TextureMapping2D>,
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.map); let w = checkerboard(ctx, self.map2d, self.map3d);
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 {
&& let Some(tex) = self.tex[0].get() if 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 {
&& let Some(tex) = self.tex[1].get() if 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,6 +1,8 @@
use crate::Float; use crate::Float;
use crate::core::geometry::{Point2f, VectorLike}; use crate::core::geometry::{Point2f, VectorLike};
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvalContext, TextureMapping2D}; use crate::core::texture::{
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;
@ -20,30 +22,18 @@ fn inside_polka_dot(st: Point2f) -> bool {
return true; return true;
} }
} }
false return 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 inside_dot: Ptr<FloatTexture>,
pub outside_dot: Ptr<FloatTexture>, pub outside_dot: Ptr<FloatTexture>,
pub inside_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) {
@ -64,22 +54,11 @@ impl FloatDotsTexture {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct SpectrumDotsTexture { pub struct SpectrumDotsTexture {
pub mapping: TextureMapping2D, pub mapping: TextureMapping2D,
pub inside_dot: Ptr<SpectrumTexture>,
pub outside_dot: Ptr<SpectrumTexture>, pub outside_dot: Ptr<SpectrumTexture>,
pub inside_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,18 +5,11 @@ 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 octaves: u32,
pub omega: Float, pub omega: Float,
pub octaves: u32,
} }
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)

View file

@ -1,39 +0,0 @@
//! 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,7 +2,6 @@ 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,4 +1,3 @@
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;
@ -18,7 +17,6 @@ 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,
@ -35,7 +33,6 @@ 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,
@ -45,7 +42,7 @@ impl Default for BasicPBRTOptions {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Copy)]
pub struct PBRTOptions { pub struct PBRTOptions {
pub basic: BasicPBRTOptions, pub basic: BasicPBRTOptions,
@ -55,8 +52,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<String>, pub mse_reference_image: Option<&'static str>,
pub mse_reference_output: Option<String>, pub mse_reference_output: Option<&'static str>,
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 crate::utils::error::{Error, Result}; use anyhow::{bail, Context, Result};
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -2125,7 +2125,15 @@ 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. {
return Err(Error::DegenerateLookAt); bail!(
"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);
@ -2142,6 +2150,8 @@ 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.inverse().ok_or(Error::SingularMatrix)?; let camera_from_world = world_from_camera
.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,5 +1,4 @@
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;
@ -11,12 +10,13 @@ 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: &mut SampledWavelengths, lambda: &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: &mut SampledWavelengths, lambda: &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: &mut SampledWavelengths, _lambda: &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: &mut SampledWavelengths, _lambda: &SampledWavelengths,
_camera: &Camera, _camera: &Camera,
_sampler: &mut Sampler, _sampler: &mut Sampler,
_materials: &[Material], _materials: &[Material],

View file

@ -1,17 +1,18 @@
use super::BasicScene;
use super::entities::*; use super::entities::*;
use crate::Arena; use super::BasicScene;
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::{AtLoc, ParserError, ParserTarget}; use crate::utils::parser::{ParserError, ParserTarget};
use shared::Float; use crate::Arena;
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::{PBRTOptions, RenderingCoordinateSystem}; use shared::utils::options::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;
@ -23,16 +24,6 @@ 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],
@ -134,11 +125,6 @@ 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>,
@ -191,7 +177,6 @@ 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(),
@ -226,12 +211,6 @@ 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,
@ -275,6 +254,12 @@ 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)?;
@ -344,7 +329,8 @@ 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)).at(&loc)?; let t = transform::look_at((ex, ey, ez), (lx, ly, lz), (ux, uy, uz))
.with_context(|| format!("at {}", loc))?;
self.for_active_transforms(|cur| cur * &t); self.for_active_transforms(|cur| cur * &t);
Ok(()) Ok(())
} }
@ -461,65 +447,8 @@ 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> {
let bad = |what: &str| { todo!()
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(
@ -605,8 +534,7 @@ 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 {
@ -774,8 +702,7 @@ 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(
@ -835,8 +762,7 @@ 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,
@ -868,8 +794,7 @@ 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).
@ -902,8 +827,7 @@ 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();
@ -950,8 +874,7 @@ 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,16 +1,15 @@
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::{Result, anyhow}; use anyhow::{anyhow, Result};
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, PointTransformMapping, SphericalMapping, CylindricalMapping, PlanarMapping, SphericalMapping, TextureEvalContext, TextureMapping2D,
TextureEvalContext, TextureMapping2D, TextureMapping3D, UVMapping, UVMapping,
}; };
use shared::spectra::{SampledSpectrum, SampledWavelengths}; use shared::spectra::{SampledSpectrum, SampledWavelengths};
use shared::textures::{ use shared::textures::{
@ -19,10 +18,22 @@ 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),
@ -38,12 +49,19 @@ 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,
@ -83,6 +101,7 @@ 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),
@ -101,7 +120,6 @@ pub trait CreateSpectrumTexture {
parameters: TextureParameterDictionary, parameters: TextureParameterDictionary,
spectrum_type: SpectrumType, spectrum_type: SpectrumType,
loc: FileLoc, loc: FileLoc,
arena: &Arena,
) -> Result<SpectrumTexture>; ) -> Result<SpectrumTexture>;
} }
@ -112,29 +130,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, arena) SpectrumConstantTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"scale" => { "scale" => {
SpectrumScaledTexture::create(render_from_texture, params, spectrum_type, loc, arena) SpectrumScaledTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"mix" => SpectrumMixTexture::create(render_from_texture, params, spectrum_type, loc, arena), "mix" => SpectrumMixTexture::create(render_from_texture, params, spectrum_type, loc),
"directionmix" => { "directionmix" => {
SpectrumDirectionMixTexture::create(render_from_texture, params, spectrum_type, loc, arena) SpectrumDirectionMixTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"bilerp" => { "bilerp" => {
SpectrumBilerpTexture::create(render_from_texture, params, spectrum_type, loc, arena) SpectrumBilerpTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"imagemap" => { "imagemap" => {
SpectrumImageTexture::create(render_from_texture, params, spectrum_type, loc, arena) SpectrumImageTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"checkerboard" => { "checkerboard" => {
SpectrumCheckerboardTexture::create(render_from_texture, params, spectrum_type, loc, arena) SpectrumCheckerboardTexture::create(render_from_texture, params, spectrum_type, loc)
} }
"dots" => SpectrumDotsTexture::create(render_from_texture, params, spectrum_type, loc, arena), "dots" => SpectrumDotsTexture::create(render_from_texture, params, spectrum_type, loc),
_ => Err(anyhow!( _ => Err(anyhow!(
"Spectrum texture type '{}' unknown at {}", "Spectrum texture type '{}' unknown at {}",
name, name,
@ -144,6 +162,12 @@ 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,
@ -197,21 +221,6 @@ 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: &mut SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
visible_surface: bool, visible_surface: bool,
arena: &Arena, arena: &Arena,
@ -69,8 +69,7 @@ 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 = let integrator = PathIntegrator::new(aggregate, lights, camera, light_sampler, config, materials);
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 crate::Arena; use super::RayIntegratorTrait;
use crate::core::interaction::InteractionGetter; use crate::core::interaction::InteractionGetter;
use shared::core::bsdf::{BSDF, BSDFSample}; use crate::Arena;
use shared::core::bsdf::{BSDFSample, BSDF};
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,6 +72,7 @@ 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>,
@ -207,7 +208,7 @@ impl RayIntegratorTrait for PathIntegrator {
fn li( fn li(
&self, &self,
mut ray: Ray, mut ray: Ray,
lambda: &mut SampledWavelengths, lambda: &SampledWavelengths,
sampler: &mut Sampler, sampler: &mut Sampler,
want_visible: bool, want_visible: bool,
_arena: &Arena, _arena: &Arena,
@ -246,9 +247,7 @@ impl RayIntegratorTrait for PathIntegrator {
} }
// Get BSDF // Get BSDF
let Some(mut bsdf) = let Some(mut bsdf) = isect.get_bsdf(&ray, lambda, &self.camera, sampler, &self.materials) else {
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::RayIntegratorTrait;
use super::base::IntegratorBase; use super::base::IntegratorBase;
use super::RayIntegratorTrait;
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 mut lambda = camera.get_film().sample_wavelengths(lu); let 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,
&mut lambda, &lambda,
sampler, sampler,
initialize_visible_surface, initialize_visible_surface,
arena, arena,

View file

@ -1,61 +1,51 @@
use crate::Arena; use crate::Arena;
use crate::core::texture::{ use crate::core::texture::{
CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture, SpectrumTexture, CreateFloatTexture, CreateSpectrumTexture, FloatTextureTrait, SpectrumTexture,
SpectrumTextureTrait,
}; };
use crate::utils::{FileLoc, TextureParameterDictionary};
use anyhow::Result; use anyhow::Result;
use shared::core::spectrum::Spectrum; use shared::core::texture::{SpectrumType, TextureEvalContext};
use shared::core::texture::{SpectrumType, TextureMapping2D}; use shared::{
use shared::spectra::ConstantSpectrum; spectra::{SampledSpectrum, SampledWavelengths},
use shared::textures::{FloatBilerpTexture, SpectrumBilerpTexture}; textures::{FloatBilerpTexture, SpectrumBilerpTexture},
use shared::utils::Transform; 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> {
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?; todo!()
}
}
let tex = FloatBilerpTexture::new( impl FloatTextureTrait for FloatBilerpTexture {
map, fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float {
parameters.get_one_float("v00", 0.)?, todo!()
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> {
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?; todo!()
let zero = Spectrum::Constant(ConstantSpectrum::new(0.)); }
let one = Spectrum::Constant(ConstantSpectrum::new(1.)); }
let get = |name: &str, def: Spectrum| { impl SpectrumTextureTrait for SpectrumBilerpTexture {
let s = parameters fn evaluate(&self, _ctx: &TextureEvalContext, _lambda: &SampledWavelengths) -> SampledSpectrum {
.get_one_spectrum(name, Some(def), spectrum_type) todo!()
.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,79 +1,53 @@
use crate::Arena; use crate::Arena;
use anyhow::{Result, bail}; use anyhow::Result;
use shared::{ use shared::{
core::spectrum::Spectrum, core::texture::SpectrumType,
core::texture::{SpectrumType, TextureMapping2D, TextureMapping3D}, textures::{FloatCheckerboardTexture, SpectrumCheckerboardTexture},
spectra::ConstantSpectrum,
textures::{CheckerMap, FloatCheckerboardTexture, SpectrumCheckerboardTexture},
utils::Transform, utils::Transform,
}; };
use crate::{ use crate::{
core::texture::{ core::texture::{
CreateFloatTexture, CreateSpectrumTexture, CreateTextureMapping, FloatTexture, CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait,
SpectrumTexture, SpectrumTexture, SpectrumTextureTrait,
}, },
utils::{ArenaUpload, FileLoc, TextureParameterDictionary}, utils::{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> {
let tex1 = arena.upload(parameters.get_float_texture("tex1", 1.)?); todo!()
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]);
Ok(FloatTexture::Checkerboard(tex)) impl FloatTextureTrait for FloatCheckerboardTexture {
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> {
let zero = Spectrum::Constant(ConstantSpectrum::new(0.)); todo!()
let one = Spectrum::Constant(ConstantSpectrum::new(1.)); }
let tex = |name: &str, def: Spectrum| { }
arena.upload(
parameters impl SpectrumTextureTrait for SpectrumCheckerboardTexture {
.get_spectrum_texture(name, Some(def), spectrum_type) fn evaluate(
.expect("default supplied"), &self,
) _ctx: &shared::core::texture::TextureEvalContext,
}; _lambda: &shared::spectra::SampledWavelengths,
) -> shared::spectra::SampledSpectrum {
let tex1 = tex("tex1", one); todo!()
let tex2 = tex("tex2", zero);
let map = checker_map(render_from_texture, parameters, loc)?;
let tex = SpectrumCheckerboardTexture::new(map, [tex1, tex2]);
Ok(SpectrumTexture::Checkerboard(tex))
} }
} }

View file

@ -1,46 +1,53 @@
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, core::texture::{SpectrumType, TextureEvalContext},
textures::{FloatConstantTexture, SpectrumConstantTexture}, textures::{FloatConstantTexture, SpectrumConstantTexture},
utils::Transform, utils::Transform,
}; };
use crate::{ use crate::{
core::texture::{ core::texture::{
CreateFloatTexture, CreateSpectrumTexture, FloatTexture, SpectrumTexture }, CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait,
utils::{FileLoc, TextureParameterDictionary} SpectrumTexture, SpectrumTextureTrait,
},
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> {
let value = parameters.get_one_float("value", 1.)?; todo!()
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> {
let one = Spectrum::Constant(ConstantSpectrum::new(1.)); todo!()
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,57 +1,53 @@
use crate::{Arena, ArenaUpload}; use crate::Arena;
use anyhow::Result; use anyhow::Result;
use shared::{ use shared::{
core::spectrum::Spectrum, core::texture::SpectrumType,
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, CreateTextureMapping, FloatTexture, CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait,
SpectrumTexture, SpectrumTexture, SpectrumTextureTrait,
}, },
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> {
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?; todo!()
let inside = parameters.get_float_texture("inside", 1.)?; }
let outside = parameters.get_float_texture("outside", 1.)?; }
let tex = FloatDotsTexture::new(map, arena.upload(inside), arena.upload(outside)); impl SpectrumTextureTrait for SpectrumDotsTexture {
fn evaluate(
Ok(FloatTexture::Dots(tex)) &self,
_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> {
let map = TextureMapping2D::create(&parameters, &render_from_texture, &loc)?; todo!()
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, TextureMapping3D}; use shared::core::texture::TextureEvalContext;
use shared::{textures::FBmTexture, utils::Transform}; use shared::{textures::FBmTexture, utils::Transform};
use crate::{ use crate::{
core::texture::{CreateFloatTexture, CreateTextureMapping, FloatTexture}, core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait},
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> {
let map = TextureMapping3D::create(&parameters, &render_from_texture, &loc)?; todo!()
let tex = FBmTexture::new( }
map, }
parameters.get_one_int("octaves", 5)?.try_into().unwrap(),
parameters.get_one_float("roughness", 0.5)?, impl FloatTextureTrait for FBmTexture {
); fn evaluate(&self, _ctx: &TextureEvalContext) -> shared::Float {
Ok(FloatTexture::FBm(tex)) todo!()
} }
} }

View file

@ -1,11 +1,12 @@
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, SpectrumTexture CreateFloatTexture, CreateSpectrumTexture, FloatTexture, FloatTextureTrait, 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::{Context, Result}; use anyhow::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;
@ -14,7 +15,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;
@ -27,7 +28,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 {
@ -44,7 +45,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();
@ -57,7 +58,7 @@ impl ImageTextureBase {
filename, filename,
scale, scale,
invert, invert,
mipmap: mipmap.clone() mipmap: mipmap.clone(),
}; };
} }
} }
@ -78,7 +79,7 @@ impl ImageTextureBase {
filename, filename,
scale, scale,
invert, invert,
mipmap: stored_mipmap.clone() mipmap: stored_mipmap.clone(),
} }
} }
} }
@ -96,7 +97,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 {
@ -123,18 +124,58 @@ 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)?;
@ -149,7 +190,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);
@ -171,7 +212,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 {
@ -193,7 +234,26 @@ 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
} }
} }
} }
@ -211,10 +271,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).with_context(|| format!("{:?}", filter))?; let ff = FilterFunction::parse(&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).with_context(|| format!("{:?}", wrap_string))?; let wrap_mode = WrapMode::parse(&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", "")?);
@ -227,8 +287,7 @@ 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 = let encoding = ColorEncoding::from_name(&encoding_str)?;
ColorEncoding::from_name(&encoding_str).with_context(|| format!("{:?}", encoding_str))?;
let tex = FloatImageTexture::new( let tex = FloatImageTexture::new(
mapping, mapping,

View file

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

View file

@ -1,5 +1,6 @@
use crate::core::texture::{ use crate::core::texture::{
CreateSpectrumTexture, FloatTexture, SpectrumTexture }; CreateSpectrumTexture, FloatTexture, FloatTextureTrait, SpectrumTexture, SpectrumTextureTrait,
};
use crate::utils::{FileLoc, TextureParameterDictionary}; use crate::utils::{FileLoc, TextureParameterDictionary};
use crate::Arena; use crate::Arena;
use anyhow::Result; use anyhow::Result;
@ -14,7 +15,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 {
@ -40,11 +41,26 @@ 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 {
@ -67,11 +83,17 @@ 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 {
@ -80,17 +102,22 @@ 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 {
@ -99,9 +126,13 @@ 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,7 +10,6 @@ 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,4 +1,5 @@
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;
@ -12,7 +13,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 {
@ -51,10 +52,20 @@ 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 {
@ -63,7 +74,6 @@ 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
@ -85,8 +95,17 @@ 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 }, core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait},
utils::{FileLoc, TextureParameterDictionary} utils::{FileLoc, TextureParameterDictionary},
}; };
impl CreateFloatTexture for WindyTexture { impl CreateFloatTexture for WindyTexture {
@ -18,3 +18,8 @@ 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 }, core::texture::{CreateFloatTexture, FloatTexture, FloatTextureTrait},
utils::{FileLoc, TextureParameterDictionary} utils::{FileLoc, TextureParameterDictionary},
}; };
impl CreateFloatTexture for WrinkledTexture { impl CreateFloatTexture for WrinkledTexture {
@ -18,3 +18,8 @@ impl CreateFloatTexture for WrinkledTexture {
} }
} }
impl FloatTextureTrait for WrinkledTexture {
fn evaluate(&self, _ctx: &shared::core::texture::TextureEvalContext) -> shared::Float {
todo!()
}
}

View file

@ -1,4 +1,3 @@
use thiserror::Error;
use anyhow::Result; use anyhow::Result;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use memmap2::Mmap; use memmap2::Mmap;
@ -248,39 +247,17 @@ impl Token {
} }
} }
#[derive(Debug, Error)] #[derive(Debug)]
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,12 +1,11 @@
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;
@ -19,23 +18,24 @@ 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::{CameraSample, Sampler, SamplerTrait, get_camera_sample}; use shared::core::sampler::{get_camera_sample, CameraSample, Sampler, SamplerTrait};
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, Ptr, SHADOW_EPSILON, gvec, gvec_from_slice}; use shared::{gvec, gvec_from_slice, GVec, Ptr, SHADOW_EPSILON};
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::Arc;
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
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,39 +232,23 @@ 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!( eprintln!(" non_specular_skip={}", DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed));
" non_specular_skip={}", eprintln!(" sample_light_none={}", DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed));
DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed) eprintln!(" sample_li_none={}", DIAG_SAMPLE_LI_NONE.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!( eprintln!(" shadow_unoccluded={}", super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed));
" 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 = let pixel0 = f32::from_bits(DIAG_IMG_PIXEL0_BITS.load(Ordering::Relaxed));
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 = let result0 = f32::from_bits(DIAG_IMG_RESULT0_BITS.load(Ordering::Relaxed));
f32::from_bits(DIAG_IMG_RESULT0_BITS.load(Ordering::Relaxed)); eprintln!(" img_tex_calls={} scale={:.6} pixel0={:.6} rgb0_pre_scale={:.6} result[0]={:.6}",
eprintln!( img_n, scale, pixel0, rgb0, result0);
" img_tex_calls={} scale={:.6} pixel0={:.6} rgb0_pre_scale={:.6} result[0]={:.6}",
img_n, scale, pixel0, rgb0, result0
);
} }
} }
} }
@ -279,27 +263,15 @@ 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!( eprintln!("non_specular_skip={}", DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed));
"non_specular_skip={}", eprintln!("sample_light_none={}", DIAG_SAMPLE_LIGHT_NONE.load(Ordering::Relaxed));
DIAG_NON_SPECULAR_SKIP.load(Ordering::Relaxed) eprintln!("sample_li_none={}", DIAG_SAMPLE_LI_NONE.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!( eprintln!("shadow_unoccluded={}", super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed));
"shadow_unoccluded={}",
super::aggregate::DIAG_SHADOW_UNOCCLUDED.load(Ordering::Relaxed)
);
} }
fn generate_camera_rays( fn generate_camera_rays(
@ -492,19 +464,11 @@ 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.pixel_index, w.depth,
w.depth, w.p, w.n, w.ns,
w.p, w.dpdu, w.dpdv,
w.n, w.dpdus, w.dpdvs,
w.ns, w.uv, w.material, w.area_light, w.face_index,
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);
@ -536,12 +500,12 @@ impl CpuWavefrontRenderer {
dpdus: w.dpdus, dpdus: w.dpdus,
}; };
let mut lambda = w.lambda; let lambda = w.lambda;
let mut bsdf = if use_universal { let mut bsdf = if use_universal {
material.get_bsdf(&UniversalTextureEvaluator, &ctx, &mut lambda) material.get_bsdf(&UniversalTextureEvaluator, &ctx, &lambda)
} else { } else {
material.get_bsdf(&BasicTextureEvaluator, &ctx, &mut lambda) material.get_bsdf(&BasicTextureEvaluator, &ctx, &lambda)
}; };
if lambda.secondary_terminated() { if lambda.secondary_terminated() {
@ -694,16 +658,8 @@ 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, w.pixel_index, ls.l, ls.pdf, f, beta,
ls.l, light_pdf, bsdf_pdf, r_u, r_l, l_d
ls.pdf,
f,
beta,
light_pdf,
bsdf_pdf,
r_u,
r_l,
l_d
); );
} }
} }