[Bf-blender-cvs] [0399badca57] principled-v2: Cleanup microfacet code (move distribution helpers to header, reduce nested ifs)

Lukas Stockner noreply at git.blender.org
Mon Jul 4 23:56:11 CEST 2022


Commit: 0399badca5736c8097c5a99b59e14f15b1080b9d
Author: Lukas Stockner
Date:   Mon Jul 4 23:31:47 2022 +0200
Branches: principled-v2
https://developer.blender.org/rB0399badca5736c8097c5a99b59e14f15b1080b9d

Cleanup microfacet code (move distribution helpers to header, reduce nested ifs)

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

M	intern/cycles/kernel/CMakeLists.txt
M	intern/cycles/kernel/closure/bsdf_microfacet.h
A	intern/cycles/kernel/closure/bsdf_microfacet_util.h

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

diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index a37c0299652..7948031ec40 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -103,6 +103,7 @@ set(SRC_KERNEL_CLOSURE_HEADERS
   closure/bsdf_microfacet_beckmann.h
   closure/bsdf_microfacet_multi.h
   closure/bsdf_microfacet_multi_impl.h
+  closure/bsdf_microfacet_util.h
   closure/bsdf_oren_nayar.h
   closure/bsdf_phong_ramp.h
   closure/bsdf_reflection.h
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 42ea71f62a9..000bde9e5d5 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -8,6 +8,7 @@
 
 #pragma once
 
+#include "kernel/closure/bsdf_microfacet_util.h"
 #include "kernel/closure/bsdf_util.h"
 
 CCL_NAMESPACE_BEGIN
@@ -66,80 +67,6 @@ ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const Shad
   bsdf->sample_weight *= average(bsdf->extra->fresnel_color);
 }
 
