Functional Definitions Notebook¶

The following notebook demonstrates how to create functional node definitions from non-functional ones in the MaterialX standard library. This includes inline both functional nodegrapsh as well as direct implementation references.

The version of MaterialX used include the proposed changes required to support this functionality in version 1.39.5.

In [1]:
import MaterialX as mx
# Import lib to display markdown cells
from IPython.display import Markdown, display

def print_markdown(text):
    display(Markdown(text))

print_markdown("- MaterialX version: " + mx.getVersionString())

def createTestDoc():
    doc : mx.Document = mx.createDocument()

    stdlib = mx.createDocument()
    libFiles = mx.loadLibraries(mx.getDefaultDataLibraryFolders(), mx.getDefaultDataSearchPath(), stdlib)  

    defs = stdlib.getNodeDefs()
    print_markdown(f"- Loaded: {len(defs)} node definitions from {len(libFiles)} library files")
    return doc, stdlib

doc, stdlib = createTestDoc()
  • MaterialX version: 1.39.5
  • Loaded: 803 node definitions from 60 library files

The follow code is a small wrapper around the C++ NodeDef::inlineImplementation() method which basically:

  • Removes any back-references to node definition (nodedef attribute)
  • Create a copy of the original implementation (for the given target) parented under the existing node definition
  • Returns the modified node definition
In [2]:
def make_functional_definition(test_name, target=''):
    test_def = stdlib.getNodeDef(test_name)
    if test_def:
        new_def = test_def.inlineImplementation(target)        
    return test_def

As the branch of code used currently does not contain support for this function yet, we write a Python version here.

In [3]:
def make_functional_definition_impl(test_name, target='', requireExclusive=False):
    """
    Add per-target implementations to a functional nodedef.
    """
    test_def = stdlib.getNodeDef(test_name)
    if test_def:
        shared_impl = test_def.hasSharedImplementation()

        if requireExclusive and shared_impl:
            print(f'Node definition uses a shared implementation. Skipping: {test_name}. Target: {target}')
            return None
        
        impl = None
        if shared_impl:
            unmapped = stdlib.getMatchingUnmappedImplementations(test_name)
            if len(unmapped) > 0:
                impl = unmapped[0] 

        if not impl:
            impl = test_def.getImplementation(target)
        if impl:
            new_impl = None
            new_impl_name = impl.getName()
            existing_child = test_def.getChild(new_impl_name)
            if existing_child:
                return test_def
            new_impl = test_def.addChildOfCategory(impl.getCategory(), new_impl_name)
            print(f'Add child implementation: {new_impl_name}. Target:  {impl.getTarget()}')
            if not new_impl:
                print("Failed to create new functional def child:", new_impl_name)
                return None
            else:   
                # Copy over implementation content without the nodedef back-reference.
                impl.removeAttribute(mx.InterfaceElement.NODE_DEF_ATTRIBUTE)
                new_impl.copyContentFrom(impl)
            
    return test_def

Examples¶

This following examples inline implementations by:

  • Iterating over all target definitions in the standard library.
  • Inline the implementation for each target.

The result is the accumulation of all target-specific implementations directly under the node definition.

Inline the functional nodegraph for the tiledimage definition.¶

In [4]:
def test_inline(test_nam, requireExclusive=False):
    print_markdown(f"##### Converting node definition: `{test_name}`")

    targetDefs = stdlib.getTargetDefs()
    test_def = stdlib.getNodeDef(test_name)
    display(Markdown('**Original definition**'))
    display(Markdown("```xml\n" + mx.prettyPrint(test_def) + "\n```"))

    test_def = None
    for targetDef in targetDefs:
        #print("> Adding target:", targetDef.getName())
        test_def = make_functional_definition_impl(test_name, targetDef.getName(), requireExclusive=requireExclusive)

    if test_def:
        display(Markdown("**New functional node definition**"))
        display(Markdown("```xml\n" + mx.prettyPrint(test_def) + "\n```"))

    if test_def:
        display(Markdown("##### New functional node definition:"))
        display(Markdown("```xml\n" + mx.prettyPrint(test_def) + "\n```"))

test_name = "ND_tiledimage_color3"
test_def = test_inline(test_name)
Converting node definition: ND_tiledimage_color3¶

Original definition

<nodedef name="ND_tiledimage_color3" node="tiledimage" nodegroup="texture2d">
  <input name="file" type="filename" value="" uniform="true">
  <input name="default" type="color3" value="0.0, 0.0, 0.0">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0">
  <input name="uvtiling" type="vector2" value="1.0, 1.0">
  <input name="uvoffset" type="vector2" value="0.0, 0.0">
  <input name="realworldimagesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="realworldtilesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uniform="true">
  <input name="framerange" type="string" value="" uniform="true">
  <input name="frameoffset" type="integer" value="0" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uniform="true">
  <output name="out" type="color3" default="0.0, 0.0, 0.0">
Add child implementation: NG_tiledimage_color3. Target:  

New functional node definition

<nodedef name="ND_tiledimage_color3" node="tiledimage" nodegroup="texture2d">
  <input name="file" type="filename" value="" uniform="true">
  <input name="default" type="color3" value="0.0, 0.0, 0.0">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0">
  <input name="uvtiling" type="vector2" value="1.0, 1.0">
  <input name="uvoffset" type="vector2" value="0.0, 0.0">
  <input name="realworldimagesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="realworldtilesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uniform="true">
  <input name="framerange" type="string" value="" uniform="true">
  <input name="frameoffset" type="integer" value="0" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uniform="true">
  <output name="out" type="color3" default="0.0, 0.0, 0.0">
  <nodegraph name="NG_tiledimage_color3">
    <multiply name="N_mult_color3" type="vector2">
      <input name="in1" type="vector2" interfacename="texcoord">
      <input name="in2" type="vector2" interfacename="uvtiling">
    <subtract name="N_sub_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_mult_color3">
      <input name="in2" type="vector2" interfacename="uvoffset">
    <divide name="N_divtilesize_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_sub_color3">
      <input name="in2" type="vector2" interfacename="realworldimagesize">
    <multiply name="N_multtilesize_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_divtilesize_color3">
      <input name="in2" type="vector2" interfacename="realworldtilesize">
    <image name="N_img_color3" type="color3">
      <input name="file" type="filename" interfacename="file">
      <input name="default" type="color3" interfacename="default">
      <input name="texcoord" type="vector2" nodename="N_multtilesize_color3">
      <input name="uaddressmode" type="string" value="periodic">
      <input name="vaddressmode" type="string" value="periodic">
      <input name="filtertype" type="string" interfacename="filtertype">
      <input name="framerange" type="string" interfacename="framerange">
      <input name="frameoffset" type="integer" interfacename="frameoffset">
      <input name="frameendaction" type="string" interfacename="frameendaction">
    <output name="out" type="color3" nodename="N_img_color3">
