[Bf-blender-cvs] [68573757bc5] microfacet_hair: Cycles: initial commit of microfacet hair bsdf

Weizhen Huang noreply at git.blender.org
Tue Dec 6 18:52:09 CET 2022


Commit: 68573757bc5fb615f6bf2e27056f6e10a556bf70
Author: Weizhen Huang
Date:   Tue Dec 6 18:43:56 2022 +0100
Branches: microfacet_hair
https://developer.blender.org/rB68573757bc5fb615f6bf2e27056f6e10a556bf70

Cycles: initial commit of microfacet hair bsdf

This is an implementation of the paper [A Microfacet-based Hair Scattering Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by Weizhen Huang, Matthias Hullin, and Johannes Hanika.
Original implementation in [Mitsuba 2](https://github.com/RiverIntheSky/roughhair) by Weizhen Huang.
Adapted to Cycles by Olivier Maury D16682 and Christophe Hery.

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

M	intern/cycles/blender/shader.cpp
M	intern/cycles/kernel/CMakeLists.txt
M	intern/cycles/kernel/closure/bsdf.h
A	intern/cycles/kernel/closure/bsdf_hair_microfacet.h
M	intern/cycles/kernel/film/denoising_passes.h
M	intern/cycles/kernel/osl/shaders/CMakeLists.txt
A	intern/cycles/kernel/osl/shaders/node_microfacet_hair_bsdf.osl
M	intern/cycles/kernel/osl/shaders/stdcycles.h
M	intern/cycles/kernel/svm/closure.h
M	intern/cycles/kernel/svm/types.h
M	intern/cycles/scene/shader_graph.cpp
M	intern/cycles/scene/shader_nodes.cpp
M	intern/cycles/scene/shader_nodes.h
M	release/datafiles/locale
M	release/scripts/addons
M	source/blender/blenkernel/BKE_node.h
M	source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/nodes/NOD_static_types.h
M	source/blender/nodes/shader/CMakeLists.txt
M	source/blender/nodes/shader/node_shader_register.cc
M	source/blender/nodes/shader/node_shader_register.hh
M	source/blender/nodes/shader/node_shader_tree.cc
A	source/blender/nodes/shader/nodes/node_shader_bsdf_hair_microfacet.cc

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

diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index f25e98469fb..43bc5538628 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -660,6 +660,21 @@ static ShaderNode *add_node(Scene *scene,
                                                     NODE_PRINCIPLED_HAIR_REFLECTANCE));
     node = principled_hair;
   }