-/* GGX microfacet with Smith shadow-masking from:
- *
- * Microfacet Models for Refraction through Rough Surfaces
- * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007
- *
- * VNDF sampling as well as D and lambda terms from:
- *
- * Sampling the GGX Distribution of Visible Normals.
- * E. Heitz and E. d'Eon, JCGT Vol. 7, No. 4, 2018.
- * https://jcgt.org/published/0007/04/01/
- *
- * Also see for more details on marking-shadowing:
- * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs.
- * E. Heitz, JCGT Vol. 3, No. 2, 2014.
- * https://jcgt.org/published/0003/02/03/
- *
- * Anisotropy is only supported for reflection currently, but adding it for
- * transmission is just a matter of copying code from reflection if needed. */
-
-ccl_device_forceinline float microfacet_ggx_lambda(const float cosTheta, const float alpha2)
-{
-  float tanTheta2 = (1 - sqr(cosTheta)) / sqr(cosTheta);
-  return 0.5f * (safe_sqrtf(1 + alpha2 * tanTheta2) - 1);
-}
-
-ccl_device_forceinline float microfacet_ggx_lambda_aniso(const float3 w,
-                                                         const float alpha_x,
-                                                         const float alpha_y)
-{
-  return 0.5f * (safe_sqrtf(1 + (sqr(w.x * alpha_x) + sqr(w.y * alpha_y)) / sqr(w.z)) - 1);
-}
-
-ccl_device_forceinline float microfacet_ggx_D(const float cosThetaM, const float alpha2)
-{
-  float cosThetaM2 = sqr(cosThetaM);
-  float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
-  return alpha2 / (M_PI_F * sqr(cosThetaM2 * (alpha2 + tanThetaM2)));
-}
-
-ccl_device_forceinline float microfacet_ggx_D_aniso(const float3 m,
-                                                    const float alpha_x,
-                                                    const float alpha_y)
-{
-  return 1 /
-         (M_PI_F * alpha_x * alpha_y * sqr(sqr(m.x / alpha_x) + sqr(m.y / alpha_y) + sqr(m.z)));
-}
-
-ccl_device_forceinline float microfacet_GTR1_D(const float cosThetaM, const float alpha2)
-{
-  if (alpha2 >= 1.0f)
-    return M_1_PI_F;
-  float t = 1.0f + (alpha2 - 1.0f) * sqr(cosThetaM);
-  return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
-}
-
-ccl_device_forceinline float3 microfacet_ggx_sample_vndf(
-    const float3 V, const float alpha_x, const float alpha_y, const float U1, const float U2)
-{
-  /* Section 3.2: Transforming the view direction to the hemisphere configuration. */
-  float3 Vh = normalize(make_float3(alpha_x * V.x, alpha_y * V.y, V.z));
-  /* Section 4.1: Orthonormal basis (with special case if cross product is zero). */
-  float lensq = sqr(Vh.x) + sqr(Vh.y);
-  float3 T1 = lensq > 1e-7f ? make_float3(-Vh.y, Vh.x, 0.0f) / sqrtf(lensq) :
-                              make_float3(1.0f, 0.0f, 0.0f);
-  float3 T2 = cross(Vh, T1);
-  /* Section 4.2: Parameterization of the projected area. */
-  float2 t = concentric_sample_disk(U1, U2);
-  t.y = mix(safe_sqrtf(1.0f - sqr(t.x)), t.y, 0.5f * (1.0f + Vh.z));
-  /* Section 4.3: Reprojection onto hemisphere. */
-  float3 Mh = t.x * T1 + t.y * T2 + safe_sqrtf(1.0f - len_squared(t)) * Vh;
-  /* Section 3.4: Transforming the normal back to the ellipsoid configuration. */
-  return normalize(make_float3(alpha_x * Mh.x, alpha_y * Mh.y, max(0.0f, Mh.z)));
-}
-
 ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
 {
   bsdf->extra = NULL;
@@ -218,10 +145,11 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(ccl_private const ShaderClosu
   ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
   float alpha_x = bsdf->alpha_x;
   float alpha_y = bsdf->alpha_y;
+  float alpha2 = alpha_x * alpha_y;
   bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
   float3 N = bsdf->N;
 
-  if (m_refractive || alpha_x * alpha_y <= 1e-7f) {
+  if (m_refractive || alpha2 <= 1e-7f) {
     *pdf = 0.0f;
     return make_float3(0.0f, 0.0f, 0.0f);
   }
@@ -232,76 +160,76 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(ccl_private const ShaderClosu
    * Therefore, in the BSDF code, I is referred to as O and omega_in is referred to as I
    * in order to be consistent with papers.
    */
+
+  /* Ensure that both direction are in the upper hemisphere */
   float cosNO = dot(N, I);
   float cosNI = dot(N, omega_in);
+  if (cosNI <= 0 || cosNO <= 0) {
+    *pdf = 0.0f;
+    return make_float3(0.0f, 0.0f, 0.0f);
+  }
 
-  if (cosNI > 0 && cosNO > 0) {
-    /* get half vector */
-    float3 m = normalize(omega_in + I);
-    float alpha2 = alpha_x * alpha_y;
-    float D, lambdaO, lambdaI;
-
-    if (alpha_x == alpha_y) {
-      /* Isotropic case */
+  /* Compute half vector */
+  float3 m = normalize(omega_in + I);
 
-      if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
-        /* use GTR1 for clearcoat */
-        D = microfacet_GTR1_D(dot(N, m), alpha2);
+  float D, lambdaO, lambdaI;
+  if (alpha_x == alpha_y) {
+    /* Isotropic case */
 
-        /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
-        alpha2 = 0.0625f;
-      }
-      else {
-        /* use GTR2 otherwise */
-        D = microfacet_ggx_D(dot(N, m), alpha2);
-      }
+    if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
+      /* use GTR1 for clearcoat */
+      D = microfacet_GTR1_D(dot(N, m), alpha2);
 
-      lambdaO = microfacet_ggx_lambda(cosNO, alpha2);
-      lambdaI = microfacet_ggx_lambda(cosNI, alpha2);
+      /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
+      alpha2 = 0.0625f;
     }
     else {
-      /* Anisotropic case */
-      float3 X, Y, Z = N;
-      make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
-
-      /* Transform vectors into local coordinate space */
-      float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
-      float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO);
-      float3 local_I = make_float3(dot(X, omega_in), dot(Y, omega_in), cosNI);
-
-      D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y);
-      lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y);
-      lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y);
+      /* use GTR2 otherwise */
+      D = microfacet_ggx_D(dot(N, m), alpha2);
     }
 
-    /* The full BSDF is (see e.g. eq. 20 in Walter et al. 2017):
-     * f(i, o) = F(i, m) * G(i, o) * D(m) / (4*cosNI*cosNO).
-     *
-     * Here, F is the fresnel reflection term, G is the masking-shadowing term,
-     * D is the microfacet distribution and cosNI/cosNO are cosines of angles.
-     *
-     * For G, this implementation uses the non-separable form of the Smith
-     * masking-shadowing term, so G is defined in terms of a function Lambda:
-     * G(i, o) = 1 / (1 + Lambda(i) + Lambda(o)).
-     *
-     * In Cycles, BSDF evaluation actually returns f(i, o)*cosNI, so one term
-     * in the BSDFs denominator cancels out.
-     *
-     * The PDF of VNDF sampling is D(m) * G1(o) / (4*cosNO), where G1(o) is
-     * 1 / (1 + Lambda(o)).
-     */
+    lambdaO = microfacet_ggx_lambda(cosNO, alpha2);
+    lambdaI = microfacet_ggx_lambda(cosNI, alpha2);
+  }
+  else {
+    /* Anisotropic case */
+    float3 X, Y, Z = N;
+    make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
 
-    float common = D * 0.25f / cosNO;
+    /* Transform vectors into local coordinate space */
+    float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
+    float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO);
+    float3 local_I = make_float3(dot(X, omega_in), dot(Y, omega_in), cosNI);
 