New functional node definition:¶
<nodedef name="ND_tiledimage_color3" node="tiledimage" nodegroup="texture2d">
  <input name="file" type="filename" value="" uniform="true">
  <input name="default" type="color3" value="0.0, 0.0, 0.0">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0">
  <input name="uvtiling" type="vector2" value="1.0, 1.0">
  <input name="uvoffset" type="vector2" value="0.0, 0.0">
  <input name="realworldimagesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="realworldtilesize" type="vector2" value="1.0, 1.0" unittype="distance">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uniform="true">
  <input name="framerange" type="string" value="" uniform="true">
  <input name="frameoffset" type="integer" value="0" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uniform="true">
  <output name="out" type="color3" default="0.0, 0.0, 0.0">
  <nodegraph name="NG_tiledimage_color3">
    <multiply name="N_mult_color3" type="vector2">
      <input name="in1" type="vector2" interfacename="texcoord">
      <input name="in2" type="vector2" interfacename="uvtiling">
    <subtract name="N_sub_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_mult_color3">
      <input name="in2" type="vector2" interfacename="uvoffset">
    <divide name="N_divtilesize_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_sub_color3">
      <input name="in2" type="vector2" interfacename="realworldimagesize">
    <multiply name="N_multtilesize_color3" type="vector2">
      <input name="in1" type="vector2" nodename="N_divtilesize_color3">
      <input name="in2" type="vector2" interfacename="realworldtilesize">
    <image name="N_img_color3" type="color3">
      <input name="file" type="filename" interfacename="file">
      <input name="default" type="color3" interfacename="default">
      <input name="texcoord" type="vector2" nodename="N_multtilesize_color3">
      <input name="uaddressmode" type="string" value="periodic">
      <input name="vaddressmode" type="string" value="periodic">
      <input name="filtertype" type="string" interfacename="filtertype">
      <input name="framerange" type="string" interfacename="framerange">
      <input name="frameoffset" type="integer" interfacename="frameoffset">
      <input name="frameendaction" type="string" interfacename="frameendaction">
    <output name="out" type="color3" nodename="N_img_color3">

Inline non-graph implementations for the image definition.¶

In [5]:
test_name = "ND_image_float"
test_def = test_inline(test_name)
Converting node definition: ND_image_float¶

Original definition

<nodedef name="ND_image_float" node="image" nodegroup="texture2d">
  <input name="file" type="filename" value="" uiname="Filename" uniform="true">
  <input name="layer" type="string" value="" uiname="Layer" uniform="true">
  <input name="default" type="float" value="0.0" uiname="Default Color">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0" uiname="Texture Coordinates">
  <input name="uaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode U" uniform="true">
  <input name="vaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode V" uniform="true">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uiname="Filter Type" uniform="true">
  <input name="framerange" type="string" value="" uiname="Frame Range" uniform="true">
  <input name="frameoffset" type="integer" value="0" uiname="Frame Offset" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uiname="Frame End Action" uniform="true">
  <output name="out" type="float" default="0.0">
Add child implementation: IM_image_float_genglsl. Target:  genglsl
Add child implementation: IM_image_float_genmdl. Target:  genmdl
Add child implementation: IM_image_float_genmsl. Target:  genmsl
Add child implementation: IM_image_float_genosl. Target:  genosl
Add child implementation: IM_image_float_genslang. Target:  genslang

New functional node definition

<nodedef name="ND_image_float" node="image" nodegroup="texture2d">
  <input name="file" type="filename" value="" uiname="Filename" uniform="true">
  <input name="layer" type="string" value="" uiname="Layer" uniform="true">
  <input name="default" type="float" value="0.0" uiname="Default Color">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0" uiname="Texture Coordinates">
  <input name="uaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode U" uniform="true">
  <input name="vaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode V" uniform="true">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uiname="Filter Type" uniform="true">
  <input name="framerange" type="string" value="" uiname="Frame Range" uniform="true">
  <input name="frameoffset" type="integer" value="0" uiname="Frame Offset" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uiname="Frame End Action" uniform="true">
  <output name="out" type="float" default="0.0">
  <implementation name="IM_image_float_genglsl" file="mx_image_float.glsl" function="mx_image_float" target="genglsl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genmdl" sourcecode="materialx::stdlib_{{MDL_VERSION_SUFFIX}}::mx_image_float({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genmsl" file="../genglsl/mx_image_float.glsl" function="mx_image_float" target="genmsl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genosl" file="mx_image_float.osl" function="mx_image_float" target="genosl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genslang" file="../genglsl/mx_image_float.glsl" function="mx_image_float" target="genslang">
    <input name="default" type="float" implname="default_value">
New functional node definition:¶
<nodedef name="ND_image_float" node="image" nodegroup="texture2d">
  <input name="file" type="filename" value="" uiname="Filename" uniform="true">
  <input name="layer" type="string" value="" uiname="Layer" uniform="true">
  <input name="default" type="float" value="0.0" uiname="Default Color">
  <input name="texcoord" type="vector2" defaultgeomprop="UV0" uiname="Texture Coordinates">
  <input name="uaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode U" uniform="true">
  <input name="vaddressmode" type="string" value="periodic" enum="constant,clamp,periodic,mirror" uiname="Address Mode V" uniform="true">
  <input name="filtertype" type="string" value="linear" enum="closest,linear,cubic" uiname="Filter Type" uniform="true">
  <input name="framerange" type="string" value="" uiname="Frame Range" uniform="true">
  <input name="frameoffset" type="integer" value="0" uiname="Frame Offset" uniform="true">
  <input name="frameendaction" type="string" value="constant" enum="constant,clamp,periodic,mirror" uiname="Frame End Action" uniform="true">
  <output name="out" type="float" default="0.0">
  <implementation name="IM_image_float_genglsl" file="mx_image_float.glsl" function="mx_image_float" target="genglsl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genmdl" sourcecode="materialx::stdlib_{{MDL_VERSION_SUFFIX}}::mx_image_float({{file}}, {{layer}}, {{default}}, {{texcoord}}, {{uaddressmode}}, {{vaddressmode}}, {{filtertype}}, {{framerange}}, {{frameoffset}}, {{frameendaction}}, mxp_flip_v:{{flip_v}})" target="genmdl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genmsl" file="../genglsl/mx_image_float.glsl" function="mx_image_float" target="genmsl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genosl" file="mx_image_float.osl" function="mx_image_float" target="genosl">
    <input name="default" type="float" implname="default_value">
  <implementation name="IM_image_float_genslang" file="../genglsl/mx_image_float.glsl" function="mx_image_float" target="genslang">
    <input name="default" type="float" implname="default_value">

