Render: make Cycles and Evee support each other's output material nodes.

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.
This commit is contained in:
2017-08-01 18:03:16 +02:00
parent 110d6832a8
commit c42c129393
7 changed files with 85 additions and 66 deletions

View File

@@ -899,19 +899,22 @@ class CYCLES_OT_use_shading_nodes(Operator):
return {'FINISHED'} 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: if not id_data.use_nodes:
layout.operator("cycles.use_shading_nodes", icon='NODETREE') layout.operator("cycles.use_shading_nodes", icon='NODETREE')
return False return False
ntree = id_data.node_tree ntree = id_data.node_tree
node = find_output_node(ntree, output_type) node = find_output_node(ntree, output_types)
if not node: if node:
layout.label(text="No output node")
else:
input = find_node_input(node, input_name) 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 return True
@@ -1000,7 +1003,7 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
layout = self.layout layout = self.layout
lamp = context.lamp 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") layout.prop(lamp, "color")
@@ -1055,7 +1058,7 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
world = context.world 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") layout.prop(world, "horizon_color", text="Color")
@@ -1073,7 +1076,7 @@ class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
layout = self.layout layout = self.layout
world = context.world 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): class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
@@ -1218,7 +1221,7 @@ class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
layout = self.layout layout = self.layout
mat = context.material 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") layout.prop(mat, "diffuse_color")
@@ -1238,7 +1241,7 @@ class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
mat = context.material mat = context.material
# cmat = mat.cycles # 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): class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
@@ -1254,7 +1257,7 @@ class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
layout = self.layout layout = self.layout
mat = context.material 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): class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):

View File

@@ -231,14 +231,6 @@ static void get_tex_mapping(TextureMapping *mapping,
mapping->max = get_float3(b_mapping.max()); 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, static ShaderNode *add_node(Scene *scene,
BL::RenderEngine& b_engine, BL::RenderEngine& b_engine,
BL::BlendData& b_data, BL::BlendData& b_data,
@@ -951,6 +943,42 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node,
return node->output(name.c_str()); 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, static void add_nodes(Scene *scene,
BL::RenderEngine& b_engine, BL::RenderEngine& b_engine,
BL::BlendData& b_data, BL::BlendData& b_data,
@@ -971,23 +999,7 @@ static void add_nodes(Scene *scene,
BL::Node::outputs_iterator b_output; BL::Node::outputs_iterator b_output;
/* find the node to use for output if there are multiple */ /* find the node to use for output if there are multiple */
bool found_active_output = false; BL::ShaderNode output_node = find_output_node(b_ntree);
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;
}
}
}
/* add nodes */ /* add nodes */
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { 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 { else {
ShaderNode *node = NULL; ShaderNode *node = NULL;
if(is_output_node(*b_node)) { if(b_node->ptr.data == output_node.ptr.data) {
if(b_node->ptr.data == output_node.ptr.data) { node = graph->output();
node = graph->output();
}
} }
else { else {
BL::ShaderNode b_shader_node(*b_node); BL::ShaderNode b_shader_node(*b_node);

View File

@@ -32,16 +32,19 @@ def find_node_input(node, name):
return None return None
# Return the output node to display in the UI # Return the output node to display in the UI. In case multiple node types are
def find_output_node(ntree, nodetype): # specified, node types earlier in the list get priority.
def find_output_node(ntree, nodetypes):
if ntree: if ntree:
active_output_node = None output_node = None
for node in ntree.nodes: for nodetype in nodetypes:
if getattr(node, "type", None) == nodetype: for node in ntree.nodes:
if getattr(node, "is_active_output", True): if getattr(node, "type", None) == nodetype:
return node if getattr(node, "is_active_output", True):
if not active_output_node: return node
active_output_node = node if not output_node:
return active_output_node output_node = node
if output_node:
return output_node
return None return None

View File

@@ -1120,10 +1120,12 @@ def panel_node_draw(layout, ntree, output_type):
if node: if node:
input = find_node_input(node, 'Surface') input = find_node_input(node, 'Surface')
layout.template_node_view(ntree, node, input) if input:
return True layout.template_node_view(ntree, node, input)
else:
return False layout.label(text="Incompatible output node")
else:
layout.label(text="No output node")
class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel): class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
@@ -1145,8 +1147,7 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
layout.separator() layout.separator()
if mat.use_nodes: if mat.use_nodes:
if not panel_node_draw(layout, mat.node_tree, 'OUTPUT_EEVEE_MATERIAL'): panel_node_draw(layout, mat.node_tree, ['OUTPUT_EEVEE_MATERIAL', 'OUTPUT_MATERIAL'])
layout.label(text="No output node")
else: else:
raym = mat.raytrace_mirror raym = mat.raytrace_mirror
layout.prop(mat, "diffuse_color", text="Base Color") layout.prop(mat, "diffuse_color", text="Base Color")

View File

@@ -270,13 +270,16 @@ class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
if world.use_nodes: if world.use_nodes:
ntree = world.node_tree ntree = world.node_tree
node = find_output_node(ntree, 'OUTPUT_WORLD') node = find_output_node(ntree, ['OUTPUT_WORLD'])
if not node: if node:
layout.label(text="No output node")
else:
input = find_node_input(node, 'Surface') 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: else:
layout.prop(world, "horizon_color", text="Color") layout.prop(world, "horizon_color", text="Color")

View 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 * 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 * can change in the future and make it a generic function, but for now it stays
* private here. * 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) static bNode *ntree_shader_output_node(bNodeTree *ntree)
{ {

View File

@@ -42,10 +42,6 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, bNode *node, bNodeE
{ {
GPUNodeLink *outlink; 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_stack_link(mat, node, "node_output_material", in, out, &outlink);
GPU_material_output_link(mat, outlink); GPU_material_output_link(mat, outlink);