Eevee: Remove Additive & Multiply Blend mode
authorClément Foucault <foucault.clem@gmail.com>
Mon, 12 Aug 2019 22:11:36 +0000 (00:11 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 14 Aug 2019 11:36:56 +0000 (13:36 +0200)
This commit also provide a compatibility code that will convert old
materials using Additive or Multiply Blend mode to their node equivalent.

This conversion is only done on outputs that are enabled for eevee.

source/blender/blenkernel/BKE_blender_version.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/readfile.h
source/blender/blenloader/intern/versioning_280.c
source/blender/draw/engines/eevee/eevee_materials.c
source/blender/makesdna/DNA_material_types.h
source/blender/makesrna/intern/rna_material.c

index ced9f4a3153d32fe521ddf618ff02a470ccb4a96..0c55ae8ee8308445435116962dba35c5a5604e59 100644 (file)
@@ -27,7 +27,7 @@
  * \note Use #STRINGIFY() rather than defining with quotes.
  */
 #define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 1
+#define BLENDER_SUBVERSION 2
 /** Several breakages with 280, e.g. collections vs layers. */
 #define BLENDER_MINVERSION 280
 #define BLENDER_MINSUBVERSION 0
index 65120fc4c10d4af5c126fffdc7aa42872b57b5a4..bcee606ea7b83590a15d5c06a5f282ca72fcc28f 100644 (file)
@@ -9487,7 +9487,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
   /* don't forget to set version number in BKE_blender_version.h! */
 }
 
-static void do_versions_after_linking(Main *main)
+static void do_versions_after_linking(Main *main, ReportList *reports)
 {
   //  printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
   //         main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
@@ -9495,7 +9495,7 @@ static void do_versions_after_linking(Main *main)
   do_versions_after_linking_250(main);
   do_versions_after_linking_260(main);
   do_versions_after_linking_270(main);
-  do_versions_after_linking_280(main);
+  do_versions_after_linking_280(main, reports);
   do_versions_after_linking_cycles(main);
 }
 
@@ -9798,7 +9798,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
       blo_split_main(&mainlist, bfd->main);
       for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) {
         BLI_assert(mainvar->versionfile != 0);
-        do_versions_after_linking(mainvar);
+        do_versions_after_linking(mainvar, fd->reports);
       }
       blo_join_main(&mainlist);
 
@@ -11569,7 +11569,7 @@ static void library_link_end(Main *mainl,
      * or they will go again through do_versions - bad, very bad! */
     split_main_newid(mainvar, main_newid);
 
-    do_versions_after_linking(main_newid);
+    do_versions_after_linking(main_newid, (*fd)->reports);
 
     add_main_to_main(mainvar, main_newid);
   }
index 7cd5bb7ac934535314f92adbdc0d1a285c7923c5..10ee3d52a744d3b44365fa663054ff18d97388e2 100644 (file)
@@ -187,7 +187,7 @@ void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Mai
 void do_versions_after_linking_250(struct Main *bmain);
 void do_versions_after_linking_260(struct Main *bmain);
 void do_versions_after_linking_270(struct Main *bmain);
-void do_versions_after_linking_280(struct Main *bmain);
+void do_versions_after_linking_280(struct Main *bmain, ReportList *reports);
 void do_versions_after_linking_cycles(struct Main *bmain);
 
 #endif
index 15b4f513050eaa9921df777fffe6f912e2c701a2..254259b15424e5acd1bb4c01e009eaa421dc5520 100644 (file)
@@ -734,7 +734,128 @@ static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase)
   }
 }
 
