Fix T56925: Cycles banding artifacts in dense volumes

Offset the starting point of segments by a random amount to avoid the bounding
box shape affecting the result and creating artifacts.

Differential Revision: https://developer.blender.org/D10576
This commit is contained in:
Mikhail Matrosov 2021-03-15 15:17:46 +01:00 committed by Brecht Van Lommel
parent cd3fade2aa
commit fbe0165aad
1 changed files with 37 additions and 38 deletions

View File

@ -175,7 +175,8 @@ ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg,
const float object_step_size,
float t,
float *step_size,
float *step_offset)
float *step_shade_offset,
float *steps_offset)
{
const int max_steps = kernel_data.integrator.volume_max_steps;
float step = min(object_step_size, t);
@ -186,7 +187,14 @@ ccl_device_inline void kernel_volume_step_init(KernelGlobals *kg,
}
*step_size = step;
*step_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4) * step;
/* Perform shading at this offset within a step, to integrate over
* over the entire step segment. */
*step_shade_offset = path_state_rng_1D_hash(kg, state, 0x1e31d8a4);
/* Shift starting point of all segment by this random amount to avoid
* banding artifacts from the volume bounding shape. */
*steps_offset = path_state_rng_1D_hash(kg, state, 0x3d22c7b3);
}
/* Volume Shadows
@ -220,10 +228,15 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
float3 tp = *throughput;
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
/* prepare for stepping */
/* Prepare for stepping.
* For shadows we do not offset all segments, since the starting point is
* already a random distance inside the volume. It also appears to create
* banding artifacts for unknown reasons. */
int max_steps = kernel_data.integrator.volume_max_steps;
float step_offset, step_size;
kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
float step_size, step_shade_offset, unused;
kernel_volume_step_init(
kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &unused);
const float steps_offset = 1.0f;
/* compute extinction at the start */
float t = 0.0f;
@ -232,23 +245,17 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++) {
/* advance to new position */
float new_t = min(ray->t, (i + 1) * step_size);
float new_t = min(ray->t, (i + steps_offset) * step_size);
float dt = new_t - t;
/* use random position inside this segment to sample shader, adjust
* for last step that is shorter than other steps. */
if (new_t == ray->t) {
step_offset *= (new_t - t) / step_size;
}
float3 new_P = ray->P + ray->D * (t + step_offset);
float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
float3 sigma_t = zero_float3();
/* compute attenuation over segment */
if (volume_shader_extinction_sample(kg, sd, state, new_P, &sigma_t)) {
/* Compute expf() only for every Nth step, to save some calculations
* because exp(a)*exp(b) = exp(a+b), also do a quick tp_eps check then. */
sum += (-sigma_t * (new_t - t));
sum += (-sigma_t * dt);
if ((i & 0x07) == 0) { /* ToDo: Other interval? */
tp = *throughput * exp3(sum);
@ -567,10 +574,12 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
float3 tp = *throughput;
const float tp_eps = 1e-6f; /* todo: this is likely not the right value */
/* prepare for stepping */
/* Prepare for stepping.
* Using a different step offset for the first step avoids banding artifacts. */
int max_steps = kernel_data.integrator.volume_max_steps;
float step_offset, step_size;
kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
float step_size, step_shade_offset, steps_offset;
kernel_volume_step_init(
kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset);
/* compute coefficients at the start */
float t = 0.0f;
@ -584,16 +593,10 @@ kernel_volume_integrate_heterogeneous_distance(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++) {
/* advance to new position */
float new_t = min(ray->t, (i + 1) * step_size);
float new_t = min(ray->t, (i + steps_offset) * step_size);
float dt = new_t - t;
/* use random position inside this segment to sample shader,
* for last shorter step we remap it to fit within the segment. */
if (new_t == ray->t) {
step_offset *= (new_t - t) / step_size;
}
float3 new_P = ray->P + ray->D * (t + step_offset);
float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
@ -771,11 +774,12 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
/* prepare for volume stepping */
int max_steps;
float step_size, step_offset;
float step_size, step_shade_offset, steps_offset;
if (object_step_size != FLT_MAX) {
max_steps = kernel_data.integrator.volume_max_steps;
kernel_volume_step_init(kg, state, object_step_size, ray->t, &step_size, &step_offset);
kernel_volume_step_init(
kg, state, object_step_size, ray->t, &step_size, &step_shade_offset, &steps_offset);
# ifdef __KERNEL_CPU__
/* NOTE: For the branched path tracing it's possible to have direct
@ -802,7 +806,8 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
else {
max_steps = 1;
step_size = ray->t;
step_offset = 0.0f;
step_shade_offset = 0.0f;
steps_offset = 1.0f;
segment->steps = &segment->stack_step;
}
@ -821,16 +826,10 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
for (int i = 0; i < max_steps; i++, step++) {
/* advance to new position */
float new_t = min(ray->t, (i + 1) * step_size);
float new_t = min(ray->t, (i + steps_offset) * step_size);
float dt = new_t - t;
/* use random position inside this segment to sample shader,
* for last shorter step we remap it to fit within the segment. */
if (new_t == ray->t) {
step_offset *= (new_t - t) / step_size;
}
float3 new_P = ray->P + ray->D * (t + step_offset);
float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
VolumeShaderCoefficients coeff ccl_optional_struct_init;
/* compute segment */
@ -888,7 +887,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg,
step->accum_transmittance = accum_transmittance;
step->cdf_distance = cdf_distance;
step->t = new_t;
step->shade_t = t + step_offset;
step->shade_t = t + dt * step_shade_offset;
/* stop if at the end of the volume */
t = new_t;