Fix: Cycles: reuse random number for sampling color channel in volume

The same random number was used for sampling color channel at each step,
which leads to bias. Fixed by rescaling the random number.

Another possibility would be to scramble `rng_offset` and use a new
random number each time, similar as in subsurface scattering, but
rescaling random number should be faster than computing a new one, and
is favorable here since the precision here is not very important

Pull Request: https://projects.blender.org/blender/blender/pulls/127454
This commit is contained in:
Weizhen Huang
2024-09-12 14:27:56 +02:00
committed by Weizhen Huang
parent 2ca5a65add
commit ee2fe7fa6c
4 changed files with 9 additions and 6 deletions

View File

@@ -153,7 +153,7 @@ ccl_device float volume_channel_get(Spectrum value, int channel)
ccl_device int volume_sample_channel(Spectrum albedo,
Spectrum throughput,
float rand,
ccl_private float *rand,
ccl_private Spectrum *pdf)
{
/* Sample color channel proportional to throughput and single scattering
@@ -173,10 +173,13 @@ ccl_device int volume_sample_channel(Spectrum albedo,
float pdf_sum = 0.0f;
FOREACH_SPECTRUM_CHANNEL (i) {
pdf_sum += GET_SPECTRUM_CHANNEL(*pdf, i);
if (rand < pdf_sum) {
const float channel_pdf = GET_SPECTRUM_CHANNEL(*pdf, i);
if (*rand < pdf_sum + channel_pdf) {
/* Rescale to reuse. */
*rand = (*rand - pdf_sum) / channel_pdf;
return i;
}
pdf_sum += channel_pdf;
}
return SPECTRUM_CHANNELS - 1;
}

View File

@@ -436,7 +436,7 @@ ccl_device_forceinline void volume_integrate_step_scattering(
const Spectrum albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t);
Spectrum channel_pdf;
const int channel = volume_sample_channel(
albedo, result.indirect_throughput, vstate.rchannel, &channel_pdf);
albedo, result.indirect_throughput, &vstate.rchannel, &channel_pdf);
/* Equiangular sampling for direct lighting. */
if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {

View File

@@ -269,7 +269,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
/* Sample color channel, use MIS with balance heuristic. */
float rchannel = path_state_rng_1D(kg, &rng_state, PRNG_SUBSURFACE_COLOR_CHANNEL);
Spectrum channel_pdf;
int channel = volume_sample_channel(alpha, throughput, rchannel, &channel_pdf);
int channel = volume_sample_channel(alpha, throughput, &rchannel, &channel_pdf);
float sample_sigma_t = volume_channel_get(sigma_t, channel);
float randt = path_state_rng_1D(kg, &rng_state, PRNG_SUBSURFACE_SCATTER_DISTANCE);