This is another example which inline the implementations for the position definition.

In this case we have a mix of source code and externally referenced implementations. The result is again a functional node definition with all implementations inlined.

In [6]:
test_name = "ND_position_vector3"
test_def = test_inline(test_name)
Converting node definition: ND_position_vector3¶

Original definition

<nodedef name="ND_position_vector3" node="position" nodegroup="geometric">
  <input name="space" type="string" value="object" enum="model,object,world" uniform="true">
  <output name="out" type="vector3" default="0.0, 0.0, 0.0">
Add child implementation: IM_position_vector3_genglsl. Target:  genglsl
Add child implementation: IM_position_vector3_genmdl. Target:  genmdl
Add child implementation: IM_position_vector3_genmsl. Target:  genmsl
Add child implementation: IM_position_vector3_genosl. Target:  genosl
Add child implementation: IM_position_vector3_genslang. Target:  genslang

New functional node definition

<nodedef name="ND_position_vector3" node="position" nodegroup="geometric">
  <input name="space" type="string" value="object" enum="model,object,world" uniform="true">
  <output name="out" type="vector3" default="0.0, 0.0, 0.0">
  <implementation name="IM_position_vector3_genglsl" target="genglsl">
  <implementation name="IM_position_vector3_genmdl" sourcecode="materialx::stdlib_{{MDL_VERSION_SUFFIX}}::mx_position_vector3(mxp_space:{{space}})" target="genmdl">
  <implementation name="IM_position_vector3_genmsl" target="genmsl">
  <implementation name="IM_position_vector3_genosl" target="genosl" sourcecode="transform({{space}}, P)">
  <implementation name="IM_position_vector3_genslang" target="genslang">
New functional node definition:¶
<nodedef name="ND_position_vector3" node="position" nodegroup="geometric">
  <input name="space" type="string" value="object" enum="model,object,world" uniform="true">
  <output name="out" type="vector3" default="0.0, 0.0, 0.0">
  <implementation name="IM_position_vector3_genglsl" target="genglsl">
  <implementation name="IM_position_vector3_genmdl" sourcecode="materialx::stdlib_{{MDL_VERSION_SUFFIX}}::mx_position_vector3(mxp_space:{{space}})" target="genmdl">
  <implementation name="IM_position_vector3_genmsl" target="genmsl">
  <implementation name="IM_position_vector3_genosl" target="genosl" sourcecode="transform({{space}}, P)">
  <implementation name="IM_position_vector3_genslang" target="genslang">

Inheritance and Shared Implementations¶

Some node definitions inherit their implementations from parent definitions.

The followiing utility shows how to traverse through inheritance to find the definitions and the associated implementations. Additionally there is a check to find out which implementations are directly references and which are indirectly referenced via <implementation> elements.

In [7]:
def get_matching_definitions(def_name):
    check_nodedef = stdlib.getNodeDef(def_name)
    nodegraph_counts = {}  # Will store {nodegraph: count}
    nodegraph_nodedefs = {}  # Will store {nodegraph: set(nodedefs)}
    mapped_inheritance_tree_nodedefs = []
    if check_nodedef:
        print("-"*80)
        print(f"Example hierarhy for: {check_nodedef.getName()}")

        # Traverse inheritance to find all matching definitions
        inheritance_tree_nodedefs = check_nodedef.getMatchingDefinitions()
        print("* number of definitions in inheritance tree:", len(inheritance_tree_nodedefs))
        for ndstring in inheritance_tree_nodedefs:
            nd = stdlib.getNodeDef(ndstring)
            if nd:
                inheritance_string = nd.getInheritString()
                if not inheritance_string:
                    inheritance_string = "<NONE>"
                print("  Scan definition:", ndstring, " version:", nd.getVersionString(), " inherits from:", inheritance_string)

                # See if there are any indirect mappings
                for impl in stdlib.getMatchingUnmappedImplementations(ndstring):
                    if not impl.isA(mx.NodeGraph):
                        nodegraph_string = impl.getAttribute("nodegraph")
                        if nodegraph_string:
                            print("- Found intermediate mapping implementation", impl.getName(), "redirecting to nodegraph:", nodegraph_string)
                        else:
                            print("- Found intermediate mapping implementations", impl.getName())
                        mapped_inheritance_tree_nodedefs.append(nd)
                        #print(mx.prettyPrint(impl))

                impl = nd.getImplementation()
                if impl.isA(mx.NodeGraph):
                    print("  Implementation name:", impl.getName()) 

                    # Check if there is an indirect mapping to get to this nodegraph
                    #
                    if mapped_inheritance_tree_nodedefs:
                        for other in mapped_inheritance_tree_nodedefs:
                            if other.getAttribute("nodegraph") == impl.getName():
                                print(f"   (nodegraph acessed via {other.getName()} implementation redirection !)") 
                else: 
                    # >>> Code to handle regression (not required anymore after new cache change)          
                    nodegraph_name = None
                    nodegraph_string = impl.getAttribute("nodegraph")
                    if nodegraph_string:
                        impl = stdlib.getNodeGraph(nodegraph_string)
                        nodegraph_name = nodegraph_string
                    if nodegraph_name:
                        # Count usage of each nodegraph
                        if nodegraph_name in nodegraph_counts:
                            nodegraph_counts[nodegraph_name] += 1
                        else:
                            nodegraph_counts[nodegraph_name] = 1
                        # Track which nodedefs use this nodegraph
                        if nodegraph_name not in nodegraph_nodedefs:
                            nodegraph_nodedefs[nodegraph_name] = set()
                        nodegraph_nodedefs[nodegraph_name].add(ndstring)
                    if impl and impl.isA(mx.NodeGraph):
                        print("  mapped implementation:", impl.getName())



get_matching_definitions("ND_UsdUVTexture")
get_matching_definitions("ND_standard_surface_surfaceshader")
--------------------------------------------------------------------------------
Example hierarhy for: ND_UsdUVTexture
* number of definitions in inheritance tree: 2
  Scan definition: ND_UsdUVTexture  version: 2.2  inherits from: ND_UsdUVTexture_23
  Implementation name: IMP_UsdUVTexture_22
  Scan definition: ND_UsdUVTexture_23  version: 2.3  inherits from: <NONE>
  Implementation name: IMP_UsdUVTexture_23
--------------------------------------------------------------------------------
Example hierarhy for: ND_standard_surface_surfaceshader
* number of definitions in inheritance tree: 2
  Scan definition: ND_standard_surface_surfaceshader  version: 1.0.1  inherits from: ND_standard_surface_surfaceshader_100
