[Bf-blender-cvs] [7811c114723] cycles-x: Cycles X: add anisotropic random walk SSS

Christophe Hery noreply at git.blender.org
Tue Aug 17 19:52:40 CEST 2021


Commit: 7811c11472302948015b94137c8918f0292936d4
Author: Christophe Hery
Date:   Thu Aug 12 19:19:54 2021 +0200
Branches: cycles-x
https://developer.blender.org/rB7811c11472302948015b94137c8918f0292936d4

Cycles X: add anisotropic random walk SSS

This adds new Subsurface Anisotropy and IOR to the Principled BSDF and
Subsurface Scattering nodes. Real world skin has an anisotropy of around
0.8 and this makes it possible to simulate that more accurately.

Based on the paper: "Path Traced Subsurface Scattering using Anisotropic
Phase Functions and  Non-Exponential Free Flights"
https://graphics.pixar.com/library/PathTracedSubsurface/

This comes with a new albedo inversion that gives different results than
the old one. For that reason there is now a Random Walk and Random Walk
(Fixed Radius) option. The latter is provided for backwards compatibility,
and uses the radius exactly as specified. The new one adjust the radius
based on albedo and IOR.

Differential Revision: https://developer.blender.org/D11965

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

M	intern/cycles/blender/blender_shader.cpp
M	intern/cycles/kernel/closure/bssrdf.h
M	intern/cycles/kernel/integrator/integrator_state_template.h
M	intern/cycles/kernel/integrator/integrator_subsurface.h
M	intern/cycles/kernel/osl/osl_bssrdf.cpp
M	intern/cycles/kernel/shaders/node_principled_bsdf.osl
M	intern/cycles/kernel/shaders/node_subsurface_scattering.osl
M	intern/cycles/kernel/svm/svm_closure.h
M	intern/cycles/kernel/svm/svm_types.h
M	intern/cycles/render/nodes.cpp
M	intern/cycles/render/nodes.h
M	source/blender/blenloader/intern/versioning_300.c
M	source/blender/blenloader/intern/versioning_cycles.c
M	source/blender/editors/space_node/drawnode.cc
M	source/blender/gpu/intern/gpu_material_library.h
M	source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
M	source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.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/nodes/node_shader_bsdf_principled.c
M	source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c

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

diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 13d9f91b689..a1b4e24ac41 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -475,6 +475,15 @@ static ShaderNode *add_node(Scene *scene,
 
     SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
 
+    switch (b_subsurface_node.falloff()) {
+      case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
+        subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+        break;
+      case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
+        subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
+        break;
+    }
+
     node = subsurface;
   }
   else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
@@ -582,6 +591,14 @@ static ShaderNode *add_node(Scene *scene,
         principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
         break;
     }
+    switch (b_principled_node.subsurface_method()) {
+      case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
+        principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
+        break;
+      case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
+        principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
+        break;
+    }
     node = principled;
   }
   else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index 76f62845ea9..1f730c49713 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -24,16 +24,66 @@ typedef ccl_addr_space struct Bssrdf {
   float3 radius;
   float3 albedo;
   float roughness;
+  float anisotropy;
 } Bssrdf;
 
 static_assert(sizeof(ShaderClosure) >= sizeof(Bssrdf), "Bssrdf is too large!");
 
