From e894e6a411f1c9f5ad329ea9c1dc4f9e78e43a09 Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Mon, 18 Sep 2023 16:20:48 +0200 Subject: [PATCH] Fix: Cycles: wrong refractive index in path guiding should be the relative IOR of the outgoing media to the incoming media, depending on `bsdf->ior` and whether the interaction is refraction. Reference paper: [Robust Fitting of Parallax-Aware Mixtures for Path Guiding](https://uni-tuebingen.de/fakultaeten/mathematisch-naturwissenschaftliche-fakultaet/fachbereiche/informatik/lehrstuehle/computergrafik/lehrstuhl/veroeffentlichungen/robust-fitting-of-parallax-aware-mixtures-for-path-guiding/) Eq (35) Pull Request: https://projects.blender.org/blender/blender/pulls/112157 --- intern/cycles/kernel/closure/bsdf.h | 18 ++++++++---------- intern/cycles/kernel/closure/bsdf_microfacet.h | 2 +- .../closure/bsdf_principled_hair_chiang.h | 4 +--- .../closure/bsdf_principled_hair_huang.h | 10 ++++------ intern/cycles/kernel/integrator/guiding.h | 1 + .../cycles/kernel/integrator/surface_shader.h | 16 ++++++++-------- 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index ff94e3dce24..93168770c1c 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -196,10 +196,12 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, *eta = 1.0f; break; case CLOSURE_BSDF_HAIR_CHIANG_ID: - label = bsdf_hair_chiang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta); + label = bsdf_hair_chiang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness); + *eta = 1.0f; break; case CLOSURE_BSDF_HAIR_HUANG_ID: - label = bsdf_hair_huang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness, eta); + label = bsdf_hair_huang_sample(kg, sc, sd, rand, eval, wo, pdf, sampled_roughness); + *eta = 1.0f; break; case CLOSURE_BSDF_SHEEN_ID: label = bsdf_sheen_sample(sc, Ng, sd->wi, rand_xy, eval, wo, pdf); @@ -247,6 +249,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, ccl_private const ShaderClosure *sc, + const float3 wo, ccl_private float2 *roughness, ccl_private float *eta) { @@ -290,12 +293,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; *roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); - if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) { - *eta = 1.0f / bsdf->ior; - } - else { - *eta = bsdf->ior; - } + *eta = (bsdf_is_transmission(sc, wo)) ? bsdf->ior : 1.0f; break; } case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: { @@ -330,12 +328,12 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, case CLOSURE_BSDF_HAIR_CHIANG_ID: alpha = ((ccl_private ChiangHairBSDF *)sc)->m0_roughness; *roughness = make_float2(alpha, alpha); - *eta = ((ccl_private ChiangHairBSDF *)sc)->eta; + *eta = 1.0f; break; case CLOSURE_BSDF_HAIR_HUANG_ID: alpha = ((ccl_private HuangHairBSDF *)sc)->roughness; *roughness = make_float2(alpha, alpha); - *eta = ((ccl_private HuangHairBSDF *)sc)->eta; + *eta = 1.0f; break; case CLOSURE_BSDF_SHEEN_ID: alpha = ((ccl_private SheenBsdf *)sc)->roughness; diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 591f9fa6aa9..fa939ae854f 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -683,7 +683,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, } *sampled_roughness = make_float2(alpha_x, alpha_y); - *eta = do_refract ? m_inv_eta : m_eta; + *eta = do_refract ? m_eta : 1.0f; return (do_refract ? LABEL_TRANSMIT : LABEL_REFLECT) | (m_singular ? LABEL_SINGULAR : LABEL_GLOSSY); diff --git a/intern/cycles/kernel/closure/bsdf_principled_hair_chiang.h b/intern/cycles/kernel/closure/bsdf_principled_hair_chiang.h index 27cdaed02c3..b1642f67b5a 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_hair_chiang.h +++ b/intern/cycles/kernel/closure/bsdf_principled_hair_chiang.h @@ -335,13 +335,11 @@ ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, - ccl_private float2 *sampled_roughness, - ccl_private float *eta) + ccl_private float2 *sampled_roughness) { ccl_private ChiangHairBSDF *bsdf = (ccl_private ChiangHairBSDF *)sc; *sampled_roughness = make_float2(bsdf->m0_roughness, bsdf->m0_roughness); - *eta = bsdf->eta; const float3 Y = bsdf->N; diff --git a/intern/cycles/kernel/closure/bsdf_principled_hair_huang.h b/intern/cycles/kernel/closure/bsdf_principled_hair_huang.h index 5c607d89f8a..47b67862045 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_hair_huang.h +++ b/intern/cycles/kernel/closure/bsdf_principled_hair_huang.h @@ -614,14 +614,12 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, - ccl_private float2 *sampled_roughness, - ccl_private float *eta) + ccl_private float2 *sampled_roughness) { ccl_private HuangHairBSDF *bsdf = (ccl_private HuangHairBSDF *)sc; const float roughness = bsdf->roughness; *sampled_roughness = make_float2(roughness, roughness); - *eta = bsdf->eta; kernel_assert(fabsf(bsdf->h) < bsdf->extra->radius); @@ -680,7 +678,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg, } float cos_theta_t1; - const float R1 = fresnel_dielectric(dot(wi, wh1), *eta, &cos_theta_t1); + const float R1 = fresnel_dielectric(dot(wi, wh1), bsdf->eta, &cos_theta_t1); const float scale1 = bsdf_hair_huang_energy_scale(kg, cos_mi1, sqrt_roughness, bsdf->eta); const float R = bsdf->extra->R * R1 * scale1 * microfacet_visible(wr, wmi_, wh1) * bsdf_Go(roughness2, cos_mi1, dot(wmi, wr)); @@ -717,7 +715,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg, const float T2 = 1.0f - R2; const float scale2 = bsdf_hair_huang_energy_scale(kg, cos_mi2, sqrt_roughness, inv_eta); - wtt = refract_angle(-wt, wh2, cos_theta_t2, *eta); + wtt = refract_angle(-wt, wh2, cos_theta_t2, bsdf->eta); if (dot(wmt, -wtt) > 0.0f && cos_theta_t2 != 0.0f && microfacet_visible(-wtt, wmt_, wh2)) { TT = bsdf->extra->TT * T1 * A_t * T2 * scale2 * bsdf_Go(roughness2, cos_mi2, dot(wmt, -wtt)); @@ -733,7 +731,7 @@ ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg, float cos_theta_t3; const float R3 = fresnel_dielectric(dot(wtr, wh3), inv_eta, &cos_theta_t3); - wtrt = refract_angle(wtr, wh3, cos_theta_t3, *eta); + wtrt = refract_angle(wtr, wh3, cos_theta_t3, bsdf->eta); const float cos_mi3 = dot(wmtr, wtr); if (cos_mi3 > 0.0f) { diff --git a/intern/cycles/kernel/integrator/guiding.h b/intern/cycles/kernel/integrator/guiding.h index 681663d88f8..f2d1c343a83 100644 --- a/intern/cycles/kernel/integrator/guiding.h +++ b/intern/cycles/kernel/integrator/guiding.h @@ -15,6 +15,7 @@ CCL_NAMESPACE_BEGIN struct GuidingRISSample { float3 rand; float2 sampled_roughness; + /* The relative ior of the outgoing media and the incoming media. */ float eta{1.0f}; int label; float3 wo; diff --git a/intern/cycles/kernel/integrator/surface_shader.h b/intern/cycles/kernel/integrator/surface_shader.h index ed8eeceefc0..92749d6b9ad 100644 --- a/intern/cycles/kernel/integrator/surface_shader.h +++ b/intern/cycles/kernel/integrator/surface_shader.h @@ -209,7 +209,7 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg, } /* BSDF */ -#if 0 +#ifdef WITH_CYCLES_DEBUG ccl_device_inline void surface_shader_validate_bsdf_sample(const KernelGlobals kg, const ShaderClosure *sc, const float3 wo, @@ -224,7 +224,7 @@ ccl_device_inline void surface_shader_validate_bsdf_sample(const KernelGlobals k float2 comp_roughness; float comp_eta; - bsdf_roughness_eta(kg, sc, &comp_roughness, &comp_eta); + bsdf_roughness_eta(kg, sc, wo, &comp_roughness, &comp_eta); kernel_assert(org_eta == comp_eta); kernel_assert(org_roughness.x == comp_roughness.x); kernel_assert(org_roughness.y == comp_roughness.y); @@ -550,10 +550,10 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg, unguided_bsdf_pdf, sampled_roughness, eta); -# if 0 -// Code path to validate the estimation of the label, sampled roughness and eta -// This should be activated from time to time when the BSDFs change to check if everything -// is still working correctly. +# ifdef WITH_CYCLES_DEBUG + /* Code path to validate the estimation of the label, sampled roughness and eta. This should be + * activated from time to time when the BSDFs change to check if everything is still working + * correctly. */ if (*unguided_bsdf_pdf > 0.0f) { surface_shader_validate_bsdf_sample(kg, sc, *wo, label, *sampled_roughness, *eta); } @@ -773,7 +773,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg, idx = (rnd > sum_pdfs) ? sd->num_closure - 1 : idx; label = bsdf_label(kg, &sd->closure[idx], *wo); - bsdf_roughness_eta(kg, &sd->closure[idx], sampled_roughness, eta); + bsdf_roughness_eta(kg, &sd->closure[idx], *wo, sampled_roughness, eta); } kernel_assert(isfinite_safe(*bsdf_pdf)); @@ -793,7 +793,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg, unguided_bsdf_pdf, sampled_roughness, eta); -# if 0 +# ifdef WITH_CYCLES_DEBUG // Code path to validate the estimation of the label, sampled roughness and eta // This should be activated from time to time when the BSDFs change to check if everything // is still working correctly.