diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index 5604d8e5163..2af4c9a5e7a 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -74,7 +74,8 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg, make_float3(0.0f, 0.0f, 0.0f); if(sd->flag & SD_SCATTER) { - if(state->volume_bounce < kernel_data.integrator.max_volume_bounce) { + if(state->bounce < kernel_data.integrator.max_bounce && + state->volume_bounce < kernel_data.integrator.max_volume_bounce) { for(int i = 0; i < sd->num_closure; i++) { const ShaderClosure *sc = &sd->closure[i]; @@ -340,6 +341,34 @@ ccl_device float3 kernel_volume_emission_integrate(VolumeShaderCoefficients *coe /* Volume Path */ +ccl_device int kernel_volume_sample_channel(float3 albedo, float3 throughput, float rand, float3 *pdf) +{ + /* Sample color channel proportional to throughput and single scattering + * albedo, to significantly reduce noise with many bounce, following: + * + * "Practical and Controllable Subsurface Scattering for Production Path + * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */ + float3 weights = fabs(throughput * albedo); + float sum_weights = weights.x + weights.y + weights.z; + + if(sum_weights > 0.0f) { + *pdf = weights/sum_weights; + } + else { + *pdf = make_float3(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f); + } + + if(rand < pdf->x) { + return 0; + } + else if(rand < pdf->x + pdf->y) { + return 1; + } + else { + return 2; + } +} + /* homogeneous volume: assume shader evaluation at the start gives * the volume shading coefficient for the entire line segment */ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( @@ -363,20 +392,18 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( #ifdef __VOLUME_SCATTER__ /* randomly scatter, and if we do t is shortened */ if(closure_flag & SD_SCATTER) { - /* extinction coefficient */ - float3 sigma_t = coeff.sigma_t; - - /* pick random color channel, we use the Veach one-sample - * model with balance heuristic for the channels */ + /* Sample channel, use MIS with balance heuristic. */ float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); - int channel = (int)(rphase*3.0f); + float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t); + float3 channel_pdf; + int channel = kernel_volume_sample_channel(albedo, *throughput, rphase, &channel_pdf); /* decide if we will hit or miss */ bool scatter = true; float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); if(probalistic_scatter) { - float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel); + float sample_sigma_t = kernel_volume_channel_get(coeff.sigma_t, channel); float sample_transmittance = expf(-sample_sigma_t * t); if(1.0f - xi >= sample_transmittance) { @@ -397,19 +424,19 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( float sample_t; /* distance sampling */ - sample_t = kernel_volume_distance_sample(ray->t, sigma_t, channel, xi, &transmittance, &pdf); + sample_t = kernel_volume_distance_sample(ray->t, coeff.sigma_t, channel, xi, &transmittance, &pdf); /* modify pdf for hit/miss decision */ if(probalistic_scatter) - pdf *= make_float3(1.0f, 1.0f, 1.0f) - volume_color_transmittance(sigma_t, t); + pdf *= make_float3(1.0f, 1.0f, 1.0f) - volume_color_transmittance(coeff.sigma_t, t); - new_tp = *throughput * coeff.sigma_s * transmittance / average(pdf); + new_tp = *throughput * coeff.sigma_s * transmittance / dot(channel_pdf, pdf); t = sample_t; } else { /* no scattering */ - float3 transmittance = volume_color_transmittance(sigma_t, t); - float pdf = average(transmittance); + float3 transmittance = volume_color_transmittance(coeff.sigma_t, t); + float pdf = dot(channel_pdf, transmittance); new_tp = *throughput * transmittance / pdf; } } @@ -423,8 +450,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous( /* integrate emission attenuated by extinction */ if(L && (closure_flag & SD_EMISSION)) { - float3 sigma_t = coeff.sigma_t; - float3 transmittance = volume_color_transmittance(sigma_t, ray->t); + float3 transmittance = volume_color_transmittance(coeff.sigma_t, ray->t); float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, ray->t); path_radiance_accum_emission(L, state, *throughput, emission); } @@ -473,7 +499,6 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( * model with balance heuristic for the channels */ float xi = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); - int channel = (int)(rphase*3.0f); bool has_scatter = false; for(int i = 0; i < max_steps; i++) { @@ -500,32 +525,34 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( if((closure_flag & SD_SCATTER) || (has_scatter && (closure_flag & SD_EXTINCTION))) { has_scatter = true; - float3 sigma_t = coeff.sigma_t; - float3 sigma_s = coeff.sigma_s; + /* Sample channel, use MIS with balance heuristic. */ + float3 albedo = safe_divide_color(coeff.sigma_s, coeff.sigma_t); + float3 channel_pdf; + int channel = kernel_volume_sample_channel(albedo, tp, rphase, &channel_pdf); /* compute transmittance over full step */ - transmittance = volume_color_transmittance(sigma_t, dt); + transmittance = volume_color_transmittance(coeff.sigma_t, dt); /* decide if we will scatter or continue */ float sample_transmittance = kernel_volume_channel_get(transmittance, channel); if(1.0f - xi >= sample_transmittance) { /* compute sampling distance */ - float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel); + float sample_sigma_t = kernel_volume_channel_get(coeff.sigma_t, channel); float new_dt = -logf(1.0f - xi)/sample_sigma_t; new_t = t + new_dt; /* transmittance and pdf */ - float3 new_transmittance = volume_color_transmittance(sigma_t, new_dt); - float3 pdf = sigma_t * new_transmittance; + float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt); + float3 pdf = coeff.sigma_t * new_transmittance; /* throughput */ - new_tp = tp * sigma_s * new_transmittance / average(pdf); + new_tp = tp * coeff.sigma_s * new_transmittance / dot(channel_pdf, pdf); scatter = true; } else { /* throughput */ - float pdf = average(transmittance); + float pdf = dot(channel_pdf, transmittance); new_tp = tp * transmittance / pdf; /* remap xi so we can reuse it and keep thing stratified */ @@ -632,6 +659,7 @@ typedef struct VolumeSegment { float3 accum_emission; /* accumulated emission at end of segment */ float3 accum_transmittance; /* accumulated transmittance at end of segment */ + float3 accum_albedo; /* accumulated average albedo over segment */ int sampling_method; /* volume sampling method */ } VolumeSegment; @@ -698,6 +726,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta /* init accumulation variables */ float3 accum_emission = make_float3(0.0f, 0.0f, 0.0f); float3 accum_transmittance = make_float3(1.0f, 1.0f, 1.0f); + float3 accum_albedo = make_float3(0.0f, 0.0f, 0.0f); float3 cdf_distance = make_float3(0.0f, 0.0f, 0.0f); float t = 0.0f; @@ -724,6 +753,11 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta int closure_flag = sd->flag; float3 sigma_t = coeff.sigma_t; + /* compute average albedo for channel sampling */ + if(closure_flag & SD_SCATTER) { + accum_albedo += dt * safe_divide_color(coeff.sigma_s, sigma_t); + } + /* compute accumulated transmittance */ float3 transmittance = volume_color_transmittance(sigma_t, dt); @@ -783,6 +817,7 @@ ccl_device void kernel_volume_decoupled_record(KernelGlobals *kg, PathState *sta /* store total emission and transmittance */ segment->accum_emission = accum_emission; segment->accum_transmittance = accum_transmittance; + segment->accum_albedo = accum_albedo; /* normalize cumulative density function for distance sampling */ VolumeStep *last_step = segment->steps + segment->numsteps - 1; @@ -825,9 +860,13 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( { kernel_assert(segment->closure_flag & SD_SCATTER); - /* pick random color channel, we use the Veach one-sample - * model with balance heuristic for the channels */ - int channel = (int)(rphase*3.0f); + /* Sample color channel, use MIS with balance heuristic. */ + float3 channel_pdf; + int channel = kernel_volume_sample_channel(segment->accum_albedo, + *throughput, + rphase, + &channel_pdf); + float xi = rscatter; /* probabilistic scattering decision based on transmittance */ @@ -914,7 +953,7 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( if(probalistic_scatter) distance_pdf *= make_float3(1.0f, 1.0f, 1.0f) - segment->accum_transmittance; - pdf = average(distance_pdf * step_pdf_distance); + pdf = dot(channel_pdf, distance_pdf * step_pdf_distance); /* multiple importance sampling */ if(use_mis) { @@ -977,7 +1016,7 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( /* multiple importance sampling */ if(use_mis) { float3 distance_pdf3 = kernel_volume_distance_pdf(step_t, step->sigma_t, step_sample_t); - float distance_pdf = average(distance_pdf3 * step_pdf_distance); + float distance_pdf = dot(channel_pdf, distance_pdf3 * step_pdf_distance); mis_weight = 2.0f*power_heuristic(pdf, distance_pdf); } }