-/* Scale mean free path length so it gives similar looking result to older
- * to Cubic, Gaussian and Burley models.
- */
-ccl_device_inline float3 bssrdf_burley_compatible_mfp(float3 r)
+ccl_device float bssrdf_dipole_compute_Rd(float alpha_prime, float fourthirdA)
+{
+  float s = sqrtf(3.0f * (1.0f - alpha_prime));
+  return 0.5f * alpha_prime * (1.0f + expf(-fourthirdA * s)) * expf(-s);
+}
+
+ccl_device float bssrdf_dipole_compute_alpha_prime(float rd, float fourthirdA)
+{
+  /* Little Newton solver. */
+  if (rd < 1e-4f) {
+    return 0.0f;
+  }
+  if (rd >= 0.995f) {
+    return 0.999999f;
+  }
+
+  float x0 = 0.0f;
+  float x1 = 1.0f;
+  float xmid, fmid;
+
+  constexpr const int max_num_iterations = 12;
+  for (int i = 0; i < max_num_iterations; ++i) {
+    xmid = 0.5f * (x0 + x1);
+    fmid = bssrdf_dipole_compute_Rd(xmid, fourthirdA);
+    if (fmid < rd) {
+      x0 = xmid;
+    }
+    else {
+      x1 = xmid;
+    }
+  }
+
+  return xmid;
+}
+
+ccl_device void bssrdf_setup_radius(Bssrdf *bssrdf, const ClosureType type, const float eta)
 {
-  return 0.25f * M_1_PI_F * r;
+  /* Scale mean free path length so it gives similar looking result to older
+   * to Cubic, Gaussian and Burley models. */
+  bssrdf->radius *= 0.25f * M_1_PI_F;
+
+  if (type != CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) {
+    /* Adjust radius based on IOR and albedo. */
+    const float inv_eta = 1.0f / eta;
+    const float F_dr = inv_eta * (-1.440f * inv_eta + 0.710f) + 0.668f + 0.0636f * eta;
+    const float fourthirdA = (4.0f / 3.0f) * (1.0f + F_dr) /
+                             (1.0f - F_dr); /* From Jensen's Fdr ratio formula. */
+
+    const float3 alpha_prime = make_float3(
+        bssrdf_dipole_compute_alpha_prime(bssrdf->albedo.x, fourthirdA),
+        bssrdf_dipole_compute_alpha_prime(bssrdf->albedo.y, fourthirdA),
+        bssrdf_dipole_compute_alpha_prime(bssrdf->albedo.z, fourthirdA));
+
+    bssrdf->radius *= sqrt(3.0f * (one_float3() - alpha_prime));
+  }
 }
 
 /* Setup */
@@ -51,7 +101,7 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
   return (sample_weight >= CLOSURE_WEIGHT_CUTOFF) ? bssrdf : NULL;
 }
 
-ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type)
+ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, const float ior)
 {
   int flag = 0;
   int bssrdf_channels = 3;
@@ -112,8 +162,7 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type)
     bssrdf->type = type;
     bssrdf->sample_weight = fabsf(average(bssrdf->weight)) * bssrdf_channels;
 
-    /* Mean free path length. */
-    bssrdf->radius = bssrdf_burley_compatible_mfp(bssrdf->radius);
+    bssrdf_setup_radius(bssrdf, type, ior);
 
     flag |= SD_BSSRDF;
   }
diff --git a/intern/cycles/kernel/integrator/integrator_state_template.h b/intern/cycles/kernel/integrator/integrator_state_template.h
index e3b0d893290..be5bb97754a 100644
--- a/intern/cycles/kernel/integrator/integrator_state_template.h
+++ b/intern/cycles/kernel/integrator/integrator_state_template.h
@@ -98,6 +98,7 @@ KERNEL_STRUCT_END(isect)
 KERNEL_STRUCT_BEGIN(subsurface)
 KERNEL_STRUCT_MEMBER(subsurface, float3, albedo, KERNEL_FEATURE_SUBSURFACE)
 KERNEL_STRUCT_MEMBER(subsurface, float3, radius, KERNEL_FEATURE_SUBSURFACE)
+KERNEL_STRUCT_MEMBER(subsurface, float, anisotropy, KERNEL_FEATURE_SUBSURFACE)
 KERNEL_STRUCT_MEMBER(subsurface, float, roughness, KERNEL_FEATURE_SUBSURFACE)
 KERNEL_STRUCT_END(subsurface)
 
diff --git a/intern/cycles/kernel/integrator/integrator_subsurface.h b/intern/cycles/kernel/integrator/integrator_subsurface.h
index 5f00b4f22c7..a4f173e3009 100644
--- a/intern/cycles/kernel/integrator/integrator_subsurface.h
+++ b/intern/cycles/kernel/integrator/integrator_subsurface.h
@@ -67,6 +67,7 @@ ccl_device int subsurface_bounce(INTEGRATOR_STATE_ARGS, ShaderData *sd, const Sh
   INTEGRATOR_STATE_WRITE(subsurface, albedo) = bssrdf->albedo;
   INTEGRATOR_STATE_WRITE(subsurface, radius) = bssrdf->radius;
   INTEGRATOR_STATE_WRITE(subsurface, roughness) = bssrdf->roughness;
+  INTEGRATOR_STATE_WRITE(subsurface, anisotropy) = bssrdf->anisotropy;
 
   return LABEL_SUBSURFACE_SCATTER;
 }
