[Bf-blender-cvs] [5b3530e4805] master: GPU: Add better support for displacement relinking behavior

Clément Foucault noreply at git.blender.org
Wed Jun 26 12:25:54 CEST 2019


Commit: 5b3530e4805f35202eeab57253c02b144f838134
Author: Clément Foucault
Date:   Wed Jun 26 12:03:15 2019 +0200
Branches: master
https://developer.blender.org/rB5b3530e4805f35202eeab57253c02b144f838134

GPU: Add better support for displacement relinking behavior

Previously displacement relinking was trying to be smart and seems to be
broken in some cases. This fixes all cases by brute force.

We copy the whole branch linked to the displacement socket and tag it
accordingly. Then we only relink the nodes that are not tagged.

Moreover, we bypass bump nodes inside the dispacement trees so that the
resulting bump is the same as cycles.

Fix T66000 EEVEE: Unexpected results when displacement interact with nodegroups

===================================================================

M	source/blender/nodes/shader/node_shader_tree.c

===================================================================

diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 8af570aea08..92b24d40b0d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -43,6 +43,7 @@
 #include "BKE_linestyle.h"
 #include "BKE_node.h"
 #include "BKE_scene.h"
+#include "BKE_library.h"
 
 #include "RNA_access.h"
 
@@ -551,28 +552,28 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
   return displacement->link != NULL;
 }
 
-static bool ntree_shader_relink_node_normal(bNodeTree *ntree,
+static void 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;
+  for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+    if (STREQ(sock->identifier, "Normal") && sock->link == NULL) {
+      /* It's a normal input and nothing is connected to it. */
+      nodeAddLink(ntree, node_from, socket_from, node, sock);
+    }
+    else if (sock->link) {
+      bNodeLink *link = sock->link;
+      if (ELEM(link->fromnode->type, SH_NODE_NEW_GEOMETRY, SH_NODE_TEX_COORD) &&
+          STREQ(link->fromsock->identifier, "Normal")) {
+        /* Linked to a geometry node normal output. */
+        nodeAddLink(ntree, node_from, socket_from, node, sock);
+      }
+    }
   }
-  /* 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,
@@ -596,45 +597,8 @@ static void ntree_shader_link_builtin_group_normal(bNodeTree *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);
-    if (group_output_node == NULL) {
-      return;
-    }
-    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);
+    /* This should never happen as all displacement nodes are duplicated and tagged. */
+    BLI_assert(0);
   }
   else if (group_input_node) {
     /* Connect group node normal input. */
@@ -665,6 +629,10 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
       /* Don't connect node itself! */
       continue;
     }
+    if (node->tmp_flag == -2) {
+      /* This node is used inside the displacement tree. Skip to avoid cycles. */
+      continue;
+    }
     if ((ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) && node->id) {
       /* Special re-linking for group nodes. */
       ntree_shader_link_builtin_group_normal(
@@ -679,6 +647,127 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
   }
 }
 
