Texture paint: properly implement image slots for principled BSDF node.
authorSebastian Parborg <zeddb>
Mon, 10 Sep 2018 16:18:04 +0000 (18:18 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Mon, 10 Sep 2018 16:56:54 +0000 (18:56 +0200)
Now we can create new base color, roughness, metallic, specular, normal,
bump and displacement images, and linked them to the appropriate socket.

Also fixes image nodes inside groups not being visible.

Differential Revision: https://developer.blender.org/D3679

source/blender/blenkernel/intern/material.c
source/blender/editors/sculpt_paint/paint_image_proj.c

index ba46c6ca8252781610e7a4c9c1ee3630dde12fe9..9280f95a803b305d1dcca2ec6e558017506a0bb0 100644 (file)
@@ -1030,10 +1030,58 @@ static bNode *nodetree_uv_node_recursive(bNode *node)
        return NULL;
 }
 
+static int count_texture_nodes_recursive(bNodeTree *nodetree)
+{
+       int tex_nodes = 0;
+
+       for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+               if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+                       tex_nodes++;
+               }
+               else if (node->type == NODE_GROUP) {
+                       /* recurse into the node group and see if it contains any textures */
+                       tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id);
+               }
+       }
+
+       return tex_nodes;
+}
+
+static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, Material *ma, int *index)
+{
+       for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+               if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+                       if (active_node == node) {
+                               ma->paint_active_slot = *index;
+                       }
+                       ma->texpaintslot[*index].ima = (Image *)node->id;
+
+                       /* for new renderer, we need to traverse the treeback in search of a UV node */
+                       bNode *uvnode = nodetree_uv_node_recursive(node);
+
+                       if (uvnode) {
+                               NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+                               ma->texpaintslot[*index].uvname = storage->uv_map;
+                               /* set a value to index so UI knows that we have a valid pointer for the mesh */
+                               ma->texpaintslot[*index].valid = true;
+                       }
+                       else {
+                               /* just invalidate the index here so UV map does not get displayed on the UI */
+                               ma->texpaintslot[*index].valid = false;
+                       }
+                       (*index)++;
+               }
+               else if (node->type == NODE_GROUP) {
+                       /* recurse into the node group and see if it contains any textures */
+                       fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index);
+               }
+       }
+}
+
 void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
 {
-       short count = 0;
-       short index = 0;
+       int count = 0;
+       int index = 0;
 
        if (!ma)
                return;
@@ -1050,50 +1098,25 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
                return;
        }
 
-       bNode *node, *active_node;
-
        if (!(ma->nodetree)) {
                ma->paint_active_slot = 0;
                ma->paint_clone_slot = 0;
                return;
        }
 
-       for (node = ma->nodetree->nodes.first; node; node = node->next) {
-               if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
-                       count++;
-       }
+       count = count_texture_nodes_recursive(ma->nodetree);
 
        if (count == 0) {
                ma->paint_active_slot = 0;
                ma->paint_clone_slot = 0;
                return;
        }
-       ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
-
-       active_node = nodeGetActiveTexture(ma->nodetree);
 
-       for (node = ma->nodetree->nodes.first; node; node = node->next) {
-               if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
-                       if (active_node == node)
-                               ma->paint_active_slot = index;
-                       ma->texpaintslot[index].ima = (Image *)node->id;
+       ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
 
-                       /* for new renderer, we need to traverse the treeback in search of a UV node */
-                       bNode *uvnode = nodetree_uv_node_recursive(node);
+       bNode *active_node = nodeGetActiveTexture(ma->nodetree);
 
-                       if (uvnode) {
-                               NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
-                               ma->texpaintslot[index].uvname = storage->uv_map;
-                               /* set a value to index so UI knows that we have a valid pointer for the mesh */
-                               ma->texpaintslot[index].valid = true;
-                       }
-                       else {
-                               /* just invalidate the index here so UV map does not get displayed on the UI */
-                               ma->texpaintslot[index].valid = false;
-                       }
-                       index++;
-               }
-       }
+       fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index);
 
        ma->tot_slots = count;
 
index 7badd30e6d054203c011f03f27a43db734770f36..386ae315b9393c92a0bc35c366c588cdcadf15f6 100644 (file)
@@ -5612,13 +5612,24 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m
 }
 
 /* Add layer operator */