@@ -123,25 +124,72 @@ ccl_device void subsurface_shader_data_setup(INTEGRATOR_STATE_ARGS, ShaderData *
  * "Practical and Controllable Subsurface Scattering for Production Path
  *  Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
 
-ccl_device void subsurface_random_walk_remap(const float A,
-                                             const float d,
-                                             float *sigma_t,
-                                             float *alpha)
+/* Support for anisotropy from:
+ * "Path Traced Subsurface Scattering using Anisotropic Phase Functions
+ * and Non-Exponential Free Flights".
+ * Magnus Wrenninge, Ryusuke Villemin, Christophe Hery.
+ * https://graphics.pixar.com/library/PathTracedSubsurface/ */
+
+ccl_device void subsurface_random_walk_remap(
+    const float albedo, const float d, float g, float *sigma_t, float *alpha)
 {
+  /* Not well defined for negative anisotropy, just clamp for now. */
+  g = fmaxf(g, 0.0f);
+
   /* Compute attenuation and scattering coefficients from albedo. */
-  *alpha = 1.0f - expf(A * (-5.09406f + A * (2.61188f - A * 4.31805f)));
-  *sigma_t = 1.0f / fmaxf(d, 1e-16f);
+  const float g2 = g * g;
+  const float g3 = g2 * g;
+  const float g4 = g3 * g;
+  const float g5 = g4 * g;
+  const float g6 = g5 * g;
+  const float g7 = g6 * g;
+
+  const float A = 1.8260523782f + -1.28451056436f * g + -1.79904629312f * g2 +
+                  9.19393289202f * g3 + -22.8215585862f * g4 + 32.0234874259f * g5 +
+                  -23.6264803333f * g6 + 7.21067002658f * g7;
+  const float B = 4.98511194385f +
+                  0.127355959438f *
+                      expf(31.1491581433f * g + -201.847017512f * g2 + 841.576016723f * g3 +
+                           -2018.09288505f * g4 + 2731.71560286f * g5 + -1935.41424244f * g6 +
+                           559.009054474f * g7);
+  const float C = 1.09686102424f + -0.394704063468f * g + 1.05258115941f * g2 +
+                  -8.83963712726f * g3 + 28.8643230661f * g4 + -46.8802913581f * g5 +
+                  38.5402837518f * g6 + -12.7181042538f * g7;
+  const float D = 0.496310210422f + 0.360146581622f * g + -2.15139309747f * g2 +
+                  17.8896899217f * g3 + -55.2984010333f * g4 + 82.065982243f * g5 +
+                  -58.5106008578f * g6 + 15.8478295021f * g7;
+  const float E = 4.23190299701f +
+                  0.00310603949088f *
+                      expf(76.7316253952f * g + -594.356773233f * g2 + 2448.8834203f * g3 +
+                           -5576.68528998f * g4 + 7116.60171912f * g5 + -4763.54467887f * g6 +
+                           1303.5318055f * g7);
+  const float F = 2.40602999408f + -2.51814844609f * g + 9.18494908356f * g2 +
+                  -79.2191708682f * g3 + 259.082868209f * g4 + -403.613804597f * g5 +
+                  302.85712436f * g6 + -87.4370473567f * g7;
+
+  const float blend = powf(albedo, 0.25f);
+
+  *alpha = (1.0f - blend) * A * powf(atanf(B * albedo), C) +
+           blend * D * powf(atanf(E * albedo), F);
+  *alpha = clamp(*alpha, 0.0f, 0.999999f);  // because of numerical precision
+
+  float sigma_t_prime = 1.0f / fmaxf(d, 1e-16f);
+  *sigma_t = sigma_t_prime / (1.0f - g);
 }
 
-ccl_device void subsurface_random_walk_coefficients(
-    const float3 albedo, const float3 radius, float3 *sigma_t, float3 *alpha, float3 *throughput)
+ccl_device void subsurface_random_walk_coefficients(const float3 albedo,
+                                                    const float3 radius,
+                                                    const float anisotropy,
+                                                    float3 *sigma_t,
+                                                    float3 *alpha,
+                                                    float3 *throughput)
 {
   float sigma_t_x, sigma_t_y, sigma_t_z;
   float alpha_x, alpha_y, alpha_z;
 
-  subsurface_random_walk_remap(albedo.x, radius.x, &sigma_t_x, &alpha_x);
-  subsurface_random_walk_remap(albedo.y, radius.y, &sigma_t_y, &alpha_y);
-  subsurfa

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list