From 27fc091be8018369eaafc4e31141cef4e66307c2 Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Fri, 13 Dec 2024 10:27:53 +0100 Subject: [PATCH] Fix #131723: Cycles volume not sampling channels with zero extinction The original paper uses the single scattering albedo `sigma_s/sigma_t` to pick a channel for sampling the scattering distance. However, this only considers the situation where there is scattering inside the volume. If some channel has an extinction coefficient of zero, the light passes through without attenuation for that channel. We assign such channel with a weight of 1 instead of 0 to make sure it can be sampled. Pull Request: https://projects.blender.org/blender/blender/pulls/131741 --- intern/cycles/kernel/integrator/shade_volume.h | 9 ++++++--- intern/cycles/util/math.h | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 8b6c554034b..958f73046b8 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -486,9 +486,12 @@ ccl_device_forceinline void volume_integrate_step_scattering( ccl_private VolumeIntegrateState &ccl_restrict vstate, ccl_private VolumeIntegrateResult &ccl_restrict result) { - /* Pick random color channel, we use the Veach one-sample - * model with balance heuristic for the channels. */ - const Spectrum albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t); + /* Pick random color channel for sampling the scatter distance. We use the Veach one-sample model + * with balance heuristic for the channels. + * Set `albedo` to 1 for the channel where extinction coefficient `sigma_t` is zero, to make sure + * that we sample a distance outside the current segment when that channel is picked, meaning + * light passes through without attenuation. */ + const Spectrum albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t, 1.0f); Spectrum channel_pdf; const int channel = volume_sample_channel( albedo, result.indirect_throughput, &vstate.rchannel, &channel_pdf); diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h index cc7cf0fd619..68c74c1c610 100644 --- a/intern/cycles/util/math.h +++ b/intern/cycles/util/math.h @@ -634,12 +634,13 @@ ccl_device_inline Spectrum safe_invert_color(Spectrum a) return a; } -ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b) +/* Returns `a/b`, and replace the channel value with `fallback` if `b == 0`. */ +ccl_device_inline Spectrum safe_divide_color(Spectrum a, Spectrum b, const float fallback = 0.0f) { FOREACH_SPECTRUM_CHANNEL (i) { GET_SPECTRUM_CHANNEL(a, i) = (GET_SPECTRUM_CHANNEL(b, i) != 0.0f) ? GET_SPECTRUM_CHANNEL(a, i) / GET_SPECTRUM_CHANNEL(b, i) : - 0.0f; + fallback; } return a;