[Bf-blender-cvs] [320757bc611] master: Refactor microfacet BSDF to reduce repetition

Weizhen Huang noreply at git.blender.org
Thu Jan 19 12:08:04 CET 2023


Commit: 320757bc6111bf7c652068368b92312c994838f8
Author: Weizhen Huang
Date:   Thu Jan 19 12:06:14 2023 +0100
Branches: master
https://developer.blender.org/rB320757bc6111bf7c652068368b92312c994838f8

Refactor microfacet BSDF to reduce repetition

===================================================================

M	intern/cycles/kernel/closure/bsdf_microfacet.h
M	intern/cycles/kernel/integrator/mnee.h

===================================================================

diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index ed438b1f483..377cf836fb8 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -43,17 +43,18 @@ ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg,
                                                          ccl_private float *slope_y,
                                                          ccl_private float *G1i)
 {
-  /* special case (normal incidence) */
+  /* Special case (normal incidence). */
   if (cos_theta_i >= 0.99999f) {
     const float r = sqrtf(-logf(randu));
     const float phi = M_2PI_F * randv;
     *slope_x = r * cosf(phi);
     *slope_y = r * sinf(phi);
     *G1i = 1.0f;
+
     return;
   }
 
-  /* precomputations */
+  /* Precomputations. */
   const float tan_theta_i = sin_theta_i / cos_theta_i;
   const float inv_a = tan_theta_i;
   const float cot_theta_i = 1.0f / tan_theta_i;
@@ -129,7 +130,7 @@ ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i,
                                                     ccl_private float *slope_y,
                                                     ccl_private float *G1i)
 {
-  /* special case (normal incidence) */
+  /* Special case (normal incidence). */
   if (cos_theta_i >= 0.99999f) {
     const float r = sqrtf(randu / (1.0f - randu));
     const float phi = M_2PI_F * randv;
@@ -140,13 +141,13 @@ ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i,
     return;
   }
 
-  /* precomputations */
+  /* Precomputations. */
   const float tan_theta_i = sin_theta_i / cos_theta_i;
   const float G1_inv = 0.5f * (1.0f + safe_sqrtf(1.0f + tan_theta_i * tan_theta_i));
 
   *G1i = 1.0f / G1_inv;
 
-  /* sample slope_x */
+  /* Sample slope_x. */
   const float A = 2.0f * randu * G1_inv - 1.0f;
   const float AA = A * A;
   const float tmp = 1.0f / (AA - 1.0f);
@@ -157,7 +158,7 @@ ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i,
   const float slope_x_2 = B * tmp + D;
   *slope_x = (A < 0.0f || slope_x_2 * tan_theta_i > 1.0f) ? slope_x_1 : slope_x_2;
 
-  /* sample slope_y */
+  /* Sample slope_y. */
   float S;
 
   if (randv > 0.5f) {
@@ -187,7 +188,7 @@ ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals kg,
   float3 wi_ = make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z);
   wi_ = normalize(wi_);
 
-  /* get polar coordinates of wi_ */
+  /* Compute polar coordinates of wi_. */
   float costheta_ = 1.0f;
   float sintheta_ = 0.0f;
   float cosphi_ = 1.0f;
@@ -238,26 +239,85 @@ ccl_device_forceinline Spectrum reflection_color(ccl_private const MicrofacetBsd
                                                  float3 H)
 {
   Spectrum F = one_spectrum();
-  bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID ||
-                      bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID);
+
+  bool use_clearcoat = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
+  bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || use_clearcoat);
+
   if (use_fresnel) {
     float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
 
     F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0);
   }
 
+  if (use_clearcoat) {
+    F *= 0.25f * bsdf->extra->clearcoat;
+  }
+
   return F;
 }
 
-ccl_device_forceinline float D_GTR1(float NdotH, float alpha)
+/* Generalized Trowbridge-Reitz for clearcoat. */
+ccl_device_forceinline float bsdf_clearcoat_D(float alpha2, float cos_NH)
 {
-  if (alpha >= 1.0f)
+  if (alpha2 >= 1.0f) {
     return M_1_PI_F;
-  float alpha2 = alpha * alpha;
-  float t = 1.0f + (alpha2 - 1.0f) * NdotH * NdotH;
+  }
+
+  const float t = 1.0f + (alpha2 - 1.0f) * cos_NH * cos_NH;
   return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
 }
 
