/* Use specified node and socket as an input for unconnected normal sockets. */ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, bNode *node_from, bNodeSocket *socket_from) { for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) { if (node == node_from) { /* Don't connect node itself! */ continue; } bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal"); /* TODO(sergey): Can we do something smarter here than just a name-based * matching? */ if (sock == NULL) { /* There's no Normal input, nothing to link. */ continue; } if (sock->link != NULL) { /* Something is linked to the normal input already. can't * use other input for that. */ continue; } /* Create connection between specified node and the normal input. */ nodeAddLink(ntree, node_from, socket_from, node, sock); } }
/* Check whether shader has a displacement. * * Will also return a node and it's socket which is connected to a displacement * output. Additionally, link which is attached to the displacement output is * also returned. */ static bool ntree_shader_has_displacement(bNodeTree *ntree, bNode **r_node, bNodeSocket **r_socket, bNodeLink **r_link) { bNode *output_node = ntree_shader_output_node(ntree); if (output_node == NULL) { /* We can't have displacement without output node, apparently. */ return false; } /* Make sure sockets links pointers are correct. */ ntreeUpdateTree(G.main, ntree); bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement"); if (displacement == NULL) { /* Non-cycles node is used as an output. */ return false; } if (displacement->link != NULL) { *r_node = displacement->link->fromnode; *r_socket = displacement->link->fromsock; *r_link = displacement->link; } return displacement->link != NULL; }
/* Re-link displacement output to unconnected normal sockets via bump node. * This way material with have proper displacement in the viewport. */ static void ntree_shader_relink_displacement(bNodeTree *ntree, short compatibility) { if (compatibility != NODE_NEW_SHADING) { /* We can only deal with new shading system here. */ return; } bNode *displacement_node; bNodeSocket *displacement_socket; bNodeLink *displacement_link; if (!ntree_shader_has_displacement(ntree, &displacement_node, &displacement_socket, &displacement_link)) { /* There is no displacement output connected, nothing to re-link. */ return; } /* We have to disconnect displacement output socket, otherwise we'll have * cycles in the Cycles material :) */ nodeRemLink(ntree, displacement_link); /* We can't connect displacement to normal directly, use bump node for that * and hope that it gives good enough approximation. */ bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP); bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); BLI_assert(bump_input_socket != NULL); BLI_assert(bump_output_socket != NULL); /* Connect bump node to where displacement output was originally * connected to. */ nodeAddLink(ntree, displacement_node, displacement_socket, bump_node, bump_input_socket); /* Connect all free-standing Normal inputs. */ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket, displacement_node, displacement_socket); /* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new * bump node. */ /* We modified the tree, it needs to be updated now. */ ntreeUpdateTree(G.main, ntree); }
static bool ntree_shader_relink_node_normal(bNodeTree *ntree, bNode *node, bNode *node_from, bNodeSocket *socket_from) { bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal"); /* TODO(sergey): Can we do something smarter here than just a name-based * matching? */ if (sock == NULL) { /* There's no Normal input, nothing to link. */ return false; } if (sock->link != NULL) { /* Something is linked to the normal input already. can't * use other input for that. */ return false; } /* Create connection between specified node and the normal input. */ nodeAddLink(ntree, node_from, socket_from, node, sock); return true; }
static void ntree_shader_link_builtin_group_normal( bNodeTree *ntree, bNode *group_node, bNode *node_from, bNodeSocket *socket_from, bNode *displacement_node, bNodeSocket *displacement_socket) { bNodeTree *group_ntree = (bNodeTree *)group_node->id; /* Create input socket to plug displacement connection to. */ bNodeSocket *group_normal_socket = ntreeAddSocketInterface(group_ntree, SOCK_IN, "NodeSocketVector", "Normal"); /* Need to update tree so all node instances nodes gets proper sockets. */ bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); node_group_verify(ntree, group_node, &group_ntree->id); if (group_input_node) node_group_input_verify(group_ntree, group_input_node, &group_ntree->id); ntreeUpdateTree(G.main, group_ntree); /* Assumes sockets are always added at the end. */ bNodeSocket *group_node_normal_socket = group_node->inputs.last; if (displacement_node == group_node) { /* If displacement is coming from this node group we need to perform * some internal re-linking in order to avoid cycles. */ bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT); BLI_assert(group_output_node != NULL); bNodeSocket *group_output_node_displacement_socket = nodeFindSocket(group_output_node, SOCK_IN, displacement_socket->identifier); bNodeLink *group_displacement_link = group_output_node_displacement_socket->link; if (group_displacement_link == NULL) { /* Displacement output is not connected to anything, can just stop * right away. */ return; } /* This code is similar to ntree_shader_relink_displacement() */ bNode *group_displacement_node = group_displacement_link->fromnode; bNodeSocket *group_displacement_socket = group_displacement_link->fromsock; /* Create and link bump node. * Can't re-use bump node from parent tree because it'll cause cycle. */ bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP); bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); BLI_assert(bump_input_socket != NULL); BLI_assert(bump_output_socket != NULL); nodeAddLink(group_ntree, group_displacement_node, group_displacement_socket, bump_node, bump_input_socket); /* Relink normals inside of the instanced tree. */ ntree_shader_link_builtin_normal(group_ntree, bump_node, bump_output_socket, group_displacement_node, group_displacement_socket); ntreeUpdateTree(G.main, group_ntree); } else if (group_input_node) { /* Connect group node normal input. */ nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket); BLI_assert(group_input_node != NULL); bNodeSocket *group_input_node_normal_socket = nodeFindSocket(group_input_node, SOCK_OUT, group_normal_socket->identifier); BLI_assert(group_input_node_normal_socket != NULL); /* Relink normals inside of the instanced tree. */ ntree_shader_link_builtin_normal(group_ntree, group_input_node, group_input_node_normal_socket, displacement_node, displacement_socket); ntreeUpdateTree(G.main, group_ntree); } }