Refactor: handle MIS weight in lower-level functions

it is difficult to keep in mind when MIS weight is needed, better to
handle this logic in the lower-level functions.
This reduces code duplication in many places.
This commit is contained in:
Weizhen Huang
2024-03-07 02:01:04 +01:00
committed by Weizhen Huang
parent 418acfe8bb
commit 0c9ce4ba4f
8 changed files with 49 additions and 58 deletions

View File

@@ -107,13 +107,7 @@ ccl_device_inline void integrate_background(KernelGlobals kg,
}
/* Background MIS weights. */
float mis_weight = 1.0f;
/* Check if background light exists or if we should skip PDF. */
if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_MIS_SKIP) &&
kernel_data.background.use_mis)
{
mis_weight = light_sample_mis_weight_forward_background(kg, state, path_flag);
}
const float mis_weight = light_sample_mis_weight_forward_background(kg, state, path_flag);
guiding_record_background(kg, state, L, mis_weight);
L *= mis_weight;
@@ -174,10 +168,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
}
/* MIS weighting. */
float mis_weight = 1.0f;
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = light_sample_mis_weight_forward_distant(kg, state, path_flag, &ls);
}
const float mis_weight = light_sample_mis_weight_forward_distant(kg, state, path_flag, &ls);
/* Write to render buffer. */
guiding_record_background(kg, state, light_eval, mis_weight);

View File

@@ -110,9 +110,7 @@ ccl_device bool shadow_linking_shade_light(KernelGlobals kg,
}
/* MIS weighting. */
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
}
mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
bsdf_spectrum = light_eval * mis_weight *
INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
@@ -152,18 +150,7 @@ ccl_device bool shadow_linking_shade_surface_emission(KernelGlobals kg,
const Spectrum L = surface_shader_emission(emission_sd);
const bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(emission_sd->flag &
((emission_sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
# ifdef __HAIR__
if (has_mis && (emission_sd->type & PRIMITIVE_TRIANGLE))
# else
if (has_mis)
# endif
{
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, emission_sd);
}
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, emission_sd);
bsdf_spectrum = L * mis_weight * INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
light_group = object_lightgroup(kg, emission_sd->object);

View File

@@ -55,10 +55,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
}
/* MIS weighting. */
float mis_weight = 1.0f;
if (!(path_flag & PATH_RAY_MIS_SKIP)) {
mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray_P);
}
const float mis_weight = light_sample_mis_weight_forward_lamp(kg, state, path_flag, &ls, ray_P);
/* Write to render buffer. */
guiding_record_surface_emission(kg, state, light_eval, mis_weight);

View File

@@ -138,19 +138,8 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
/* Evaluate emissive closure. */
Spectrum L = surface_shader_emission(sd);
float mis_weight = 1.0f;
const bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(sd->flag & ((sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
#ifdef __HAIR__
if (has_mis && (sd->type & PRIMITIVE_TRIANGLE))
#else
if (has_mis)
#endif
{
mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, sd);
}
const float mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, sd);
guiding_record_surface_emission(kg, state, L, mis_weight);
film_write_surface_emission(
@@ -338,12 +327,8 @@ ccl_device
/* Evaluate BSDF. */
const float bsdf_pdf = surface_shader_bsdf_eval(kg, state, sd, ls.D, &bsdf_eval, ls.shader);
bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf);
if (ls.shader & SHADER_USE_MIS) {
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf);
bsdf_eval_mul(&bsdf_eval, mis_weight);
}
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf);
bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf * mis_weight);
/* Path termination. */
const float terminate = path_state_rng_light_termination(kg, rng_state);

View File

@@ -798,14 +798,9 @@ ccl_device_forceinline void integrate_volume_direct_light(
/* Evaluate BSDF. */
BsdfEval phase_eval ccl_optional_struct_init;
float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls.D, &phase_eval);
if (ls.shader & SHADER_USE_MIS) {
float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf);
bsdf_eval_mul(&phase_eval, mis_weight);
}
bsdf_eval_mul(&phase_eval, light_eval / ls.pdf);
float phase_pdf = volume_shader_phase_eval(kg, state, sd, phases, ls.D, &phase_eval, ls.shader);
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, phase_pdf);
bsdf_eval_mul(&phase_eval, light_eval / ls.pdf * mis_weight);
/* Path termination. */
const float terminate = path_state_rng_light_termination(kg, rng_state);

View File

@@ -364,6 +364,12 @@ ccl_device_inline
float pdf = _surface_shader_bsdf_eval_mis(
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
/* If the light does not use MIS, then it is only sampled via NEE, so the probability of hitting
* the light using BSDF sampling is zero. */
if (!(light_shader_flags & SHADER_USE_MIS)) {
pdf = 0.0f;
}
#if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 4
if (pdf > 0.0f && state->guiding.use_surface_guiding) {
const float guiding_sampling_prob = state->guiding.surface_guiding_sampling_prob;

View File

@@ -249,7 +249,8 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
ccl_private const ShaderData *sd,
ccl_private const ShaderVolumePhases *phases,
const float3 wo,
ccl_private BsdfEval *phase_eval)
ccl_private BsdfEval *phase_eval,
const uint light_shader_flags)
{
bsdf_eval_init(phase_eval, zero_spectrum());
@@ -263,6 +264,12 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
}
# endif
/* If the light does not use MIS, then it is only sampled via NEE, so the probability of hitting
* the light using BSDF sampling is zero. */
if (!(light_shader_flags & SHADER_USE_MIS)) {
pdf = 0.0f;
}
return pdf;
}

View File

@@ -300,7 +300,10 @@ ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg,
{
#ifdef WITH_CYCLES_DEBUG
if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) {
return 0.0f;
/* Return 0.0f to only account for the contribution in forward path tracing, unless when the
* light can not be forward sampled, in which case return 1.0f so it converges to the same
* result. */
return (forward_pdf == 0.0f);
}
else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) {
return 1.0f;
@@ -420,6 +423,17 @@ ccl_device_inline float light_sample_mis_weight_forward_surface(KernelGlobals kg
const uint32_t path_flag,
const ccl_private ShaderData *sd)
{
bool has_mis = !(path_flag & PATH_RAY_MIS_SKIP) &&
(sd->flag & ((sd->flag & SD_BACKFACING) ? SD_MIS_BACK : SD_MIS_FRONT));
#ifdef __HAIR__
has_mis &= (sd->type & PRIMITIVE_TRIANGLE);
#endif
if (!has_mis) {
return 1.0f;
}
const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
const float t = sd->ray_length;
float pdf = triangle_light_pdf(kg, sd, t);
@@ -453,6 +467,10 @@ ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg,
const ccl_private LightSample *ls,
const float3 P)
{
if (path_flag & PATH_RAY_MIS_SKIP) {
return 1.0f;
}
const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
float pdf = ls->pdf;
@@ -492,6 +510,11 @@ ccl_device_inline float light_sample_mis_weight_forward_background(KernelGlobals
IntegratorState state,
const uint32_t path_flag)
{
/* Check if background light exists or if we should skip PDF. */
if (!kernel_data.background.use_mis || (path_flag & PATH_RAY_MIS_SKIP)) {
return 1.0f;
}
const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);