+  else if (b_node.is_a(&RNA_ShaderNodeBsdfHairMicrofacet)) {
+    BL::ShaderNodeBsdfHairMicrofacet b_microfacet_hair_node(b_node);
+    MicrofacetHairBsdfNode *microfacet_hair = graph->create_node<MicrofacetHairBsdfNode>();
+    microfacet_hair->set_parametrization(
+        (NodeMicrofacetHairParametrization)get_enum(b_microfacet_hair_node.ptr,
+                                                    "parametrization",
+                                                    NODE_MICROFACET_HAIR_NUM,
+                                                    NODE_MICROFACET_HAIR_REFLECTANCE));
+    microfacet_hair->set_model_type(
+        (NodeMicrofacetHairModelType)get_enum(b_microfacet_hair_node.ptr,
+                                              "model_type",
+                                              NODE_MICROFACET_HAIR_MODEL_TYPE_NUM,
+                                              NODE_MICROFACET_HAIR_CIRCULAR_GGX));
+    node = microfacet_hair;
+  }
   else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
     BL::ShaderNodeBsdfPrincipled b_principled_node(b_node);
     PrincipledBsdfNode *principled = graph->create_node<PrincipledBsdfNode>();
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 9dc343f597d..a203adda324 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -128,6 +128,7 @@ set(SRC_KERNEL_CLOSURE_HEADERS
   closure/bsdf_principled_diffuse.h
   closure/bsdf_principled_sheen.h
   closure/bsdf_hair_principled.h
+  closure/bsdf_hair_microfacet.h
 )
 
 set(SRC_KERNEL_SVM_HEADERS
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 2f5c5d7bd0c..23c64205c70 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -18,6 +18,7 @@
 #include "kernel/closure/bsdf_toon.h"
 #include "kernel/closure/bsdf_hair.h"
 #include "kernel/closure/bsdf_hair_principled.h"
+#include "kernel/closure/bsdf_hair_microfacet.h"
 #include "kernel/closure/bsdf_principled_diffuse.h"
 #include "kernel/closure/bsdf_principled_sheen.h"
 #include "kernel/closure/bssrdf.h"
@@ -243,6 +244,10 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
       label = bsdf_principled_hair_sample(
           kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
       break;
+    case CLOSURE_BSDF_HAIR_MICROFACET_ID:
+      label = bsdf_microfacet_hair_sample(
+          kg, sc, sd, randu, randv, eval, omega_in, pdf, sampled_roughness, eta);
+      break;
     case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
       label = bsdf_principled_diffuse_sample(sc, Ng, sd->I, randu, randv, eval, omega_in, pdf);
       *sampled_roughness = one_float2();
@@ -408,6 +413,11 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
       *roughness = make_float2(alpha, alpha);
       *eta = ((ccl_private PrincipledHairBSDF *)sc)->eta;
       break;
+    case CLOSURE_BSDF_HAIR_MICROFACET_ID:
+      alpha = ((ccl_private MicrofacetHairBSDF *)sc)->roughness;
+      *roughness = make_float2(alpha, alpha);
+      *eta = ((ccl_private MicrofacetHairBSDF *)sc)->eta;
+      break;
     case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
       *roughness = one_float2();
       *eta = 1.0f;
@@ -504,6 +514,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
       label = LABEL_TRANSMIT | LABEL_GLOSSY;
       break;
     case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
+    case CLOSURE_BSDF_HAIR_MICROFACET_ID:
       if (bsdf_is_transmission(sc, omega_in))
         label = LABEL_TRANSMIT | LABEL_GLOSSY;
       else
@@ -609,6 +620,9 @@ ccl_device_inline
     case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
       eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf);
       break;
+    case CLOSURE_BSDF_HAIR_MICROFACET_ID:
+      eval = bsdf_microfacet_hair_eval(kg, sd, sc, omega_in, pdf);
+      break;
     case CLOSURE_BSDF_HAIR_REFLECTION_ID:
       eval = bsdf_hair_reflection_eval(sc, sd->I, omega_in, pdf);
       break;
@@ -676,6 +690,9 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
     case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
       bsdf_principled_hair_blur(sc, roughness);
       break;
+    case CLOSURE_BSDF_HAIR_MICROFACET_ID:
+      bsdf_microfacet_hair_blur(sc, roughness);
+      break;
     default:
       break;
   }
