diff options
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 19 | ||||
-rw-r--r-- | source/blender/nodes/shader/node_shader_tree.c | 144 |
3 files changed, 143 insertions, 21 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 76e49566d19..4b92c1f7a3a 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -348,6 +348,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree *ntreeFromID(struct ID *id); void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist); +struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 75f899dd597..fa0367d1656 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -2418,15 +2418,20 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree) /* ************ find stuff *************** */ +bNode *ntreeFindType(const bNodeTree *ntree, int type) { + if (ntree) { + for (bNode * node = ntree->nodes.first; node; node = node->next) { + if (node->type == type) { + return node; + } + } + } + return NULL; +} + bool ntreeHasType(const bNodeTree *ntree, int type) { - bNode *node; - - if (ntree) - for (node = ntree->nodes.first; node; node = node->next) - if (node->type == type) - return true; - return false; + return ntreeFindType(ntree, type) != NULL; } bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 29b1e5bc5c7..afccef46174 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -199,6 +199,12 @@ void register_node_tree_type_sh(void) /* GPU material from shader nodes */ +static void ntree_shader_link_builtin_normal(bNodeTree *ntree, + bNode *node_from, + bNodeSocket *socket_from, + bNode *displacement_node, + bNodeSocket *displacement_socket); + /* Find an output node of the shader tree. * * NOTE: it will only return output which is NOT in the group, which isn't how @@ -277,32 +283,138 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree, return displacement->link != NULL; } +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. */ + ntreeUpdateTree(G.main, group_ntree); + /* Assumes sockets are always added at the end. */ + bNodeSocket *group_node_normal_socket = (bNodeSocket*)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; + nodeRemLink(group_ntree, group_displacement_link); + /* 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 { + /* Connect group node normal input. */ + nodeAddLink(ntree, + node_from, socket_from, + group_node, group_node_normal_socket); + bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); + 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); + } +} + /* 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) + bNodeSocket *socket_from, + bNode *displacement_node, + bNodeSocket *displacement_socket) { 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. */ + if (node->type == NODE_GROUP && node->id) { + /* Special re-linking for group nodes. */ + ntree_shader_link_builtin_group_normal(ntree, + node, + node_from, + socket_from, + displacement_node, + displacement_socket); continue; } - if (sock->link != NULL) { - /* Something is linked to the normal input already. can't - * use other input for that. - */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + /* Group inputs and outputs needs nothing special. */ continue; } - /* Create connection between specified node and the normal input. */ - nodeAddLink(ntree, node_from, socket_from, node, sock); + ntree_shader_relink_node_normal(ntree, node, node_from, socket_from); } } @@ -346,7 +458,11 @@ static void ntree_shader_relink_displacement(bNodeTree *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); + 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. */ |