+/* Monodirectional shadowing-masking term. */
+template<bool beckmann> ccl_device_inline float bsdf_G1_from_sqr_alpha_tan_n(float sqr_alpha_tan_n)
+{
+  if (!beckmann) { /* GGX. */
+    return 2.0f / (1.0f + sqrtf(1.0f + sqr_alpha_tan_n));
+  }
+
+  const float a = inversesqrtf(sqr_alpha_tan_n);
+  return (a > 1.6f) ? 1.0f : ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f);
+}
+
+template<bool beckmann> ccl_device_inline float bsdf_G1(float alpha2, float cos_N)
+{
+  return bsdf_G1_from_sqr_alpha_tan_n<beckmann>(alpha2 *
+                                                fmaxf(1.0f / (cos_N * cos_N) - 1.0f, 0.0f));
+}
+
+template<bool beckmann>
+ccl_device_inline float bsdf_aniso_G1(float alpha_x, float alpha_y, float3 V)
+{
+  return bsdf_G1_from_sqr_alpha_tan_n<beckmann>((sqr(alpha_x * V.x) + sqr(alpha_y * V.y)) /
+                                                sqr(V.z));
+}
+
+/* Smith's separable shadowing-masking term. */
+template<bool beckmann> ccl_device_inline float bsdf_G(float alpha2, float cos_NI, float cos_NO)
+{
+  return bsdf_G1<beckmann>(alpha2, cos_NI) * bsdf_G1<beckmann>(alpha2, cos_NO);
+}
+
+/* Normal distribution function. */
+template<bool beckmann> ccl_device_inline float bsdf_D(float alpha2, float cos_NH)
+{
+  const float cos_NH2 = sqr(cos_NH);
+
+  return beckmann ? expf((1.0f - 1.0f / cos_NH2) / alpha2) / (M_PI_F * alpha2 * sqr(cos_NH2)) :
+                    alpha2 / (M_PI_F * sqr(1.0f + (alpha2 - 1.0f) * cos_NH2));
+}
+
+template<bool beckmann>
+ccl_device_inline float bsdf_aniso_D(float alpha_x, float alpha_y, float3 H)
+{
+  H /= make_float3(alpha_x, alpha_y, 1.0f);
+
+  const float cos_NH2 = sqr(H.z);
+  const float alpha2 = alpha_x * alpha_y;
+
+  return beckmann ? expf(-(sqr(H.x) + sqr(H.y)) / cos_NH2) / (M_PI_F * alpha2 * sqr(cos_NH2)) :
+                    M_1_PI_F / (alpha2 * sqr(len_squared(H)));
+}
+
 ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const ShaderData *sd,
                                                           ccl_private MicrofacetBsdf *bsdf)
 {
@@ -274,6 +334,217 @@ ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const Shad
   bsdf->sample_weight *= average(bsdf->extra->fresnel_color);
 }
 
+template<bool beckmann>
+ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
+                                         const float3 Ng,
+                                         const float3 wi,
+                                         const float3 wo,
+                                         ccl_private float *pdf)
+{
+  ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
+  const bool m_refractive = (bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) ||
+                            (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+
+  const float3 N = bsdf->N;
+  const float cos_NI = dot(N, wi);
+  const float cos_NO = dot(N, wo);
+  const float cos_NgO = dot(Ng, wo);
+
+  const float alpha_x = bsdf->alpha_x;
+  const float alpha_y = bsdf->alpha_y;
+
+  if ((cos_NI <= 0) || ((cos_NgO < 0.0f) != m_refractive) || ((cos_NO < 0.0f) != m_refractive) ||
+      (alpha_x * alpha_y <= 1e-7f)) {
+    *pdf = 0.0f;
+    return zero_spectrum();
+  }
+
+  /* Compute half vector. */
+  float3 H = m_refractive ? -(bsdf->ior * wo + wi) : (wi + wo);
+  const float inv_len_H = 1.0f / len(H);
+  H *= inv_len_H;
+
+  const float cos_NH = dot(N, H);
+  float D, G1i, G1o;
+
+  /* TODO: add support for anisotropic transmission. */
+  if (alpha_x == alpha_y || m_refractive) { /* Isotropic. */
+    float alpha2 = alpha_x * alpha_y;
+
+    if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
+      D = bsdf_clearcoat_D(alpha2, cos_NH);
+
+      /* The masking-shadowing term for clearcoat has a fixed alpha of 0.25
+       * => alpha2 = 0.25 * 0.25 */
+      alpha2 = 0.0625f;
+    }
+    else {
+      D = bsdf_D<beckmann>(alpha2, cos_NH);
+    }
+
+    G1i = bsdf_G1<beckmann>(alpha2, cos_NI);
+    G1o = bsdf_G1<beckmann>(alpha2, cos_NO);
+  }
+  else { /* Anisotropic. */
+    float3 X, Y;
+    make_orthonormals_tangent(N, bsdf->T, &X, &Y);
+
+    const float3 local_H = make_float3(dot(X, H), dot(Y, H), cos_NH);
+    const float3 local_I = make_float3(dot(X, wi), dot(Y, wi), cos_NI);
+    const float3 local_O = make_float3(dot(X, wo), dot(Y, wo), cos_NO);
+
+    D = bsdf_aniso_D<beckmann>(alpha_x, alpha_y, local_H);
+
+    G1i = bsdf_aniso_G1<beckmann>(alpha_x, alpha_y, local_I);
+    G1o = bsdf_aniso_G1<beckmann>(alpha_x, alpha_y, local_O);
+  }
+
+  const float common = G1i * D / cos_NI *
+                       (m_refractive ?
+                            sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
+                            0.25f);
+
+  *pdf = common;
+
+  const Spectrum F = m_refractive ? one_spectrum() : reflection_color(bsdf, wo, H);
+
+  return F * G1o * common;
+}
+
+template<bool beckmann>
+ccl_device int bsdf_microfacet_sample(KernelGlobals kg,
+                                      ccl_private const ShaderClosure *sc,
+                                      float3 Ng,
+                                      float3 wi,
+                                      float randu,
+                                      float randv,
+                                      ccl_private Spectrum *eval,
+                                      ccl_private float3 *wo,
+                                      ccl_private float *pdf,
+                                      ccl_private float2 *sampled_roughness,
+                                      ccl_private float *eta)
+{
+  ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
+
+  const float m_eta = bsdf->ior;
+  const bool m_refractive = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) ||
+                            (bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+  int label = m_refractive ? LABEL_TRANSMIT : LABEL_REFLECT;
+
+  const float3 N = bsdf->N;
+  const float cos_NI = dot(N, wi);
+  if (cos_NI <= 0) {
+    return label | LABEL_GLOSSY;
+  }
+
+  float3 X, Y;
+  const float alpha_x = bsdf->alpha_x;
+  const float alpha_y = bsdf->alpha_y;
+  if (alpha_x == alpha_y) {
+    make_orthonormals(N, &X, &Y);
+  }
+  else {
+    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list