-    float3 F = reflection_color(bsdf, omega_in, m);
+    D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y);
+    lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y);
+    lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y);
+  }
 
-    float3 out = F * common / (1 + lambdaO + lambdaI);
-    *pdf = common / (1 + lambdaO);
+  /* The full BSDF is (see e.g. eq. 20 in Walter et al. 2007):
+   * f(i, o) = F(i, m) * G(i, o) * D(m) / (4*cosNI*cosNO).
+   *
+   * Here, F is the fresnel reflection term, G is the masking-shadowing term,
+   * D is the microfacet distribution and cosNI/cosNO are cosines of angles.
+   *
+   * For G, this implementation uses the non-separable form of the Smith
+   * masking-shadowing term, so G is defined in terms of a function Lambda:
+   * G(i, o) = 1 / (1 + Lambda(i) + Lambda(o)).
+   *
+   * In Cycles, BSDF evaluation actually returns f(i, o)*cosNI, so one term
+   * in the BSDFs denominator cancels out.
+   *
+   * The PDF of VNDF sampling is D(m) * G1(o) / (4*cosNO), where G1(o) is
+   * 1 / (1 + Lambda(o)).
+   */
 
-    return out;
-  }
+  /* Evaluate BSDF */
+  float common = D * 0.25f / cosNO;
+  float3 F = reflection_color(bsdf, omega_in, m);
+  float3 out = F * common / (1 + lambdaO + lambdaI);
+  *pdf = common / (1 + lambdaO);
 
-  return make_float3(0.0f, 0.0f, 0.0f);
+  return out;
 }
 
 ccl_device float3 bsdf_microfacet_ggx_eval_transmit(ccl_private const ShaderClosure *sc,
@@ -312,46 +240,38 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(ccl_private const ShaderClos
   ccl_private const MicrofacetBsdf *bsdf = (ccl_p

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list