diff --git a/intern/cycles/kernel/closure/bsdf_hair_microfacet.h b/intern/cycles/kernel/closure/bsdf_hair_microfacet.h
new file mode 100644
index 00000000000..6095ebcac41
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_hair_microfacet.h
@@ -0,0 +1,1598 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2018-2022 Blender Foundation */
+
+#pragma once
+
+#ifndef __KERNEL_GPU__
+#  include <fenv.h>
+#endif
+
+#include "kernel/util/color.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef struct MicrofacetHairExtra {
+  float R;
+  float TT;
+  float TRT;
+
+  float eccentricity;
+  float twist_rate;
+  float attr_descr_intercept;
+  float attr_descr_length;
+
+  float axis_rot;
+  float diffraction_weight;
+  float pad1, pad2, pad3;
+
+  /* Geometry data. */
+  float4 geom;
+} MicrofacetHairExtra;
+
+typedef struct MicrofacetHairBSDF {
+  SHADER_CLOSURE_BASE;
+
+  /* Absorption coefficient. */
+  Spectrum sigma;
+  /* Microfacet distribution roughness. */
+  float roughness;
+  /* Cuticle tilt angle. */
+  float alpha;
+  /* IOR. */
+  float eta;
+
+  /* Blur. */
+  float blur;
+
+  /* Circular/Ellipitic and GGX/Beckmann. */
+  int model_type;
+
+  /* Extra closure. */
+  ccl_private MicrofacetHairExtra *extra;
+} MicrofacetHairBSDF;
+
+static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairBSDF),
+              "MicrofacetHairBSDF is too large!");
+static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetHairExtra),
+              "MicrofacetHairExtra is too large!");
+
+#ifdef __HAIR__
+/* Set up the hair closure. */
+ccl_device int bsdf_microfacet_hair_setup(ccl_private ShaderData *sd,
+                                          ccl_private MicrofacetHairBSDF *bsdf)
+{
+  bsdf->type = CLOSURE_BSDF_HAIR_MICROFACET_ID;
+
+  bsdf->roughness = clamp(bsdf->roughness, 0.001f, 1.0f);
+
+  /* Compute local frame, aligned to curve tangent and ray direction. */
+  float3 X = safe_normalize(sd->dPdu);
+  float3 Y = safe_normalize(cross(X, sd->I));
+
+  /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at
+   * the center, to grazing the other edge. This is the sine of the angle
+   * between sd->Ng and Z, as seen from the tangent X. */
+
+  /* TODO: we convert this value to a cosine later and discard the sign, so
+   * we could probably save some operations. */
+  float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : -dot(Y, sd->Ng);
+
+  kernel_assert(fabsf(h) < 1.0f + 1e-4f);
+  kernel_assert(isfinite_safe(Y));
+  kernel_assert(isfinite_safe(h));
+
+  bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h);
+
+  return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION;
+}
+
+#endif /* __HAIR__ */
+
+ccl_device_inline float3 make_float3_from_float(const float f)
+{
+  return make_float3(f, f, f);
+}
+
+ccl_device_inline float3 reflect_vector(const float3 w, const float3 n)
+{
+  return 2.f * dot(w, n) * n - w;
+}
+
+ccl_device float3 refract_vector(const float3 w,
+                                 const float3 n,
+                                 const float cos_theta_t,
+                                 const float eta_ti)
+{
+  return n * (dot(w, n) * eta_ti + cos_theta_t) - w * eta_ti;
+}
+
+ccl_device_inline float3 microfacet_visible_normal_sample(KernelGlobals kg,
+                                                          const bool beckmann,
+                                                          const float roughness,
+                                                          const float3 wi,
+                                                          const float randu,
+                                                          const float randv,
+                                                          ccl_private float *G1i)
+{
+  /* Step 1 : stretch wi */
+  float3 omega_i_ = normalize(make_float3(roughness * wi.x, roughness * wi.y, wi.z));
+
+  /* get polar coordinates of omega_i_ */
+  float costheta_ = 1.f;
+  float sintheta_ = 0.f;
+  float cosphi_ = 1.f;
+  float sinphi_ = 0.f;
+
+  if (omega_i_.z < 0.99999f) {
+    costheta_ = omega_i_.z;
+    sintheta_ = safe_sqrtf(1.f - costheta_ * costheta_);
+
+    float invlen = 1.f / sintheta_;
+    cosphi_ = omega_i_.x * invlen;
+    sinphi_ = omega_i_.y * invlen;
+  }
+
+  /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */
+  float slope_x, slope_y;
+
+  if (beckmann) {
+    microfacet_beckmann_sample_slopes(
+        kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i);
+  }
+  else {
+    microfacet_ggx_sample_slopes(costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i);
+  }
+
+  /* 3. rotate */
+  float tmp = cosphi_ * slope_x - sinphi_ * slope_y;
+  slope_y = sinphi_ * slope_x + cosphi_ * slope_y;
+  slope_x = tmp;
+
+  /* 4. unstretch */
+  slope_x = roughness * slope_x;
+  slope_y = roughness * slope_y;
+
+  /* 5. compute normal */
+  return normalize(make_float3(-slope_x, -slope_y, 1.f));
+}
+
+/* returns sin_theta */
+ccl_device_inline float sintheta(const float3 w)
+{
+  return w.y;
+}
+
+/* returns cos_theta */
+ccl_device_inline float costheta(const float3 w)
+{
+  return safe_sqrtf(sqr(w.x) + sqr(w.z));
+}
+
+/* returns tan_theta */
+ccl_device_inline float tantheta(const float3 w)
+{
+  return sintheta(w) / costheta(w);
+}
+
+/* extract theta coordinate from 3D direction
+ * -pi < theta < pi */
+ccl_device_inline float dir_theta(const float3 w)
+{
+  return atan2f(sintheta(w), costheta(w));
+}
+
+/* extract phi coordinate from 3D direction.
+ * -pi < phi < pi
+ * Assuming phi(wi

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list