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:
committed by
Weizhen Huang
parent
418acfe8bb
commit
0c9ce4ba4f
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user