Cycles: add random walk subsurface scattering to Principled BSDF.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Thu, 8 Feb 2018 15:19:04 +0000 (16:19 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 9 Feb 2018 18:58:42 +0000 (19:58 +0100)
Differential Revision: https://developer.blender.org/D3054

13 files changed:
intern/cycles/blender/addon/version_update.py
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/closure/bssrdf.h
intern/cycles/kernel/kernel_subsurface.h
intern/cycles/kernel/osl/osl_bssrdf.cpp
intern/cycles/kernel/shaders/node_principled_bsdf.osl
intern/cycles/kernel/svm/svm_closure.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
source/blender/editors/space_node/drawnode.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c

index 400d6dac4540ee78697c9aee9c1e613e95bc77b5..90cecec215df863cf3fb0eb026bdee08230e18d3 100644 (file)
@@ -130,10 +130,13 @@ def displacement_nodes_insert():
         if check_is_new_shading_material(material):
             displacement_node_insert(material, material.node_tree, traversed)
 
-def displacement_node_space(node):
+def displacement_principled_nodes(node):
     if node.bl_idname == 'ShaderNodeDisplacement':
         if node.space != 'WORLD':
             node.space = 'OBJECT'
+    if node.bl_idname == 'ShaderNodeBsdfPrincipled':
+        if node.subsurface_method != 'RANDOM_WALK':
+            node.subsurface_method = 'BURLEY'
 
 
 def mapping_node_order_flip(node):
@@ -372,4 +375,4 @@ def do_versions(self):
             if not cmat.is_property_set("displacement_method"):
                 cmat.displacement_method = 'BUMP'
 
-        foreach_cycles_node(displacement_node_space)
+        foreach_cycles_node(displacement_principled_nodes)
index d6f7a08431d32937de513c3f17b3b408a74ef1c8..33384709947ace9744615fb84dea8493188fec10 100644 (file)
@@ -535,6 +535,14 @@ static ShaderNode *add_node(Scene *scene,
                                principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
                                break;
                }
+               switch (b_principled_node.subsurface_method()) {
+                       case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
+                               principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_ID;
+                               break;
+                       case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
+                               principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID;
+                               break;
+               }
                node = principled;
        }
        else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