+static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bNodeLink *bump_link)
+{
+  /* Bypass bump nodes. This replicates cycles "implicit" behavior. */
+  bNodeSocket *bump_normal_input = ntree_shader_node_find_input(bump_node, "Normal");
+  bNode *fromnode;
+  bNodeSocket *fromsock;
+  /* Default to builtin normals if there is no link. */
+  if (bump_normal_input->link) {
+    fromsock = bump_normal_input->link->fromsock;
+    fromnode = bump_normal_input->link->fromnode;
+  }
+  else {
+    fromnode = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+    fromsock = ntree_shader_node_find_output(fromnode, "Normal");
+  }
+  /* Bypass the bump node by creating a link between the previous and next node. */
+  nodeAddLink(ntree, fromnode, fromsock, bump_link->tonode, bump_link->tosock);
+  nodeRemLink(ntree, bump_link);
+}
+
+static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
+{
+  /* Bypass bump links inside copied nodes */
+  bNodeLink *link, *link_next;
+  for (link = ntree->links.first; link; link = link_next) {
+    /* link might be freed by ntree_shader_bypass_bump_link. */
+    link_next = link->next;
+    bNode *node = link->fromnode;
+    /* If node is a copy. */
+    if (node->tmp_flag == -2 && node->type == SH_NODE_BUMP) {
+      ntree_shader_bypass_bump_link(ntree, node, link);
+    }
+  }
+  /* Do the same inside nodegroups. */
+  LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+    /* If node is a copy. */
+    if (node->tmp_flag == -2 && ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id) {
+      bNodeTree *group_ntree = (bNodeTree *)node->id;
+      /* Tag all nodes inside this group as copies. */
+      LISTBASE_FOREACH (bNode *, group_node, &group_ntree->nodes) {
+        group_node->tmp_flag = -2;
+      }
+      /* Recursive. */
+      ntree_shader_bypass_tagged_bump_nodes(group_ntree);
+    }
+  }
+  ntreeUpdateTree(G.main, ntree);
+}
+
+static bool ntree_branch_count_and_tag_nodes(bNode *fromnode,
+                                             bNode *tonode,
+                                             void *userdata,
+                                             const bool UNUSED(reversed))
+{
+  int *node_count = (int *)userdata;
+  if (fromnode->tmp_flag == -1) {
+    fromnode->tmp_flag = *node_count;
+    (*node_count)++;
+  }
+  if (tonode->tmp_flag == -1) {
+    tonode->tmp_flag = *node_count;
+    (*node_count)++;
+  }
+  return true;
+}
+
+static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
+                                                  bNode *displacement_node,
+                                                  bNodeSocket *displacement_socket,
+                                                  bNodeLink *displacement_link)
+{
+  /* Init tmp flag. */
+  LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+    node->tmp_flag = -1;
+  }
+  /* Count and tag all nodes inside the displacement branch of the tree. */
+  displacement_node->tmp_flag = 0;
+  int node_count = 1;
+  nodeChainIter(ntree, displacement_node, ntree_branch_count_and_tag_nodes, &node_count, true);
+  /* Make a full copy of the branch */
+  bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
+  LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+    if (node->tmp_flag >= 0) {
+      int id = node->tmp_flag;
+      nodes_copy[id] = BKE_node_copy_ex(ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT);
+      nodes_copy[id]->tmp_flag = -2; /* Copy */
+      if (ELEM(nodes_copy[id]->type, NODE_GROUP, NODE_CUSTOM_GROUP) && nodes_copy[id]->id) {
+        nodes_copy[id]->id = (ID *)ntreeLocalize((bNodeTree *)nodes_copy[id]->id);
+      }
+      /* Make sure to clear all sockets links as they are invalid. */
+      LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
+        sock->link = NULL;
+      }
+      LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->outputs) {
+        sock->link = NULL;
+      }
+    }
+  }
+  /* Recreate links between copied nodes. */
+  LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+    if (link->fromnode->tmp_flag >= 0 && link->tonode->tmp_flag >= 0) {
+      bNode *fromnode = nodes_copy[link->fromnode->tmp_flag];
+      bNode *tonode = nodes_copy[link->tonode->tmp_flag];
+      bNodeSocket *fromsock = ntree_shader_node_find_output(fromnode, link->fromsock->identifier);
+      bNodeSocket *tosock = ntree_shader_node_find_input(tonode, link->tosock->identifier);
+      nodeAddLink(ntree, fromnode, fromsock, tonode, tosock);
+    }
+  }
+  /* Replace displacement socket/node/link. */
+  bNode *tonode = displacement_link->tonode;
+  bNodeSocket *tosock = displacement_link->tosock;
+  displacement_node = nodes_copy[displacement_node->tmp_flag];
+  displacement_socket = ntree_shader_node_find_output(displacement_node,
+                                                      displacement_socket->identifier);
+  nodeRemLink(ntree, displacement_link);
+  nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
+  MEM_freeN(nodes_copy);
+
+  ntreeUpdateTree(G.main, ntree);
+}
+
 /* Re-link displacement output to unconnected normal sockets via bump nod

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list