- Found intermediate mapping implementation IMPL_standard_surface_surfaceshader_101 redirecting to nodegraph: NG_standard_surface_surfaceshader_100
- Found intermediate mapping implementation IMPL_standard_surface_surfaceshader_optim redirecting to nodegraph: NG_standard_surface_surfaceshader_optim
  Implementation name: NG_standard_surface_surfaceshader_100
  Scan definition: ND_standard_surface_surfaceshader_100  version: 1.0.0  inherits from: <NONE>
- Found intermediate mapping implementation IMPL_standard_surface_surfaceshader_100 redirecting to nodegraph: NG_standard_surface_surfaceshader_100
  Implementation name: NG_standard_surface_surfaceshader_100

The above scan implicitly shows that the standard_surface_surfaceshader node definition reuses an implementation NG_standard_surface_surfaceshader_100.

A more direct way to check is to scan through the "unmapped" implementations cached in a a library using the Document::getMatchingUnmappedDefinitions() method. Code to get both the direct and indirect references is shown below.

In [8]:
indirect_mapped_nodedefs = []
direct_mapped_nodedefs = []

for nd in stdlib.getNodeDefs():
    nd_name = nd.getName()
    direct_mapped_nodedefs.append(stdlib.getMatchingImplementations(nd_name))
    unmapped = stdlib.getMatchingUnmappedImplementations(nd_name)
    for impl in unmapped:
        if not impl.isA(mx.NodeGraph):
            if impl.getAttribute("nodegraph"):
                indirect_mapped_nodedefs.append(impl)

print("Number of indirectly mapped nodedefs:", len(indirect_mapped_nodedefs))
for impl in indirect_mapped_nodedefs:
    print("  Indirect mapping implementation:", impl.getName(), " to nodegraph:", impl.getAttribute("nodegraph"))
print("Number of directly mapped nodedefs:", len(direct_mapped_nodedefs) - len(indirect_mapped_nodedefs))
Number of indirectly mapped nodedefs: 3
  Indirect mapping implementation: IMPL_standard_surface_surfaceshader_101  to nodegraph: NG_standard_surface_surfaceshader_100
  Indirect mapping implementation: IMPL_standard_surface_surfaceshader_optim  to nodegraph: NG_standard_surface_surfaceshader_optim
  Indirect mapping implementation: IMPL_standard_surface_surfaceshader_100  to nodegraph: NG_standard_surface_surfaceshader_100
Number of directly mapped nodedefs: 800

Inlining shared implementations¶

Though it is possible to inline shared implementations this results in duplication of the same implementation across multiple node definitions. The following shows the current behaviour which is to prevent inlining if the inlining option requireExclusive is set to True.

In [9]:
test_name = 'ND_standard_surface_surfaceshader'
test_inline(test_name, requireExclusive=True)
Converting node definition: ND_standard_surface_surfaceshader¶

Original definition

<nodedef name="ND_standard_surface_surfaceshader" node="standard_surface" nodegroup="pbr" version="1.0.1" isdefaultversion="true" inherit="ND_standard_surface_surfaceshader_100" doc="Autodesk standard surface shader">
  <input name="base" type="float" value="1.0" uimin="0.0" uimax="1.0" uiname="Base" uifolder="Base" doc="Multiplier on the intensity of the diffuse reflection.">
  <input name="base_color" type="color3" value="0.8, 0.8, 0.8" uimin="0,0,0" uimax="1,1,1" uiname="Base Color" uifolder="Base" doc="Color of the diffuse reflection.">
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: essl
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genglsl
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genmdl
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genmsl
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genosl
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genoslnetwork
Node definition uses a shared implementation. Skipping: ND_standard_surface_surfaceshader. Target: genslang

The following shows an alternative is to instead only inline the <implementation> reference itself, thus keeping the shared implementation intact. Note that both a direct (nodegraph) and indirect (implemetnation) reference is inlined in this case.

In [10]:
test_name = 'ND_standard_surface_surfaceshader'
test_inline(test_name, requireExclusive=False)
Converting node definition: ND_standard_surface_surfaceshader¶

Original definition

<nodedef name="ND_standard_surface_surfaceshader" node="standard_surface" nodegroup="pbr" version="1.0.1" isdefaultversion="true" inherit="ND_standard_surface_surfaceshader_100" doc="Autodesk standard surface shader">
  <input name="base" type="float" value="1.0" uimin="0.0" uimax="1.0" uiname="Base" uifolder="Base" doc="Multiplier on the intensity of the diffuse reflection.">
  <input name="base_color" type="color3" value="0.8, 0.8, 0.8" uimin="0,0,0" uimax="1,1,1" uiname="Base Color" uifolder="Base" doc="Color of the diffuse reflection.">
Add child implementation: IMPL_standard_surface_surfaceshader_101. Target:  
Add child implementation: NG_standard_surface_surfaceshader_optim. Target:  genglsl

New functional node definition

