Render: make Cycles and Evee support each other's output material nodes.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Tue, 1 Aug 2017 16:03:16 +0000 (18:03 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Tue, 1 Aug 2017 17:13:41 +0000 (19:13 +0200)
This changes the Cycles exporting and Cycles/Eevee UI code to support both
output material nodes, giving priority to the renderer native one. Still
missing is Eevee code to prefer the Eevee output node.

intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_shader.cpp
release/scripts/modules/bpy_extras/node_utils.py
release/scripts/startup/bl_ui/properties_material.py
release/scripts/startup/bl_ui/properties_world.py
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/nodes/node_shader_output_material.c

index 3cff65c97176986ddd53cdfcbf98441b76fa7116..9aaa0d1c9c2ac442ae446ead40d1521515094d95 100644 (file)
@@ -899,19 +899,22 @@ class CYCLES_OT_use_shading_nodes(Operator):
         return {'FINISHED'}
 
 
-def panel_node_draw(layout, id_data, output_type, input_name):
+def panel_node_draw(layout, id_data, output_types, input_name):
     if not id_data.use_nodes:
         layout.operator("cycles.use_shading_nodes", icon='NODETREE')
         return False
 
     ntree = id_data.node_tree
 
-    node = find_output_node(ntree, output_type)
-    if not node:
-        layout.label(text="No output node")
-    else:
+    node = find_output_node(ntree, output_types)
+    if node:
         input = find_node_input(node, input_name)
-        layout.template_node_view(ntree, node, input)
+        if input:
+            layout.template_node_view(ntree, node, input)
+        else:
+            layout.label(text="Incompatible output node")
+    else:
+        layout.label(text="No output node")
 
     return True
 
@@ -1000,7 +1003,7 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
         layout = self.layout
 
         lamp = context.lamp
-        if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
+        if not panel_node_draw(layout, lamp, ['OUTPUT_LAMP'], 'Surface'):
             layout.prop(lamp, "color")
 
 
@@ -1055,7 +1058,7 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
 
         world = context.world
 
-        if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
+        if not panel_node_draw(layout, world, ['OUTPUT_WORLD'], 'Surface'):
             layout.prop(world, "horizon_color", text="Color")
 
 
@@ -1073,7 +1076,7 @@ class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
         layout = self.layout
 
         world = context.world
-        panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
+        panel_node_draw(layout, world, ['OUTPUT_WORLD'], 'Volume')
 
 
 class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
@@ -1218,7 +1221,7 @@ class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
         layout = self.layout
 
         mat = context.material
-        if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
+        if not panel_node_draw(layout, mat, ['OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'], 'Surface'):
             layout.prop(mat, "diffuse_color")
 
 
@@ -1238,7 +1241,7 @@ class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
         mat = context.material
         # cmat = mat.cycles
 
-        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
+        panel_node_draw(layout, mat, ['OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'], 'Volume')
 
 
 class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
@@ -1254,7 +1257,7 @@ class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
         layout = self.layout
 
         mat = context.material
-        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
+        panel_node_draw(layout, mat, ['OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'], 'Displacement')
 
 
 class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
index 50202c3f2727fa00c54346709d642f7dfcce52b3..bbf7dc720a8887dd7c05f9f3fea7d6aa7fae4653 100644 (file)
@@ -231,14 +231,6 @@ static void get_tex_mapping(TextureMapping *mapping,
                mapping->max = get_float3(b_mapping.max());
 }
 
-static bool is_output_node(BL::Node& b_node)
-{
-       return (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
-                   || b_node.is_a(&RNA_ShaderNodeOutputWorld)
-                   || b_node.is_a(&RNA_ShaderNodeOutputLamp)
-                   || b_node.is_a(&RNA_ShaderNodeOutputEeveeMaterial));
-}
-
 static ShaderNode *add_node(Scene *scene,
                             BL::RenderEngine& b_engine,
                             BL::BlendData& b_data,
@@ -951,6 +943,42 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node,
        return node->output(name.c_str());
 }
 