+enum {
+       LAYER_BASE_COLOR,
+       LAYER_SPECULAR,
+       LAYER_ROUGHNESS,
+       LAYER_METALLIC,
+       LAYER_NORMAL,
+       LAYER_BUMP,
+       LAYER_DISPLACEMENT
+};
 
 static const EnumPropertyItem layer_type_items[] = {
-       {0, "BASE_COLOR", 0, "Base Color", ""},
-       {1, "EMISSION", 0, "Emission", ""},
-       {2, "NORMAL", 0, "Normal", ""},
-       {3, "BUMP", 0, "Bump", ""},
-       {4, "DISPLACEMENT", 0, "Displacement", ""},
+       {LAYER_BASE_COLOR, "BASE_COLOR", 0, "Base Color", ""},
+       {LAYER_SPECULAR, "SPECULAR", 0, "Specular", ""},
+       {LAYER_ROUGHNESS, "ROUGHNESS", 0, "Roughness", ""},
+       {LAYER_METALLIC, "METALLIC", 0, "Metallic", ""},
+       {LAYER_NORMAL, "NORMAL", 0, "Normal", ""},
+       {LAYER_BUMP, "BUMP", 0, "Bump", ""},
+       {LAYER_DISPLACEMENT, "DISPLACEMENT", 0, "Displacement", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
@@ -5662,8 +5673,8 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
        ma = give_current_material(ob, ob->actcol);
 
        if (ma) {
-               /* TODO: use type to link to proper socket. */
                Main *bmain = CTX_data_main(C);
+               int type = RNA_enum_get(op->ptr, "type");
 
                bNode *imanode;
                bNodeTree *ntree = ma->nodetree;
@@ -5683,6 +5694,67 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
 
                nodeSetActive(ntree, imanode);
 
+               /* Connect to first available principled bsdf node. */
+               bNode *in_node;
+               in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
+
+               if (in_node != NULL) {
+                       bNode *out_node = imanode;
+                       bNodeSocket *out_sock = nodeFindSocket(out_node, SOCK_OUT, "Color");
+                       bNodeSocket *in_sock = NULL;
+
+                       if (type >= LAYER_BASE_COLOR && type < LAYER_NORMAL) {
+                               in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+                       }
+                       else if (type == LAYER_NORMAL) {
+                               bNode *nor_node;
+                               nor_node = nodeAddStaticNode(C, ntree, SH_NODE_NORMAL_MAP);
+
+                               in_sock = nodeFindSocket(nor_node, SOCK_IN, "Color");
+                               nodeAddLink(ntree, out_node, out_sock, nor_node, in_sock);
+
+                               in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+                               out_sock = nodeFindSocket(nor_node, SOCK_OUT, "Normal");
+
+                               out_node = nor_node;
+                       }
+                       else if (type == LAYER_BUMP) {
+                               bNode *bump_node;
+                               bump_node = nodeAddStaticNode(C, ntree, SH_NODE_BUMP);
+
+                               in_sock = nodeFindSocket(bump_node, SOCK_IN, "Height");
+                               nodeAddLink(ntree, out_node, out_sock, bump_node, in_sock);
+
+                               in_sock = nodeFindSocket(in_node, SOCK_IN, "Normal");
+                               out_sock = nodeFindSocket(bump_node, SOCK_OUT, "Normal");
+
+                               out_node = bump_node;
+                       }
+                       else if (type == LAYER_DISPLACEMENT) {
+                               /* Connect to the displacement output socket */
+                               in_node = ntreeFindType(ntree, SH_NODE_OUTPUT_MATERIAL);
+
+                               if (in_node != NULL) {
+                                       in_sock = nodeFindSocket(in_node, SOCK_IN, layer_type_items[type].name);
+                               }
+                               else {
+                                       in_sock = NULL;
+                               }
+                       }
+
+                       if (type > LAYER_BASE_COLOR) {
+                               /* This is a "non color data" image */
+                               NodeTexImage* tex = imanode->storage;
+                               tex->color_space = SHD_COLORSPACE_NONE;
+                       }
+
+                       /* Check if the socket in already connected to something */
+                       bNodeLink *link = in_sock ? in_sock->link : NULL;
+                       if (in_sock != NULL && link == NULL) {
+                               nodeAddLink(ntree, out_node, out_sock, in_node, in_sock);
+                       }
+               }
+
                ntreeUpdateTree(CTX_data_main(C), ntree);
 
                if (ima) {