diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index f8bc9ca8512..7a4ed4fbdaf 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -17,7 +17,7 @@ # import bpy -from bpy_extras.node_utils import find_node_input, find_output_node +from bpy_extras.node_utils import find_node_input from bl_operators.presets import PresetMenu from bpy.types import ( @@ -1069,14 +1069,14 @@ class CYCLES_OT_use_shading_nodes(Operator): return {'FINISHED'} -def panel_node_draw(layout, id_data, output_types, input_name): +def panel_node_draw(layout, id_data, output_type, 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_types) + node = ntree.get_output_node('CYCLES') if node: input = find_node_input(node, input_name) if input: @@ -1176,7 +1176,7 @@ class CYCLES_LAMP_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") @@ -1226,7 +1226,7 @@ class CYCLES_WORLD_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") @@ -1244,7 +1244,7 @@ class CYCLES_WORLD_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 CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel): @@ -1425,7 +1425,7 @@ class CYCLES_MATERIAL_PT_surface(CyclesButtonsPanel, Panel): layout = self.layout mat = context.material - if not panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Surface'): + if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'): layout.prop(mat, "diffuse_color") @@ -1445,7 +1445,7 @@ class CYCLES_MATERIAL_PT_volume(CyclesButtonsPanel, Panel): mat = context.material # cmat = mat.cycles - panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Volume') + panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume') class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): @@ -1461,7 +1461,7 @@ class CYCLES_MATERIAL_PT_displacement(CyclesButtonsPanel, Panel): layout = self.layout mat = context.material - panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Displacement') + panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement') class CYCLES_MATERIAL_PT_settings(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 66034919145..ed92cb71f04 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1001,31 +1001,6 @@ 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); - - 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; - } - } - } - - return output_node; -} - static void add_nodes(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, @@ -1045,7 +1020,7 @@ static void add_nodes(Scene *scene, BL::Node::outputs_iterator b_output; /* find the node to use for output if there are multiple */ - BL::ShaderNode output_node = find_output_node(b_ntree); + BL::ShaderNode output_node = b_ntree.get_output_node(BL::ShaderNodeOutputMaterial::target_CYCLES); /* add nodes */ for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { diff --git a/release/scripts/modules/bpy_extras/node_utils.py b/release/scripts/modules/bpy_extras/node_utils.py index d459b99ddd0..d4c6d5cd45a 100644 --- a/release/scripts/modules/bpy_extras/node_utils.py +++ b/release/scripts/modules/bpy_extras/node_utils.py @@ -20,7 +20,6 @@ __all__ = ( "find_node_input", - "find_output_node", ) @@ -31,22 +30,3 @@ def find_node_input(node, name): return input return None - -# 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: - 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 diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index fdbf0b240c4..3761cbba372 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -21,7 +21,7 @@ import bpy from bpy.types import Menu, Panel, UIList from rna_prop_ui import PropertyPanel from bpy.app.translations import pgettext_iface as iface_ -from bpy_extras.node_utils import find_node_input, find_output_node +from bpy_extras.node_utils import find_node_input class MATERIAL_MT_specials(Menu): @@ -140,7 +140,7 @@ class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): def panel_node_draw(layout, ntree, output_type): - node = find_output_node(ntree, output_type) + node = ntree.get_output_node('EEVEE') if node: input = find_node_input(node, 'Surface') @@ -171,7 +171,7 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel): layout.separator() if mat.use_nodes: - panel_node_draw(layout, mat.node_tree, ('OUTPUT_EEVEE_MATERIAL', 'OUTPUT_MATERIAL')) + panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL') else: layout.use_property_split = True layout.prop(mat, "diffuse_color", text="Base Color") diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index bba7f9e132a..52a769fd223 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -20,7 +20,7 @@ import bpy from bpy.types import Panel from rna_prop_ui import PropertyPanel -from bpy_extras.node_utils import find_node_input, find_output_node +from bpy_extras.node_utils import find_node_input class WorldButtonsPanel: @@ -109,7 +109,7 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel): if world.use_nodes: ntree = world.node_tree - node = find_output_node(ntree, ('OUTPUT_WORLD',)) + node = ntree.get_output_node('EEVEE') if node: input = find_node_input(node, 'Surface') diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a400337e2cf..9eb026b1c4f 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -812,6 +812,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, c struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree); void ntreeShaderEndExecTree(struct bNodeTreeExec *exec); bool ntreeShaderExecTree(struct bNodeTree *ntree, int thread); +struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target); void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat, bool *has_surface_output, bool *has_volume_output); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index da49a772688..d7015ed5e53 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1066,6 +1066,11 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA #endif } +static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "target", 0, "", ICON_NONE); +} + static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *row, *col; @@ -1209,6 +1214,11 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_UVALONGSTROKE: ntype->draw_buttons = node_shader_buts_uvalongstroke; break; + case SH_NODE_OUTPUT_MATERIAL: + case SH_NODE_OUTPUT_LAMP: + case SH_NODE_OUTPUT_WORLD: + ntype->draw_buttons = node_buts_output_shader; + break; case SH_NODE_OUTPUT_LINESTYLE: ntype->draw_buttons = node_buts_output_linestyle; break; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index f38ae61421b..90c9d81e996 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1101,39 +1101,6 @@ enum { #define CMP_NODE_MASK_MBLUR_SAMPLES_MAX 64 -/* geometry output socket defines */ -#define GEOM_OUT_GLOB 0 -#define GEOM_OUT_LOCAL 1 -#define GEOM_OUT_VIEW 2 -#define GEOM_OUT_ORCO 3 -#define GEOM_OUT_UV 4 -#define GEOM_OUT_NORMAL 5 -#define GEOM_OUT_VCOL 6 -#define GEOM_OUT_VCOL_ALPHA 7 -#define GEOM_OUT_FRONTBACK 8 - -/* material input socket defines */ -#define MAT_IN_COLOR 0 -#define MAT_IN_SPEC 1 -#define MAT_IN_REFL 2 -#define MAT_IN_NORMAL 3 -#define MAT_IN_MIR 4 -#define MAT_IN_AMB 5 -#define MAT_IN_EMIT 6 -#define MAT_IN_SPECTRA 7 -#define MAT_IN_RAY_MIRROR 8 -#define MAT_IN_ALPHA 9 -#define MAT_IN_TRANSLUCENCY 10 -#define NUM_MAT_IN 11 /* for array size */ - -/* material output socket defines */ -#define MAT_OUT_COLOR 0 -#define MAT_OUT_ALPHA 1 -#define MAT_OUT_NORMAL 2 -#define MAT_OUT_DIFFUSE 3 -#define MAT_OUT_SPEC 4 -#define MAT_OUT_AO 5 - /* image */ #define CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT 1 @@ -1176,4 +1143,12 @@ enum { SHD_POINTDENSITY_COLOR_VERTNOR = 2, }; +/* Output shader node */ + +typedef enum NodeShaderOutputTarget { + SHD_OUTPUT_ALL = 0, + SHD_OUTPUT_EEVEE = 1, + SHD_OUTPUT_CYCLES = 2, +} NodeShaderOutputTarget; + #endif diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 492335d4d25..9e800d3b875 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -175,6 +175,14 @@ static const EnumPropertyItem node_sampler_type_items[] = { {2, "BICUBIC", 0, "Bicubic", ""}, {0, NULL, 0, NULL, NULL} }; + + +static const EnumPropertyItem prop_shader_output_target_items[] = { + {SHD_OUTPUT_ALL, "ALL", 0, "All", "Use shaders for all renderers and viewports, unless there exists a more specific output"}, + {SHD_OUTPUT_EEVEE, "EEVEE", 0, "Eevee", "Use shaders for Eevee renderer"}, + {SHD_OUTPUT_CYCLES, "CYCLES", 0, "Cycles", "Use shaders for Cycles renderer"}, + {0, NULL, 0, NULL, NULL} +}; #endif #ifdef RNA_RUNTIME @@ -3536,6 +3544,12 @@ static void def_sh_output(StructRNA *srna) RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT); RNA_def_property_ui_text(prop, "Active Output", "True if this node is used as the active output"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "target", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, prop_shader_output_target_items); + RNA_def_property_ui_text(prop, "Target", "Which renderer and viewport shading types to use the shaders for"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_sh_output_linestyle(StructRNA *srna) @@ -8377,12 +8391,21 @@ static void rna_def_composite_nodetree(BlenderRNA *brna) static void rna_def_shader_nodetree(BlenderRNA *brna) { StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; srna = RNA_def_struct(brna, "ShaderNodeTree", "NodeTree"); RNA_def_struct_ui_text(srna, "Shader Node Tree", "Node tree consisting of linked nodes used for materials (and other shading data-blocks)"); RNA_def_struct_sdna(srna, "bNodeTree"); RNA_def_struct_ui_icon(srna, ICON_MATERIAL); + + func = RNA_def_function(srna, "get_output_node", "ntreeShaderOutputNode"); + RNA_def_function_ui_description(func, "Return active shader output node for the specified target"); + parm = RNA_def_enum(func, "target", prop_shader_output_target_items, SHD_OUTPUT_ALL, "Target", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "node", "ShaderNode", "Node", ""); + RNA_def_function_return(func, parm); } static void rna_def_texture_nodetree(BlenderRNA *brna) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 329e850d19e..8db88f13ea6 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -209,20 +209,52 @@ 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) +bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) { /* Make sure we only have single node tagged as output. */ ntreeSetOutput(ntree); - for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) { - if (node->flag & NODE_DO_OUTPUT) { - return node; + + /* Find output node that matches type and target. If there are + * multiple, we prefer exact target match and active nodes. */ + bNode *output_node = NULL; + + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, + SH_NODE_OUTPUT_WORLD, + SH_NODE_OUTPUT_LAMP)) + { + continue; + } + + if (node->custom1 == SHD_OUTPUT_ALL) { + if (output_node == NULL) { + output_node = node; + } + else if (output_node->custom1 == SHD_OUTPUT_ALL) { + if ((node->flag & NODE_DO_OUTPUT) && + !(output_node->flag & NODE_DO_OUTPUT)) + { + output_node = node; + } + } + } + else if (node->custom1 == target) { + if (output_node == NULL) { + output_node = node; + } + else if(output_node->custom1 == SHD_OUTPUT_ALL) { + output_node = node; + } + else if ((node->flag & NODE_DO_OUTPUT) && + !(output_node->flag & NODE_DO_OUTPUT)) + { + output_node = node; + } } } - return NULL; + + return output_node; } /* Find socket with a specified identifier. */ @@ -555,7 +587,7 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, bool *has_surface { /* localize tree to create links for reroute and mute */ bNodeTree *localtree = ntreeLocalize(ntree); - bNode *output = ntree_shader_output_node(localtree); + bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); bNodeTreeExec *exec; /* Perform all needed modifications on the tree in order to support