From 6f79527a3c2492a08b2a97a6f2a026a17186cd93 Mon Sep 17 00:00:00 2001 From: AuroraRyan0301 Date: Tue, 8 Sep 2026 22:53:01 -0500 Subject: [PATCH 1/2] gridvolume: fix the spectral majorant In spectral variants gridvolume::max() returned the largest of (c0, c1, c2, scale), and c0, c1, c2 are not densities. It now takes the scale alone. --- src/volumes/grid.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/volumes/grid.cpp b/src/volumes/grid.cpp index 98b1869d0..dc512469d 100644 --- a/src/volumes/grid.cpp +++ b/src/volumes/grid.cpp @@ -314,8 +314,19 @@ class GridVolume final : public Volume { m_texture.update_inplace(); - if (!m_fixed_max) - m_max = (float) dr::max_nested(dr::detach(m_texture.value())); + if (!m_fixed_max) { + if (is_spectral_v && m_texture.channel_count() == 4 && !m_raw) { + // Spectral upsampling stores (c0, c1, c2, scale) per voxel. + // The model spectrum is bounded by 1, so the scale channel + // bounds the volume; the coefficients do not. + using Array = typename TensorXf::Array; + const Array &data = m_texture.tensor().array(); + auto idx = dr::arange>(data.size() / 4) * 4 + 3; + m_max = (float) dr::max_nested(dr::gather(dr::detach(data), idx)); + } else { + m_max = (float) dr::max_nested(dr::detach(m_texture.value())); + } + } } } From 36a8b7873396e566bbdc64631636e452ce7e4364 Mon Sep 17 00:00:00 2001 From: AuroraRyan0301 Date: Tue, 8 Sep 2026 22:53:02 -0500 Subject: [PATCH 2/2] medium: clamp the optical depth in transmittance_eval_pdf() exp(-majorant * t) underflows to zero once majorant * t passes about 87. prbvolpath and prbvolpath_sm then get 0/0 in the free flight weight tr / pdf and drop the path. The optical depth is clamped to 80 before the exponential to avoid that. --- src/render/medium.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/render/medium.cpp b/src/render/medium.cpp index 9987ba978..cda1b1937 100644 --- a/src/render/medium.cpp +++ b/src/render/medium.cpp @@ -89,8 +89,11 @@ Medium::transmittance_eval_pdf(const MediumInteraction3f &mi, Mask active) const { MI_MASKED_FUNCTION(ProfilerPhase::MediumEvaluate, active); - Float t = dr::minimum(mi.t, si.t) - mi.mint; - UnpolarizedSpectrum tr = dr::exp(-t * mi.combined_extinction); + Float t = dr::minimum(mi.t, si.t) - mi.mint; + // Clamp the optical depth: callers use the ratio tr / pdf, and on a long + // flight under a large majorant both would underflow to zero + UnpolarizedSpectrum tau = dr::minimum(t * mi.combined_extinction, 80.f); + UnpolarizedSpectrum tr = dr::exp(-tau); UnpolarizedSpectrum pdf = dr::select(si.t < mi.t, tr, tr * mi.combined_extinction); return { tr, pdf }; }