index 790368ee888b0cb3e330c07575b944691054881e..8578767b07ee21e70467e2d6dbe7b7db30936c38 100644 (file)
@@ -373,7 +373,9 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type)
        if(bssrdf_channels < 3) {
                /* Add diffuse BSDF if any radius too small. */
 #ifdef __PRINCIPLED__
-               if(type == CLOSURE_BSSRDF_PRINCIPLED_ID) {
+               if(type == CLOSURE_BSSRDF_PRINCIPLED_ID ||
+                  type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
+               {
                        float roughness = bssrdf->roughness;
                        float3 N = bssrdf->N;
 
@@ -409,7 +411,8 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type)
 
                if(type == CLOSURE_BSSRDF_BURLEY_ID ||
                   type == CLOSURE_BSSRDF_PRINCIPLED_ID ||
-                  type == CLOSURE_BSSRDF_RANDOM_WALK_ID)
+                  type == CLOSURE_BSSRDF_RANDOM_WALK_ID ||
+                  type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
                {
                        bssrdf_burley_setup(bssrdf);
                }
index a0dba7e13868574fc51da373bcd0cec059ff3690..80dda31c61e17c7931a5c71013291e4a7637c54f 100644 (file)
@@ -78,7 +78,9 @@ ccl_device void subsurface_scatter_setup_diffuse_bsdf(KernelGlobals *kg, ShaderD
        if(hit) {
                Bssrdf *bssrdf = (Bssrdf *)sc;
 #ifdef __PRINCIPLED__
-               if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID) {
+               if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID ||
+                  bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
+               {
                        PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight);
 
                        if(bsdf) {
index 907afe7d17a5e535fbcc4c23ab177049aee11af1..da7368bbc61fb78bf80d86435f81361e342fdda0 100644 (file)
@@ -53,6 +53,7 @@ static ustring u_gaussian("gaussian");
 static ustring u_burley("burley");
 static ustring u_principled("principled");
 static ustring u_random_walk("random_walk");
+static ustring u_principled_random_walk("principled_random_walk");
 
 class CBSSRDFClosure : public CClosurePrimitive {
 public:
@@ -83,6 +84,9 @@ public:
                else if (method == u_random_walk) {
                        alloc(sd, path_flag, weight, CLOSURE_BSSRDF_RANDOM_WALK_ID);
                }
+               else if (method == u_principled_random_walk) {
+                       alloc(sd, path_flag, weight, CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
+               }
        }
 
        void alloc(ShaderData *sd, int path_flag, float3 weight, ClosureType type)
index 0e31dcedee42361084d6d353144d4feb714c0666..fc0a1c894da0129e50b58c393af5722c9d00f514 100644 (file)
@@ -19,6 +19,7 @@
 
 shader node_principled_bsdf(
        string distribution = "Multiscatter GGX",
+       string subsurface_method = "burley",
        color BaseColor = color(0.8, 0.8, 0.8),
        float Subsurface = 0.0,
        vector SubsurfaceRadius = vector(1.0, 1.0, 1.0),
@@ -58,8 +59,14 @@ shader node_principled_bsdf(
        if (diffuse_weight > 1e-5) {
                if (Subsurface > 1e-5) {
                        color mixed_ss_base_color = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface);
-                       BSDF = mixed_ss_base_color * bssrdf("principled", Normal, Subsurface * SubsurfaceRadius, SubsurfaceColor, "roughness", Roughness);
-               } else {
+                       if (subsurface_method == "burley") {
+                               BSDF = mixed_ss_base_color * bssrdf("principled", Normal, Subsurface * SubsurfaceRadius, SubsurfaceColor, "roughness", Roughness);
+                       }
+                       else {
+                               BSDF = mixed_ss_base_color * bssrdf("principled_random_walk", Normal, Subsurface * SubsurfaceRadius, SubsurfaceColor, "roughness", Roughness);
+                       }
+               }
+               else {
                        BSDF = BaseColor * principled_diffuse(Normal, Roughness);
                }
 
index f013dc396d08a29b7ac0eb40ab841a3bb9d55659..fa43e1b60d0ef08a4a668a6aea068619469d7fb6 100644 (file)
@@ -114,7 +114,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
                        float transmission_roughness = stack_load_float(stack, transmission_roughness_offset);
                        float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
 
-                       ClosureType distribution = stack_valid(data_node2.y) ? (ClosureType) data_node2.y : CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
+                       ClosureType distribution = (ClosureType) data_node2.y;
+                       ClosureType subsurface_method = (ClosureType) data_node2.z;
 
                        /* rotate tangent */
                        if(anisotropic_rotation != 0.0f)
@@ -193,7 +194,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
                                                bssrdf->roughness = roughness;
 
                                                /* setup bsdf */
-                                               sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID);
+                                               sd->flag |= bssrdf_setup(sd, bssrdf, subsurface_method);
                                        }
                                }
                        }
@@ -781,6 +782,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
                                bssrdf->texture_blur = param2;
                                bssrdf->sharpness = stack_load_float(stack, data_node.w);
                                bssrdf->N = N;
+                               bssrdf->roughness = 0.0f;
                                sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)type);
                        }
 
index 9a87b4ee3586c6b7f772f35f5f9ae0776b0f0a7d..c0ce0f52cd0e6c18745c8187e29b3bb1c2bfebbc 100644 (file)
@@ -447,6 +447,7 @@ typedef enum ClosureType {
        CLOSURE_BSSRDF_PRINCIPLED_ID,
        CLOSURE_BSSRDF_BURLEY_ID,
        CLOSURE_BSSRDF_RANDOM_WALK_ID,
+       CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID,
 
        /* Other */
        CLOSURE_HOLDOUT_ID,
@@ -478,8 +479,8 @@ typedef enum ClosureType {
 #define CLOSURE_IS_BSDF_MICROFACET(type) ((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID) ||\
                                           (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) ||\
                                           (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID))
-#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_ID)
-#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_ID)
+#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
+#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID)
 #define CLOSURE_IS_DISK_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_BURLEY_ID)
 #define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
 #define CLOSURE_IS_VOLUME_SCATTER(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
index 7e8298e09c1939fa0cc65f96978b89d1f3529363..cb884ba9231614b004f3a75ece2838c712169d7d 100644 (file)
@@ -2312,6 +2312,12 @@ NODE_DEFINE(PrincipledBsdfNode)
        distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
        distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
        SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+
+       static NodeEnum subsurface_method_enum;
+       subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_PRINCIPLED_ID);
+       subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
+       SOCKET_ENUM(subsurface_method, "Subsurface Method", subsurface_method_enum, CLOSURE_BSSRDF_PRINCIPLED_ID);
+
        SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f));
        SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f));
        SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