<nodedef name="ND_standard_surface_surfaceshader" node="standard_surface" nodegroup="pbr" version="1.0.1" isdefaultversion="true" inherit="ND_standard_surface_surfaceshader_100" doc="Autodesk standard surface shader">
  <input name="base" type="float" value="1.0" uimin="0.0" uimax="1.0" uiname="Base" uifolder="Base" doc="Multiplier on the intensity of the diffuse reflection.">
  <input name="base_color" type="color3" value="0.8, 0.8, 0.8" uimin="0,0,0" uimax="1,1,1" uiname="Base Color" uifolder="Base" doc="Color of the diffuse reflection.">
  <implementation name="IMPL_standard_surface_surfaceshader_101" nodegraph="NG_standard_surface_surfaceshader_100">
  <nodegraph name="NG_standard_surface_surfaceshader_optim" target="genglsl">
    <multiply name="coat_affect_roughness_multiply1" type="float">
      <input name="in1" type="float" interfacename="coat_affect_roughness">
      <input name="in2" type="float" interfacename="coat">
    <multiply name="coat_affect_roughness_multiply2" type="float">
      <input name="in1" type="float" nodename="coat_affect_roughness_multiply1">
      <input name="in2" type="float" interfacename="coat_roughness">
    <mix name="coat_affected_roughness" type="float">
      <input name="fg" type="float" value="1.0">
      <input name="bg" type="float" interfacename="specular_roughness">
      <input name="mix" type="float" nodename="coat_affect_roughness_multiply2">
    <roughness_anisotropy name="main_roughness" type="vector2">
      <input name="roughness" type="float" nodename="coat_affected_roughness">
      <input name="anisotropy" type="float" interfacename="specular_anisotropy">
    <add name="transmission_roughness_add" type="float">
      <input name="in1" type="float" interfacename="specular_roughness">
      <input name="in2" type="float" interfacename="transmission_extra_roughness">
    <clamp name="transmission_roughness_clamped" type="float">
      <input name="in" type="float" nodename="transmission_roughness_add">
    <mix name="coat_affected_transmission_roughness" type="float">
      <input name="fg" type="float" value="1.0">
      <input name="bg" type="float" nodename="transmission_roughness_clamped">
      <input name="mix" type="float" nodename="coat_affect_roughness_multiply2">
    <roughness_anisotropy name="transmission_roughness" type="vector2">
      <input name="roughness" type="float" nodename="coat_affected_transmission_roughness">
      <input name="anisotropy" type="float" interfacename="specular_anisotropy">
    <multiply name="tangent_rotate_degree" type="float">
      <input name="in1" type="float" interfacename="specular_rotation">
      <input name="in2" type="float" value="360">
    <rotate3d name="tangent_rotate" type="vector3">
      <input name="in" type="vector3" interfacename="tangent">
      <input name="amount" type="float" nodename="tangent_rotate_degree">
      <input name="axis" type="vector3" interfacename="normal">
    <normalize name="tangent_rotate_normalize" type="vector3">
      <input name="in" type="vector3" nodename="tangent_rotate">
    <ifgreater name="main_tangent" type="vector3">
      <input name="value1" type="float" interfacename="specular_anisotropy">
      <input name="value2" type="float" value="0.0">
      <input name="in1" type="vector3" nodename="tangent_rotate_normalize">
      <input name="in2" type="vector3" interfacename="tangent">
    <multiply name="coat_tangent_rotate_degree" type="float">
      <input name="in1" type="float" interfacename="coat_rotation">
      <input name="in2" type="float" value="360">
    <rotate3d name="coat_tangent_rotate" type="vector3">
      <input name="in" type="vector3" interfacename="tangent">
      <input name="amount" type="float" nodename="coat_tangent_rotate_degree">
      <input name="axis" type="vector3" interfacename="coat_normal">
    <normalize name="coat_tangent_rotate_normalize" type="vector3">
      <input name="in" type="vector3" nodename="coat_tangent_rotate">
    <ifgreater name="coat_tangent" type="vector3">
      <input name="value1" type="float" interfacename="coat_anisotropy">
      <input name="value2" type="float" value="0.0">
      <input name="in1" type="vector3" nodename="coat_tangent_rotate_normalize">
      <input name="in2" type="vector3" interfacename="tangent">
    <clamp name="coat_clamped" type="float">
      <input name="in" type="float" interfacename="coat">
    <multiply name="coat_gamma_multiply" type="float">
      <input name="in1" type="float" nodename="coat_clamped">
      <input name="in2" type="float" interfacename="coat_affect_color">
    <add name="coat_gamma" type="float">
      <input name="in1" type="float" nodename="coat_gamma_multiply">
      <input name="in2" type="float" value="1.0">
    <max name="base_color_nonnegative" type="color3">
      <input name="in1" type="color3" interfacename="base_color">
      <input name="in2" type="float" value="0.0">
    <power name="coat_affected_diffuse_color" type="color3">
      <input name="in1" type="color3" nodename="base_color_nonnegative">
      <input name="in2" type="float" nodename="coat_gamma">
    <max name="subsurface_color_nonnegative" type="color3">
      <input name="in1" type="color3" interfacename="subsurface_color">
      <input name="in2" type="float" value="0.0">
    <power name="coat_affected_subsurface_color" type="color3">
      <input name="in1" type="color3" nodename="subsurface_color_nonnegative">
      <input name="in2" type="float" nodename="coat_gamma">
    <oren_nayar_diffuse_bsdf name="diffuse_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="base">
      <input name="color" type="color3" nodename="coat_affected_diffuse_color">
      <input name="roughness" type="float" interfacename="diffuse_roughness">
      <input name="normal" type="vector3" interfacename="normal">
    <translucent_bsdf name="translucent_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="subsurface">
      <input name="color" type="color3" nodename="coat_affected_subsurface_color">
      <input name="normal" type="vector3" interfacename="normal">
    <multiply name="subsurface_radius_scaled" type="color3">
      <input name="in1" type="color3" interfacename="subsurface_radius">
      <input name="in2" type="float" interfacename="subsurface_scale">
    <subsurface_bsdf name="subsurface_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="subsurface">
      <input name="color" type="color3" nodename="coat_affected_subsurface_color">
      <input name="radius" type="color3" nodename="subsurface_radius_scaled">
      <input name="anisotropy" type="float" interfacename="subsurface_anisotropy">
      <input name="normal" type="vector3" interfacename="normal">
    <convert name="subsurface_selector" type="float">
      <input name="in" type="boolean" interfacename="thin_walled">
    <mix name="selected_subsurface_bsdf" type="BSDF">
      <input name="fg" type="BSDF" nodename="translucent_bsdf">
      <input name="bg" type="BSDF" nodename="subsurface_bsdf">
      <input name="mix" type="float" nodename="subsurface_selector">
    <invert name="subsurface_inv" type="float">
      <input name="in" type="float" interfacename="subsurface">
    <multiply name="diffuse_bsdf_non_subsurface" type="BSDF">
      <input name="in1" type="BSDF" nodename="diffuse_bsdf">
      <input name="in2" type="float" nodename="subsurface_inv">
    <add name="subsurface_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="selected_subsurface_bsdf">
      <input name="in2" type="BSDF" nodename="diffuse_bsdf_non_subsurface">
    <sheen_bsdf name="sheen_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="sheen">
      <input name="color" type="color3" interfacename="sheen_color">
      <input name="roughness" type="float" interfacename="sheen_roughness">
      <input name="normal" type="vector3" interfacename="normal">
    <layer name="sheen_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="sheen_bsdf">
      <input name="base" type="BSDF" nodename="subsurface_blend">
    <dielectric_bsdf name="transmission_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="transmission">
      <input name="tint" type="color3" interfacename="transmission_color">
      <input name="ior" type="float" interfacename="specular_IOR">
      <input name="roughness" type="vector2" nodename="transmission_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="T">
    <invert name="transmission_inv" type="float">
      <input name="in" type="float" interfacename="transmission">
    <multiply name="sheen_layer_non_transmission" type="BSDF">
      <input name="in1" type="BSDF" nodename="sheen_layer">
      <input name="in2" type="float" nodename="transmission_inv">
    <add name="transmission_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="transmission_bsdf">
      <input name="in2" type="BSDF" nodename="sheen_layer_non_transmission">
    <dielectric_bsdf name="specular_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="specular">
      <input name="tint" type="color3" interfacename="specular_color">
      <input name="ior" type="float" interfacename="specular_IOR">
      <input name="roughness" type="vector2" nodename="main_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="R">
      <input name="thinfilm_thickness" type="float" interfacename="thin_film_thickness">
      <input name="thinfilm_ior" type="float" interfacename="thin_film_IOR">
    <layer name="specular_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="specular_bsdf">
      <input name="base" type="BSDF" nodename="transmission_blend">
    <multiply name="metal_reflectivity" type="color3">
      <input name="in1" type="color3" interfacename="base_color">
      <input name="in2" type="float" interfacename="base">
    <multiply name="metal_edgecolor" type="color3">
      <input name="in1" type="color3" interfacename="specular_color">
      <input name="in2" type="float" interfacename="specular">
    <artistic_ior name="artistic_ior" type="multioutput">
      <input name="reflectivity" type="color3" nodename="metal_reflectivity">
      <input name="edge_color" type="color3" nodename="metal_edgecolor">
    <conductor_bsdf name="metal_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="metalness">
      <input name="ior" type="color3" nodename="artistic_ior" output="ior">
      <input name="extinction" type="color3" nodename="artistic_ior" output="extinction">
      <input name="roughness" type="vector2" nodename="main_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="thinfilm_thickness" type="float" interfacename="thin_film_thickness">
      <input name="thinfilm_ior" type="float" interfacename="thin_film_IOR">
    <invert name="metalness_inv" type="float">
      <input name="in" type="float" interfacename="metalness">
    <multiply name="specular_layer_non_metal" type="BSDF">
      <input name="in1" type="BSDF" nodename="specular_layer">
      <input name="in2" type="float" nodename="metalness_inv">
    <add name="metalness_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="metal_bsdf">
      <input name="in2" type="BSDF" nodename="specular_layer_non_metal">
    <mix name="coat_attenuation" type="color3">
      <input name="fg" type="color3" interfacename="coat_color">
      <input name="bg" type="color3" value="1.0, 1.0, 1.0">
      <input name="mix" type="float" interfacename="coat">
    <multiply name="thin_film_layer_attenuated" type="BSDF">
      <input name="in1" type="BSDF" nodename="metalness_blend">
      <input name="in2" type="color3" nodename="coat_attenuation">
    <roughness_anisotropy name="coat_roughness_vector" type="vector2">
      <input name="roughness" type="float" interfacename="coat_roughness">
      <input name="anisotropy" type="float" interfacename="coat_anisotropy">
    <dielectric_bsdf name="coat_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="coat">
      <input name="tint" type="color3" value="1.0, 1.0, 1.0">
      <input name="ior" type="float" interfacename="coat_IOR">
      <input name="roughness" type="vector2" nodename="coat_roughness_vector">
      <input name="normal" type="vector3" interfacename="coat_normal">
      <input name="tangent" type="vector3" nodename="coat_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="R">
    <layer name="coat_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="coat_bsdf">
      <input name="base" type="BSDF" nodename="thin_film_layer_attenuated">
    <subtract name="one_minus_coat_ior" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" interfacename="coat_IOR">
    <add name="one_plus_coat_ior" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" interfacename="coat_IOR">
    <divide name="coat_ior_to_F0_sqrt" type="float">
      <input name="in1" type="float" nodename="one_minus_coat_ior">
      <input name="in2" type="float" nodename="one_plus_coat_ior">
    <multiply name="coat_ior_to_F0" type="float">
      <input name="in1" type="float" nodename="coat_ior_to_F0_sqrt">
      <input name="in2" type="float" nodename="coat_ior_to_F0_sqrt">
    <subtract name="one_minus_coat_ior_to_F0" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" nodename="coat_ior_to_F0">
    <multiply name="emission_weight" type="color3">
      <input name="in1" type="color3" interfacename="emission_color">
      <input name="in2" type="float" interfacename="emission">
    <uniform_edf name="emission_edf" type="EDF">
      <input name="color" type="color3" nodename="emission_weight">
    <multiply name="coat_tinted_emission_edf" type="EDF">
      <input name="in1" type="EDF" nodename="emission_edf">
      <input name="in2" type="color3" interfacename="coat_color">
    <convert name="emission_color0" type="color3">
      <input name="in" type="float" nodename="one_minus_coat_ior_to_F0">
    <generalized_schlick_edf name="coat_emission_edf" type="EDF">
      <input name="color0" type="color3" nodename="emission_color0">
      <input name="color90" type="color3" value="0.0, 0.0, 0.0">
      <input name="exponent" type="float" value="5.0">
      <input name="base" type="EDF" nodename="coat_tinted_emission_edf">
    <mix name="blended_coat_emission_edf" type="EDF">
      <input name="fg" type="EDF" nodename="coat_emission_edf">
      <input name="bg" type="EDF" nodename="emission_edf">
      <input name="mix" type="float" interfacename="coat">
    <luminance name="opacity_luminance" type="color3">
      <input name="in" type="color3" interfacename="opacity">
    <extract name="opacity_luminance_float" type="float">
      <input name="in" type="color3" nodename="opacity_luminance">
      <input name="index" type="integer" value="0">
    <surface name="shader_constructor" type="surfaceshader">
      <input name="bsdf" type="BSDF" nodename="coat_layer">
      <input name="edf" type="EDF" nodename="blended_coat_emission_edf">
      <input name="opacity" type="float" nodename="opacity_luminance_float">
    <output name="out" type="surfaceshader" nodename="shader_constructor">