-void do_versions_after_linking_280(Main *bmain)
+/* Return true if there is something to convert. */
+static bool do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree,
+                                                           char blend_method,
+                                                           GSet *nodegrp_tree_set)
+{
+  bool need_update = false;
+  bool do_conversion = false;
+
+  /* Iterate backwards from end so we don't encounter newly added links. */
+  bNodeLink *prevlink;
+  for (bNodeLink *link = ntree->links.last; link; link = prevlink) {
+    prevlink = link->prev;
+
+    /* Detect link to replace. */
+    bNode *fromnode = link->fromnode;
+    bNodeSocket *fromsock = link->fromsock;
+    bNode *tonode = link->tonode;
+    bNodeSocket *tosock = link->tosock;
+
+    if (nodegrp_tree_set) {
+      if (fromnode->type == NODE_GROUP && fromnode->id != NULL) {
+        bNodeTree *group_ntree = (bNodeTree *)fromnode->id;
+        if (BLI_gset_add(nodegrp_tree_set, group_ntree)) {
+          /* Recursive but not convert (blend_method = -1). Conversion happens after. */
+          if (!do_versions_material_convert_legacy_blend_mode(group_ntree, -1, nodegrp_tree_set)) {
+            /* There is no output to convert in the tree, remove it. */
+            BLI_gset_remove(nodegrp_tree_set, group_ntree, NULL);
+          }
+        }
+      }
+      if (tonode->type == NODE_GROUP && tonode->id != NULL) {
+        bNodeTree *group_ntree = (bNodeTree *)tonode->id;
+        if (BLI_gset_add(nodegrp_tree_set, group_ntree)) {
+          /* Recursive but not convert (blend_method = -1). Conversion happens after. */
+          if (!do_versions_material_convert_legacy_blend_mode(group_ntree, -1, nodegrp_tree_set)) {
+            /* There is no output to convert in the tree, remove it. */
+            BLI_gset_remove(nodegrp_tree_set, group_ntree, NULL);
+          }
+        }
+      }
+    }
+
+    if (!(tonode->type == SH_NODE_OUTPUT_MATERIAL && STREQ(tosock->identifier, "Surface"))) {
+      continue;
+    }
+
+    /* Only do outputs that are enabled for EEVEE */
+    if (!ELEM(tonode->custom1, SHD_OUTPUT_ALL, SHD_OUTPUT_EEVEE)) {
+      continue;
+    }
+
+    do_conversion = true;
+
+    if (blend_method == 1 /* MA_BM_ADD */) {
+      nodeRemLink(ntree, link);
+
+      bNode *add_node = nodeAddStaticNode(NULL, ntree, SH_NODE_ADD_SHADER);
+      add_node->locx = 0.5f * (fromnode->locx + tonode->locx);
+      add_node->locy = 0.5f * (fromnode->locy + tonode->locy);
+
+      bNodeSocket *shader1_socket = add_node->inputs.first;
+      bNodeSocket *shader2_socket = add_node->inputs.last;
+      bNodeSocket *add_socket = nodeFindSocket(add_node, SOCK_OUT, "Shader");
+
+      bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT);
+      transp_node->locx = add_node->locx;
+      transp_node->locy = add_node->locy - 110.0f;
+
+      bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF");
+
+      /* Link to input and material output node. */
+      nodeAddLink(ntree, fromnode, fromsock, add_node, shader1_socket);
+      nodeAddLink(ntree, transp_node, transp_socket, add_node, shader2_socket);
+      nodeAddLink(ntree, add_node, add_socket, tonode, tosock);
+
+      need_update = true;
+    }
+    else if (blend_method == 2 /* MA_BM_MULTIPLY */) {
+      nodeRemLink(ntree, link);
+
+      bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT);
+
+      bNodeSocket *color_socket = nodeFindSocket(transp_node, SOCK_IN, "Color");
+      bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF");
+
+      /* If incomming link is from a closure socket, we need to convert it. */
+      if (fromsock->type == SOCK_SHADER) {
+        transp_node->locx = 0.33f * fromnode->locx + 0.66f * tonode->locx;
+        transp_node->locy = 0.33f * fromnode->locy + 0.66f * tonode->locy;
+
+        bNode *shtorgb_node = nodeAddStaticNode(NULL, ntree, SH_NODE_SHADERTORGB);
+        shtorgb_node->locx = 0.66f * fromnode->locx + 0.33f * tonode->locx;
+        shtorgb_node->locy = 0.66f * fromnode->locy + 0.33f * tonode->locy;
+
+        bNodeSocket *shader_socket = nodeFindSocket(shtorgb_node, SOCK_IN, "Shader");
+        bNodeSocket *rgba_socket = nodeFindSocket(shtorgb_node, SOCK_OUT, "Color");
+
+        nodeAddLink(ntree, fromnode, fromsock, shtorgb_node, shader_socket);
+        nodeAddLink(ntree, shtorgb_node, rgba_socket, transp_node, color_socket);
+      }
+      else {
+        transp_node->locx = 0.5f * (fromnode->locx + tonode->locx);
+        transp_node->locy = 0.5f * (fromnode->locy + tonode->locy);
+
+        nodeAddLink(ntree, fromnode, fromsock, transp_node, color_socket);
+      }
+
+      /* Link to input and material output node. */
+      nodeAddLink(ntree, transp_node, transp_socket, tonode, tosock);
+
+      need_update = true;
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+
+  return do_conversion;
+}
+
+void do_versions_after_linking_280(Main *bmain, ReportList *reports)
 {
   bool use_collection_compat_28 = true;
 
@@ -1129,6 +1250,69 @@ void do_versions_after_linking_280(Main *bmain)
       camera->dof_ob = NULL;
     }
   }