@@ -2410,7 +2416,7 @@ void PrincipledBsdfNode::compile(SVMCompiler& compiler, ShaderInput *p_metallic,
                compiler.encode_uchar4(sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset));
 
        compiler.add_node(compiler.encode_uchar4(ior_offset, transmission_offset, anisotropic_rotation_offset, transmission_roughness_offset),
-               distribution, SVM_STACK_INVALID, SVM_STACK_INVALID);
+               distribution, subsurface_method, SVM_STACK_INVALID);
 
        float3 bc_default = get_float3(base_color_in->socket_type);
 
@@ -2442,6 +2448,7 @@ void PrincipledBsdfNode::compile(SVMCompiler& compiler)
 void PrincipledBsdfNode::compile(OSLCompiler& compiler)
 {
        compiler.parameter(this, "distribution");
+       compiler.parameter(this, "subsurface_method");
        compiler.add(this, "node_principled_bsdf");
 }
 
index a00b48ca5bcf4afe14c2f8bd92cd90894005da63..f664ebf545dab935b56fc2a29ef7b4ad9ae0d65c 100644 (file)
@@ -390,6 +390,7 @@ public:
        float3 normal, clearcoat_normal, tangent;
        float surface_mix_weight;
        ClosureType distribution, distribution_orig;
+       ClosureType subsurface_method;
 
        bool has_integrator_dependency();
        void attributes(Shader *shader, AttributeRequestSet *attributes);
index eccf3c057d457c1c94bb92e171deec13ca40536b..9d873795eaf9336911c5610bce39cf86ffa4effd 100644 (file)
@@ -1082,6 +1082,12 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point
        uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
 }
 
+static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+       uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE);
+}
+
 static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
@@ -1254,9 +1260,11 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                case SH_NODE_BSDF_GLOSSY:
                case SH_NODE_BSDF_GLASS:
                case SH_NODE_BSDF_REFRACTION:
-               case SH_NODE_BSDF_PRINCIPLED:
                        ntype->draw_buttons = node_shader_buts_glossy;
                        break;
+               case SH_NODE_BSDF_PRINCIPLED:
+                       ntype->draw_buttons = node_shader_buts_principled;
+                       break;
                case SH_NODE_BSDF_ANISOTROPIC:
                        ntype->draw_buttons = node_shader_buts_anisotropic;
                        break;
index bbe78d43f505e22b2f0289ca7f12d6a4dc6d37ea..ccd16e16760ff2d5d46ca2e11a8109c7f343f17c 100644 (file)
@@ -3293,11 +3293,18 @@ static const EnumPropertyItem node_script_mode_items[] = {
 };
 
 static const EnumPropertyItem node_principled_distribution_items[] = {
-       { SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" },
-       { SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" },
+       {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+       {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem node_subsurface_method_items[] = {
+       {SHD_SUBSURFACE_BURLEY, "BURLEY", 0, "Christensen-Burley", "Approximation to physically based volume scattering"},
+       {SHD_SUBSURFACE_RANDOM_WALK, "RANDOM_WALK", 0, "Random Walk", "Volumetric approximation to physically based volume scattering"},
        { 0, NULL, 0, NULL, NULL }
 };
 
+
 /* -- Common nodes ---------------------------------------------------------- */
 
 static void def_group_input(StructRNA *srna)
@@ -4241,6 +4248,12 @@ static void def_principled(StructRNA *srna)
        RNA_def_property_enum_items(prop, node_principled_distribution_items);
        RNA_def_property_ui_text(prop, "Distribution", "");
        RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
+
+       prop = RNA_def_property(srna, "subsurface_method", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "custom2");
+       RNA_def_property_enum_items(prop, node_subsurface_method_items);
+       RNA_def_property_ui_text(prop, "Subsurface Method", "Method for rendering subsurface scattering");
+       RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
 }
 
 static void def_refraction(StructRNA *srna)
index e0330d110ca162306efe666e8830550d2bb90759..cd83139dcaab3d20ed4f0f95a1128e77c13d5f17 100644 (file)
@@ -61,6 +61,7 @@ static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
 static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
 {
        node->custom1 = SHD_GLOSSY_MULTI_GGX;
+       node->custom2 = SHD_SUBSURFACE_BURLEY;
 }
 
 static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)