New functional node definition:¶
<nodedef name="ND_standard_surface_surfaceshader" node="standard_surface" nodegroup="pbr" version="1.0.1" isdefaultversion="true" inherit="ND_standard_surface_surfaceshader_100" doc="Autodesk standard surface shader">
  <input name="base" type="float" value="1.0" uimin="0.0" uimax="1.0" uiname="Base" uifolder="Base" doc="Multiplier on the intensity of the diffuse reflection.">
  <input name="base_color" type="color3" value="0.8, 0.8, 0.8" uimin="0,0,0" uimax="1,1,1" uiname="Base Color" uifolder="Base" doc="Color of the diffuse reflection.">
  <implementation name="IMPL_standard_surface_surfaceshader_101" nodegraph="NG_standard_surface_surfaceshader_100">
  <nodegraph name="NG_standard_surface_surfaceshader_optim" target="genglsl">
    <multiply name="coat_affect_roughness_multiply1" type="float">
      <input name="in1" type="float" interfacename="coat_affect_roughness">
      <input name="in2" type="float" interfacename="coat">
    <multiply name="coat_affect_roughness_multiply2" type="float">
      <input name="in1" type="float" nodename="coat_affect_roughness_multiply1">
      <input name="in2" type="float" interfacename="coat_roughness">
    <mix name="coat_affected_roughness" type="float">
      <input name="fg" type="float" value="1.0">
      <input name="bg" type="float" interfacename="specular_roughness">
      <input name="mix" type="float" nodename="coat_affect_roughness_multiply2">
    <roughness_anisotropy name="main_roughness" type="vector2">
      <input name="roughness" type="float" nodename="coat_affected_roughness">
      <input name="anisotropy" type="float" interfacename="specular_anisotropy">
    <add name="transmission_roughness_add" type="float">
      <input name="in1" type="float" interfacename="specular_roughness">
      <input name="in2" type="float" interfacename="transmission_extra_roughness">
    <clamp name="transmission_roughness_clamped" type="float">
      <input name="in" type="float" nodename="transmission_roughness_add">
    <mix name="coat_affected_transmission_roughness" type="float">
      <input name="fg" type="float" value="1.0">
      <input name="bg" type="float" nodename="transmission_roughness_clamped">
      <input name="mix" type="float" nodename="coat_affect_roughness_multiply2">
    <roughness_anisotropy name="transmission_roughness" type="vector2">
      <input name="roughness" type="float" nodename="coat_affected_transmission_roughness">
      <input name="anisotropy" type="float" interfacename="specular_anisotropy">
    <multiply name="tangent_rotate_degree" type="float">
      <input name="in1" type="float" interfacename="specular_rotation">
      <input name="in2" type="float" value="360">
    <rotate3d name="tangent_rotate" type="vector3">
      <input name="in" type="vector3" interfacename="tangent">
      <input name="amount" type="float" nodename="tangent_rotate_degree">
      <input name="axis" type="vector3" interfacename="normal">
    <normalize name="tangent_rotate_normalize" type="vector3">
      <input name="in" type="vector3" nodename="tangent_rotate">
    <ifgreater name="main_tangent" type="vector3">
      <input name="value1" type="float" interfacename="specular_anisotropy">
      <input name="value2" type="float" value="0.0">
      <input name="in1" type="vector3" nodename="tangent_rotate_normalize">
      <input name="in2" type="vector3" interfacename="tangent">
    <multiply name="coat_tangent_rotate_degree" type="float">
      <input name="in1" type="float" interfacename="coat_rotation">
      <input name="in2" type="float" value="360">
    <rotate3d name="coat_tangent_rotate" type="vector3">
      <input name="in" type="vector3" interfacename="tangent">
      <input name="amount" type="float" nodename="coat_tangent_rotate_degree">
      <input name="axis" type="vector3" interfacename="coat_normal">
    <normalize name="coat_tangent_rotate_normalize" type="vector3">
      <input name="in" type="vector3" nodename="coat_tangent_rotate">
    <ifgreater name="coat_tangent" type="vector3">
      <input name="value1" type="float" interfacename="coat_anisotropy">
      <input name="value2" type="float" value="0.0">
      <input name="in1" type="vector3" nodename="coat_tangent_rotate_normalize">
      <input name="in2" type="vector3" interfacename="tangent">
    <clamp name="coat_clamped" type="float">
      <input name="in" type="float" interfacename="coat">
    <multiply name="coat_gamma_multiply" type="float">
      <input name="in1" type="float" nodename="coat_clamped">
      <input name="in2" type="float" interfacename="coat_affect_color">
    <add name="coat_gamma" type="float">
      <input name="in1" type="float" nodename="coat_gamma_multiply">
      <input name="in2" type="float" value="1.0">
    <max name="base_color_nonnegative" type="color3">
      <input name="in1" type="color3" interfacename="base_color">
      <input name="in2" type="float" value="0.0">
    <power name="coat_affected_diffuse_color" type="color3">
      <input name="in1" type="color3" nodename="base_color_nonnegative">
      <input name="in2" type="float" nodename="coat_gamma">
    <max name="subsurface_color_nonnegative" type="color3">
      <input name="in1" type="color3" interfacename="subsurface_color">
      <input name="in2" type="float" value="0.0">
    <power name="coat_affected_subsurface_color" type="color3">
      <input name="in1" type="color3" nodename="subsurface_color_nonnegative">
      <input name="in2" type="float" nodename="coat_gamma">
    <oren_nayar_diffuse_bsdf name="diffuse_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="base">
      <input name="color" type="color3" nodename="coat_affected_diffuse_color">
      <input name="roughness" type="float" interfacename="diffuse_roughness">
      <input name="normal" type="vector3" interfacename="normal">
    <translucent_bsdf name="translucent_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="subsurface">
      <input name="color" type="color3" nodename="coat_affected_subsurface_color">
      <input name="normal" type="vector3" interfacename="normal">
    <multiply name="subsurface_radius_scaled" type="color3">
      <input name="in1" type="color3" interfacename="subsurface_radius">
      <input name="in2" type="float" interfacename="subsurface_scale">
    <subsurface_bsdf name="subsurface_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="subsurface">
      <input name="color" type="color3" nodename="coat_affected_subsurface_color">
      <input name="radius" type="color3" nodename="subsurface_radius_scaled">
      <input name="anisotropy" type="float" interfacename="subsurface_anisotropy">
      <input name="normal" type="vector3" interfacename="normal">
    <convert name="subsurface_selector" type="float">
      <input name="in" type="boolean" interfacename="thin_walled">
    <mix name="selected_subsurface_bsdf" type="BSDF">
      <input name="fg" type="BSDF" nodename="translucent_bsdf">
      <input name="bg" type="BSDF" nodename="subsurface_bsdf">
      <input name="mix" type="float" nodename="subsurface_selector">
    <invert name="subsurface_inv" type="float">
      <input name="in" type="float" interfacename="subsurface">
    <multiply name="diffuse_bsdf_non_subsurface" type="BSDF">
      <input name="in1" type="BSDF" nodename="diffuse_bsdf">
      <input name="in2" type="float" nodename="subsurface_inv">
    <add name="subsurface_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="selected_subsurface_bsdf">
      <input name="in2" type="BSDF" nodename="diffuse_bsdf_non_subsurface">
    <sheen_bsdf name="sheen_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="sheen">
      <input name="color" type="color3" interfacename="sheen_color">
      <input name="roughness" type="float" interfacename="sheen_roughness">
      <input name="normal" type="vector3" interfacename="normal">
    <layer name="sheen_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="sheen_bsdf">
      <input name="base" type="BSDF" nodename="subsurface_blend">
    <dielectric_bsdf name="transmission_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="transmission">
      <input name="tint" type="color3" interfacename="transmission_color">
      <input name="ior" type="float" interfacename="specular_IOR">
      <input name="roughness" type="vector2" nodename="transmission_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="T">
    <invert name="transmission_inv" type="float">
      <input name="in" type="float" interfacename="transmission">
    <multiply name="sheen_layer_non_transmission" type="BSDF">
      <input name="in1" type="BSDF" nodename="sheen_layer">
      <input name="in2" type="float" nodename="transmission_inv">
    <add name="transmission_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="transmission_bsdf">
      <input name="in2" type="BSDF" nodename="sheen_layer_non_transmission">
    <dielectric_bsdf name="specular_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="specular">
      <input name="tint" type="color3" interfacename="specular_color">
      <input name="ior" type="float" interfacename="specular_IOR">
      <input name="roughness" type="vector2" nodename="main_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="R">
      <input name="thinfilm_thickness" type="float" interfacename="thin_film_thickness">
      <input name="thinfilm_ior" type="float" interfacename="thin_film_IOR">
    <layer name="specular_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="specular_bsdf">
      <input name="base" type="BSDF" nodename="transmission_blend">
    <multiply name="metal_reflectivity" type="color3">
      <input name="in1" type="color3" interfacename="base_color">
      <input name="in2" type="float" interfacename="base">
    <multiply name="metal_edgecolor" type="color3">
      <input name="in1" type="color3" interfacename="specular_color">
      <input name="in2" type="float" interfacename="specular">
    <artistic_ior name="artistic_ior" type="multioutput">
      <input name="reflectivity" type="color3" nodename="metal_reflectivity">
      <input name="edge_color" type="color3" nodename="metal_edgecolor">
    <conductor_bsdf name="metal_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="metalness">
      <input name="ior" type="color3" nodename="artistic_ior" output="ior">
      <input name="extinction" type="color3" nodename="artistic_ior" output="extinction">
      <input name="roughness" type="vector2" nodename="main_roughness">
      <input name="normal" type="vector3" interfacename="normal">
      <input name="tangent" type="vector3" nodename="main_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="thinfilm_thickness" type="float" interfacename="thin_film_thickness">
      <input name="thinfilm_ior" type="float" interfacename="thin_film_IOR">
    <invert name="metalness_inv" type="float">
      <input name="in" type="float" interfacename="metalness">
    <multiply name="specular_layer_non_metal" type="BSDF">
      <input name="in1" type="BSDF" nodename="specular_layer">
      <input name="in2" type="float" nodename="metalness_inv">
    <add name="metalness_blend" type="BSDF">
      <input name="in1" type="BSDF" nodename="metal_bsdf">
      <input name="in2" type="BSDF" nodename="specular_layer_non_metal">
    <mix name="coat_attenuation" type="color3">
      <input name="fg" type="color3" interfacename="coat_color">
      <input name="bg" type="color3" value="1.0, 1.0, 1.0">
      <input name="mix" type="float" interfacename="coat">
    <multiply name="thin_film_layer_attenuated" type="BSDF">
      <input name="in1" type="BSDF" nodename="metalness_blend">
      <input name="in2" type="color3" nodename="coat_attenuation">
    <roughness_anisotropy name="coat_roughness_vector" type="vector2">
      <input name="roughness" type="float" interfacename="coat_roughness">
      <input name="anisotropy" type="float" interfacename="coat_anisotropy">
    <dielectric_bsdf name="coat_bsdf" type="BSDF">
      <input name="weight" type="float" interfacename="coat">
      <input name="tint" type="color3" value="1.0, 1.0, 1.0">
      <input name="ior" type="float" interfacename="coat_IOR">
      <input name="roughness" type="vector2" nodename="coat_roughness_vector">
      <input name="normal" type="vector3" interfacename="coat_normal">
      <input name="tangent" type="vector3" nodename="coat_tangent">
      <input name="distribution" type="string" value="ggx">
      <input name="scatter_mode" type="string" value="R">
    <layer name="coat_layer" type="BSDF">
      <input name="top" type="BSDF" nodename="coat_bsdf">
      <input name="base" type="BSDF" nodename="thin_film_layer_attenuated">
    <subtract name="one_minus_coat_ior" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" interfacename="coat_IOR">
    <add name="one_plus_coat_ior" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" interfacename="coat_IOR">
    <divide name="coat_ior_to_F0_sqrt" type="float">
      <input name="in1" type="float" nodename="one_minus_coat_ior">
      <input name="in2" type="float" nodename="one_plus_coat_ior">
    <multiply name="coat_ior_to_F0" type="float">
      <input name="in1" type="float" nodename="coat_ior_to_F0_sqrt">
      <input name="in2" type="float" nodename="coat_ior_to_F0_sqrt">
    <subtract name="one_minus_coat_ior_to_F0" type="float">
      <input name="in1" type="float" value="1.0">
      <input name="in2" type="float" nodename="coat_ior_to_F0">
    <multiply name="emission_weight" type="color3">
      <input name="in1" type="color3" interfacename="emission_color">
      <input name="in2" type="float" interfacename="emission">
    <uniform_edf name="emission_edf" type="EDF">
      <input name="color" type="color3" nodename="emission_weight">
    <multiply name="coat_tinted_emission_edf" type="EDF">
      <input name="in1" type="EDF" nodename="emission_edf">
      <input name="in2" type="color3" interfacename="coat_color">
    <convert name="emission_color0" type="color3">
      <input name="in" type="float" nodename="one_minus_coat_ior_to_F0">
    <generalized_schlick_edf name="coat_emission_edf" type="EDF">
      <input name="color0" type="color3" nodename="emission_color0">
      <input name="color90" type="color3" value="0.0, 0.0, 0.0">
      <input name="exponent" type="float" value="5.0">
      <input name="base" type="EDF" nodename="coat_tinted_emission_edf">
    <mix name="blended_coat_emission_edf" type="EDF">
      <input name="fg" type="EDF" nodename="coat_emission_edf">
      <input name="bg" type="EDF" nodename="emission_edf">
      <input name="mix" type="float" interfacename="coat">
    <luminance name="opacity_luminance" type="color3">
      <input name="in" type="color3" interfacename="opacity">
    <extract name="opacity_luminance_float" type="float">
      <input name="in" type="color3" nodename="opacity_luminance">
      <input name="index" type="integer" value="0">
    <surface name="shader_constructor" type="surfaceshader">
      <input name="bsdf" type="BSDF" nodename="coat_layer">
      <input name="edf" type="EDF" nodename="blended_coat_emission_edf">
      <input name="opacity" type="float" nodename="opacity_luminance_float">
    <output name="out" type="surfaceshader" nodename="shader_constructor">