+
+  if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
+    /* Replace Multiply and Additive blend mode by Alpha Blend
+     * now that we use dualsource blending. */
+    /* We take care of doing only nodetrees that are always part of materials
+     * with old blending modes. */
+    GSet *ntrees_additive = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+    GSet *ntrees_multiply = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+    GSet *ntrees_nolegacy = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+    for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
+      bNodeTree *ntree = ma->nodetree;
+      if (ma->blend_method == 1 /* MA_BM_ADD */) {
+        if (ma->use_nodes) {
+          do_versions_material_convert_legacy_blend_mode(ntree, ma->blend_method, ntrees_additive);
+        }
+        ma->blend_method = MA_BM_BLEND;
+      }
+      else if (ma->blend_method == 2 /* MA_BM_MULTIPLY */) {
+        if (ma->use_nodes) {
+          do_versions_material_convert_legacy_blend_mode(ntree, ma->blend_method, ntrees_multiply);
+        }
+        ma->blend_method = MA_BM_BLEND;
+      }
+      else {
+        /* Still tag the group nodes as not using legacy blend modes. */
+        if (ma->use_nodes) {
+          do_versions_material_convert_legacy_blend_mode(ntree, -1, ntrees_nolegacy);
+        }
+      }
+    }
+    /* Remove group nodetree that are used by material using non-legacy blend mode. */
+    GHashIterState iter = {0};
+    bNodeTree *ntree;
+    bool error = false;
+    while (BLI_gset_pop(ntrees_nolegacy, (GSetIterState *)&iter, (void **)&ntree)) {
+      if (BLI_gset_remove(ntrees_additive, ntree, NULL)) {
+        error = true;
+      }
+      if (BLI_gset_remove(ntrees_multiply, ntree, NULL)) {
+        error = true;
+      }
+    }
+    BLI_gset_free(ntrees_nolegacy, NULL);
+    /* Convert remaining group nodetree. */
+    GHashIterState iter_add = {0};
+    GHashIterState iter_mul = {0};
+    while (BLI_gset_pop(ntrees_additive, (GSetIterState *)&iter_add, (void **)&ntree)) {
+      do_versions_material_convert_legacy_blend_mode(ntree, 1 /* MA_BM_ADD */, NULL);
+    }
+    while (BLI_gset_pop(ntrees_multiply, (GSetIterState *)&iter_mul, (void **)&ntree)) {
+      do_versions_material_convert_legacy_blend_mode(ntree, 2 /* MA_BM_MULTIPLY */, NULL);
+    }
+    BLI_gset_free(ntrees_additive, NULL);
+    BLI_gset_free(ntrees_multiply, NULL);
+
+    if (error) {
+      BKE_report(reports, RPT_ERROR, "Eevee material conversion problem. Error in console");
+      printf(
+          "One or more group nodetrees containing a material output were found"
+          " in both a material using deprecated blend mode and a normal one.\n"
+          "Nothing in these nodetrees was changed and manual update is required.\n");
+    }
+  }
 }
 
 /* NOTE: This version patch is intended for versions < 2.52.2,
index ccc2d6ba02023c4dbc39ec15581f2fe585f00185..738745f30723bf967d0e91d3cc33187516d9ae35 100644 (file)
@@ -1474,21 +1474,10 @@ static void material_transparent(Material *ma,
                         DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
                         DRW_STATE_BLEND_CUSTOM);
 
-  DRWState cur_state = DRW_STATE_WRITE_COLOR;
+  DRWState cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
   cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
   cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
 
-  switch (ma->blend_method) {
-    case MA_BM_ADD:
-    case MA_BM_MULTIPLY:
-    case MA_BM_BLEND:
-      cur_state |= DRW_STATE_BLEND_CUSTOM;
-      break;
-    default:
-      BLI_assert(0);
-      break;
-  }
-
   /* Disable other blend modes and use the one we want. */
   DRW_shgroup_state_disable(*shgrp, all_state);
   DRW_shgroup_state_enable(*shgrp, cur_state);
@@ -1564,8 +1553,6 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
                           &shgrp_depth_array[i],
                           &shgrp_depth_clip_array[i]);
           break;
-        case MA_BM_ADD:
-        case MA_BM_MULTIPLY:
         case MA_BM_BLEND:
           material_transparent(ma_array[i],
                                sldata,
index 152ecb85991c1ca7786b3e0f6dc5e761361441d1..1d1ccef8846ca95790b67dd6fb14d1022aa7e00c 100644 (file)
@@ -306,12 +306,12 @@ typedef struct Material {
 
 /* blend_method */
 enum {
-  MA_BM_SOLID,
-  MA_BM_ADD,
-  MA_BM_MULTIPLY,
-  MA_BM_CLIP,
-  MA_BM_HASHED,
-  MA_BM_BLEND,
+  MA_BM_SOLID = 0,
+  // MA_BM_ADD = 1, /* deprecated */
+  // MA_BM_MULTIPLY = 2,  /* deprecated */
+  MA_BM_CLIP = 3,
+  MA_BM_HASHED = 4,
+  MA_BM_BLEND = 5,
 };
 
 /* blend_flag */
index 6378ee1527930a8c06fac5dd8a89a0af24cb0e35..8bfc4bf6313dcf4c8a17c9d8222f55074e52b7c6 100644 (file)
@@ -719,16 +719,6 @@ void RNA_def_material(BlenderRNA *brna)
 
   static EnumPropertyItem prop_eevee_blend_items[] = {
       {MA_BM_SOLID, "OPAQUE", 0, "Opaque", "Render surface without transparency"},
-      {MA_BM_ADD,
-       "ADD",
-       0,
-       "Additive",
-       "Render surface and blend the result with additive blending"},
-      {MA_BM_MULTIPLY,
-       "MULTIPLY",
-       0,
-       "Multiply",
-       "Render surface and blend the result with multiplicative blending"},
       {MA_BM_CLIP,
        "CLIP",
        0,