+static BL::ShaderNode find_output_node(BL::ShaderNodeTree& b_ntree)
+{
+       BL::ShaderNodeTree::nodes_iterator b_node;
+       BL::ShaderNode output_node(PointerRNA_NULL);
+       BL::ShaderNode eevee_output_node(PointerRNA_NULL);
+
+       for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
+               BL::ShaderNodeOutputMaterial b_output_node(*b_node);
+
+               if (b_output_node.is_a(&RNA_ShaderNodeOutputMaterial) ||
+                   b_output_node.is_a(&RNA_ShaderNodeOutputWorld) ||
+                   b_output_node.is_a(&RNA_ShaderNodeOutputLamp)) {
+                       /* regular Cycles output node */
+                       if(b_output_node.is_active_output()) {
+                               output_node = b_output_node;
+                               break;
+                       }
+                       else if(!output_node.ptr.data) {
+                               output_node = b_output_node;
+                       }
+               }
+               else if (b_output_node.is_a(&RNA_ShaderNodeOutputEeveeMaterial)) {
+                       /* Eevee output used  if no Cycles node exists */
+                       if(b_output_node.is_active_output()) {
+                               eevee_output_node = b_output_node;
+                       }
+                       else if(!eevee_output_node.ptr.data) {
+                               eevee_output_node = b_output_node;
+                       }
+
+               }
+       }
+
+       return (output_node.ptr.data) ? output_node : eevee_output_node;
+}
+
 static void add_nodes(Scene *scene,
                       BL::RenderEngine& b_engine,
                       BL::BlendData& b_data,
@@ -971,23 +999,7 @@ static void add_nodes(Scene *scene,
        BL::Node::outputs_iterator b_output;
 
        /* find the node to use for output if there are multiple */
-       bool found_active_output = false;
-       BL::ShaderNode output_node(PointerRNA_NULL);
-
-       for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
-               if(is_output_node(*b_node)) {
-                       BL::ShaderNodeOutputMaterial b_output_node(*b_node);
-
-                       if(b_output_node.is_active_output()) {
-                               output_node = b_output_node;
-                               found_active_output = true;
-                               break;
-                       }
-                       else if(!output_node.ptr.data && !found_active_output) {
-                               output_node = b_output_node;
-                       }
-               }
-       }
+       BL::ShaderNode output_node = find_output_node(b_ntree);
 
        /* add nodes */
        for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
@@ -1085,10 +1097,8 @@ static void add_nodes(Scene *scene,
                else {
                        ShaderNode *node = NULL;
 
-                       if(is_output_node(*b_node)) {
-                               if(b_node->ptr.data == output_node.ptr.data) {
-                                       node = graph->output();
-                               }
+                       if(b_node->ptr.data == output_node.ptr.data) {
+                               node = graph->output();
                        }
                        else {
                                BL::ShaderNode b_shader_node(*b_node);
index 3b8d4ad7c2aa8c6cff54b222054c3d9c7fb80be3..9a2be5b9f6814bf89bc5b841e259b41c5a1407a3 100644 (file)
@@ -32,16 +32,19 @@ def find_node_input(node, name):
 
     return None
 
-# Return the output node to display in the UI
-def find_output_node(ntree, nodetype):
+# Return the output node to display in the UI. In case multiple node types are
+# specified, node types earlier in the list get priority.
+def find_output_node(ntree, nodetypes):
     if ntree:
-        active_output_node = None
-        for node in ntree.nodes:
-            if getattr(node, "type", None) == nodetype:
-                if getattr(node, "is_active_output", True):
-                    return node
-                if not active_output_node:
-                    active_output_node = node
-        return active_output_node
+        output_node = None
+        for nodetype in nodetypes:
+            for node in ntree.nodes:
+                if getattr(node, "type", None) == nodetype:
+                    if getattr(node, "is_active_output", True):
+                        return node
+                    if not output_node:
+                        output_node = node
+            if output_node:
+                return output_node
 
     return None
index e7e920007235b89659d5bfe82fd0b60580206f7a..0e130b20566217acc3666f13744956f05babb731 100644 (file)
@@ -1120,10 +1120,12 @@ def panel_node_draw(layout, ntree, output_type):
 
     if node:
         input = find_node_input(node, 'Surface')
-        layout.template_node_view(ntree, node, input)
-        return True
-
-    return False
+        if input:
+            layout.template_node_view(ntree, node, input)
+        else:
+            layout.label(text="Incompatible output node")
+    else:
+        layout.label(text="No output node")
 
 
 class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
@@ -1145,8 +1147,7 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
         layout.separator()
 
         if mat.use_nodes:
-            if not panel_node_draw(layout, mat.node_tree, 'OUTPUT_EEVEE_MATERIAL'):
-                layout.label(text="No output node")
+            panel_node_draw(layout, mat.node_tree, ['OUTPUT_EEVEE_MATERIAL', 'OUTPUT_MATERIAL'])
         else:
             raym = mat.raytrace_mirror
             layout.prop(mat, "diffuse_color", text="Base Color")
index fc5835d23d006ffa0205dbbe2cd17f675cc78147..ed5cfaa22d2cfc49aa15874d8b03c5d0fdc4564c 100644 (file)
@@ -270,13 +270,16 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
 
         if world.use_nodes:
             ntree = world.node_tree
-            node = find_output_node(ntree, 'OUTPUT_WORLD')
+            node = find_output_node(ntree, ['OUTPUT_WORLD'])
 
-            if not node:
-                layout.label(text="No output node")
-            else:
+            if node:
                 input = find_node_input(node, 'Surface')
-                layout.template_node_view(ntree, node, input)
+                if input:
+                    layout.template_node_view(ntree, node, input)
+                else:
+                    layout.label(text="Incompatible output node")
+            else:
+                layout.label(text="No output node")
         else:
             layout.prop(world, "horizon_color", text="Color")
 
index 52e9ed35a2ecc5022701bc411be550ba05f09974..ec35959f31a4f020c545402bd7d562c7e136482b 100644 (file)
@@ -214,6 +214,9 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
  * render engines works but it's how the GPU shader compilation works. This we
  * can change in the future and make it a generic function, but for now it stays
  * private here.
+ *
+ * It also does not yet take into account render engine specific output nodes,
+ * it should give priority to e.g. the Eevee material output node for Eevee.
  */
 static bNode *ntree_shader_output_node(bNodeTree *ntree)
 {
index 953999a0d48de8e35c346239d5eac1e896711ebc..0418b0393375cf9badfe960f9a5b1df823ccf642 100644 (file)
@@ -42,10 +42,6 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, bNode *node, bNodeE
 {
        GPUNodeLink *outlink;
 
-       if (BKE_scene_uses_blender_eevee(GPU_material_scene(mat))) {
-               return false;
-       }
-
        GPU_stack_link(mat, node, "node_output_material", in, out, &outlink);
        GPU_material_output_link(mat, outlink);