@@ -76,6 +76,13 @@ struct SMicrofacetNormals<Config, BRDF, ndf::PNS_SCHUSSLER, 2 NBL_PARTIAL_REQ_BO
7676 return bxdf_type::anisocache_type::template createForReflection<anisotropic_interaction_type, sample_type>(interaction, _sample);
7777 }
7878
79+ static spectral_type __calculateQuotient (const spectral_type quo, const spectral_type quo_other, const scalar_type choiceProb, const scalar_type pdf, const scalar_type pdf_other)
80+ {
81+ const scalar_type weight = pdf / (pdf + pdf_other); // balance heuristic
82+ return (quo * weight / choiceProb) / (scalar_type (1.0 ) + pdf_other * (scalar_type (1.0 ) - choiceProb) / (pdf * choiceProb)) +
83+ (quo_other * (scalar_type (1.0 ) - weight)) / (pdf_other * (scalar_type (1.0 ) - choiceProb) + (pdf * choiceProb));
84+ }
85+
7986 value_weight_type evalAndWeight (NBL_CONST_REF_ARG (sample_type) _sample, NBL_CONST_REF_ARG (isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC
8087 {
8188 return evalAndWeight (_sample, anisotropic_interaction_type::create (interaction));
@@ -311,6 +318,9 @@ struct SMicrofacetNormals<Config, BRDF, ndf::PNS_SCHUSSLER, 2 NBL_PARTIAL_REQ_BO
311318 }
312319
313320 const vector3_type Nt = shadowing_method_type::computeNt (Np, shadingBasis);
321+ const scalar_type NpdotV = interaction.getNdotV ();
322+ const scalar_type NtdotV = hlsl::dot (Nt, V.getDirection ());
323+ const scalar_type lambda_p = shadowing_method_type::lambdaP (NdotNp, hlsl::max (scalar_type (0.0 ), NpdotV), hlsl::max (scalar_type (0.0 ), NtdotV));
314324 spectral_type quo = hlsl::promote<spectral_type>(1.0 );
315325
316326 if (_cache.sampleFromNt)
@@ -325,12 +335,14 @@ struct SMicrofacetNormals<Config, BRDF, ndf::PNS_SCHUSSLER, 2 NBL_PARTIAL_REQ_BO
325335 typename bxdf_type::anisotropic_interaction_type interaction_negreflected = bxdf_type::anisotropic_interaction_type::create (iso_negreflected);
326336
327337 quotient_weight_type qw = nested_brdf.quotientAndWeight (_sample, interaction_negreflected, __createChildCache (_sample, interaction_negreflected));
328- quo *= qw.quotient ();
338+ value_weight_type vw_other = nested_brdf.evalAndWeight (_sample, interaction_negreflected);
339+ quo *= __calculateQuotient (qw.quotient (), vw_other.value (), scalar_type (1.0 ) - lambda_p, qw.weight (), vw_other.weight ());
329340 }
330341 else
331342 {
332343 quotient_weight_type qw = nested_brdf.quotientAndWeight (_sample, interaction, _cache.aniso_cache);
333- quo *= qw.quotient ();
344+ value_weight_type vw_other = nested_brdf.evalAndWeight (_sample, interaction);
345+ quo *= __calculateQuotient (qw.quotient (), vw_other.value (), lambda_p, qw.weight (), vw_other.weight ());
334346 }
335347
336348 if (_cache.sampleIsShadowed)
@@ -403,6 +415,13 @@ struct SMicrofacetNormals<Config, BRDF, P, 1 NBL_PARTIAL_REQ_BOT(config_concepts
403415 return bxdf_type::anisocache_type::template createForReflection<anisotropic_interaction_type, sample_type>(interaction, _sample);
404416 }
405417
418+ static spectral_type __calculateQuotient (const spectral_type quo, const spectral_type quo_other, const scalar_type choiceProb, const scalar_type pdf, const scalar_type pdf_other)
419+ {
420+ const scalar_type weight = pdf / (pdf + pdf_other); // balance heuristic
421+ return (quo * weight / choiceProb) / (scalar_type (1.0 ) + pdf_other * (scalar_type (1.0 ) - choiceProb) / (pdf * choiceProb)) +
422+ (quo_other * (scalar_type (1.0 ) - weight)) / (pdf_other * (scalar_type (1.0 ) - choiceProb) + (pdf * choiceProb));
423+ }
424+
406425 value_weight_type evalAndWeight (NBL_CONST_REF_ARG (sample_type) _sample, NBL_CONST_REF_ARG (isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC
407426 {
408427 return evalAndWeight (_sample, anisotropic_interaction_type::create (interaction));
@@ -580,6 +599,9 @@ struct SMicrofacetNormals<Config, BRDF, P, 1 NBL_PARTIAL_REQ_BOT(config_concepts
580599 }
581600
582601 const vector3_type Nt = shadowing_method_type::computeNt (Np, shadingBasis);
602+ const scalar_type NpdotV = interaction.getNdotV ();
603+ const scalar_type NtdotV = hlsl::dot (Nt, V.getDirection ());
604+ const scalar_type lambda_p = shadowing_method_type::lambdaP (NdotNp, hlsl::max (scalar_type (0.0 ), NpdotV), hlsl::max (scalar_type (0.0 ), NtdotV));
583605 spectral_type quo = hlsl::promote<spectral_type>(1.0 );
584606
585607 if (_cache.sampleFromNt)
@@ -589,12 +611,14 @@ struct SMicrofacetNormals<Config, BRDF, P, 1 NBL_PARTIAL_REQ_BOT(config_concepts
589611 typename bxdf_type::anisotropic_interaction_type interaction_t = bxdf_type::anisotropic_interaction_type::create (iso_t);
590612
591613 quotient_weight_type qw = nested_brdf.quotientAndWeight (_sample, interaction_t, __createChildCache (_sample, interaction_t));
592- quo *= qw.quotient ();
614+ value_weight_type vw_other = nested_brdf.evalAndWeight (_sample, interaction_t);
615+ quo *= __calculateQuotient (qw.quotient (), vw_other.value (), scalar_type (1.0 ) - lambda_p, qw.weight (), vw_other.weight ());
593616 }
594617 else
595618 {
596619 quotient_weight_type qw = nested_brdf.quotientAndWeight (_sample, interaction, _cache.aniso_cache);
597- quo *= qw.quotient ();
620+ value_weight_type vw_other = nested_brdf.evalAndWeight (_sample, interaction);
621+ quo *= __calculateQuotient (qw.quotient (), vw_other.value (), lambda_p, qw.weight (), vw_other.weight ());
598622 }
599623
600624 if (_cache.sampleIsShadowed)
0 commit comments