Tweak behavior of object.to_mesh()
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 27 Mar 2019 21:28:44 +0000 (22:28 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 1 Apr 2019 12:49:23 +0000 (14:49 +0200)
- Passing original object with apply_modifiers=false will give a
  non-modified non-deformed mesh.
  The result mesh will point to datablocks from the original "domain". For
  example, materials will be original.

- Passing original object with apply_modifiers=true will give a mesh which
  has all modifiers applied.
  The result mesh will point to datablocks from the original "domain". For
  example, materials will be original.

- Passing evaluated object will ignore apply_modifiers argument, and the
  result always contains all modifiers applied.
  The result mesh will point to an evaluated datablocks. For example,
  materials will be an evaluated IDs from the dependency graph.

Fixes T62916: Applying boolean modifier does not set material properly

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

source/blender/blenkernel/intern/mesh_convert.c

index f02f1c2..f9ab61f 100644 (file)
@@ -837,7 +837,25 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
        }
 }
 
-/* settings: 1 - preview, 2 - render */
+/* settings: 1 - preview, 2 - render
+ *
+ * The convention goes as following:
+ *
+ * - Passing original object with apply_modifiers=false will give a
+ *   non-modified non-deformed mesh.
+ *   The result mesh will point to datablocks from the original "domain". For
+ *   example, materials will be original.
+ *
+ * - Passing original object with apply_modifiers=true will give a mesh which
+ *   has all modifiers applied.
+ *   The result mesh will point to datablocks from the original "domain". For
+ *   example, materials will be original.
+ *
+ * - Passing evaluated object will ignore apply_modifiers argument, and the
+ *   result always contains all modifiers applied.
+ *   The result mesh will point to an evaluated datablocks. For example,
+ *   materials will be an evaluated IDs from the dependency graph.
+ */
 Mesh *BKE_mesh_new_from_object(
         Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
         const bool apply_modifiers, const bool calc_undeformed)
@@ -846,11 +864,28 @@ Mesh *BKE_mesh_new_from_object(
        Curve *tmpcu = NULL, *copycu;
        int i;
        const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
-       const bool cage = !apply_modifiers;
+       bool effective_apply_modifiers = apply_modifiers;
        bool do_mat_id_data_us = true;
 
+       Object *object_input = ob;
+       Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input);
+       Object object_for_eval = *object_eval;
+
+       if (object_eval == object_input) {
+               effective_apply_modifiers = false;
+       }
+       else {
+               if (apply_modifiers) {
+                       if (object_for_eval.runtime.mesh_orig != NULL) {
+                               object_for_eval.data = object_for_eval.runtime.mesh_orig;
+                       }
+               }
+       }
+
+       const bool cage = !effective_apply_modifiers;
+
        /* perform the mesh extraction based on type */
-       switch (ob->type) {
+       switch (object_for_eval.type) {
                case OB_FONT:
                case OB_CURVE:
                case OB_SURF:
@@ -861,7 +896,7 @@ Mesh *BKE_mesh_new_from_object(
 
                        /* copies object and modifiers (but not the data) */
                        Object *tmpobj;
-                       BKE_id_copy_ex(NULL, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
+                       BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
                        tmpcu = (Curve *)tmpobj->data;
 
                        /* Copy cached display list, it might be needed by the stack evaluation.
@@ -870,11 +905,11 @@ Mesh *BKE_mesh_new_from_object(
                         *
                         * TODO(sergey): Look into more proper solution.
                         */
-                       if (ob->runtime.curve_cache != NULL) {
+                       if (object_for_eval.runtime.curve_cache != NULL) {
                                if (tmpobj->runtime.curve_cache == NULL) {
                                        tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
                                }
-                               BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp);
+                               BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &object_for_eval.runtime.curve_cache->disp);
                        }
 
                        /* if getting the original caged mesh, delete object modifiers */
@@ -882,7 +917,7 @@ Mesh *BKE_mesh_new_from_object(
                                BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
 
                        /* copies the data, but *not* the shapekeys. */
-                       BKE_id_copy_ex(NULL, ob->data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
+                       BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
                        tmpobj->data = copycu;
 
                        /* make sure texture space is calculated for a copy of curve,
@@ -938,32 +973,34 @@ Mesh *BKE_mesh_new_from_object(
                case OB_MBALL:
                {
                        /* metaballs don't have modifiers, so just convert to mesh */
-                       Object *basis_ob = BKE_mball_basis_find(sce, ob);
+                       Object *basis_ob = BKE_mball_basis_find(sce, object_input);
                        /* todo, re-generatre for render-res */
                        /* metaball_polygonize(scene, ob) */
 
-                       if (ob != basis_ob)
-                               return NULL;  /* only do basis metaball */
+                       if (basis_ob != object_input) {
+                               /* Only do basis metaball. */
+                               return NULL;
+                       }
 
-                       tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
+                       tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
                        /* BKE_mesh_add gives us a user count we don't need */
                        id_us_min(&tmpmesh->id);
 
                        if (render) {
                                ListBase disp = {NULL, NULL};
-                               BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp);
+                               BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp);
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                                BKE_displist_free(&disp);
                        }
                        else {
                                ListBase disp = {NULL, NULL};
-                               if (ob->runtime.curve_cache) {
-                                       disp = ob->runtime.curve_cache->disp;
+                               if (object_for_eval.runtime.curve_cache) {
+                                       disp = object_for_eval.runtime.curve_cache->disp;
                                }
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                        }
 
-                       BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
+                       BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval);
 
                        break;
 
@@ -972,7 +1009,7 @@ Mesh *BKE_mesh_new_from_object(
                        /* copies object and modifiers (but not the data) */
                        if (cage) {
                                /* copies the data (but *not* the shapekeys). */
-                               Mesh *mesh = ob->data;
+                               Mesh *mesh = object_for_eval.data;
                                BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
                                /* XXX BKE_mesh_copy() already handles materials usercount. */
                                do_mat_id_data_us = false;
@@ -982,24 +1019,24 @@ Mesh *BKE_mesh_new_from_object(
                                /* Make a dummy mesh, saves copying */
                                Mesh *me_eval;
                                CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
-                                                                      * for example, needs CD_MASK_MDEFORMVERT */
+                                                                          * for example, needs CD_MASK_MDEFORMVERT */
 
                                if (calc_undeformed) {
                                        mask.vmask |= CD_MASK_ORCO;
                                }
 
                                if (render) {
-                                       me_eval = mesh_create_eval_final_render(depsgraph, sce, ob, &mask);
+                                       me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask);
                                }
                                else {
-                                       me_eval = mesh_create_eval_final_view(depsgraph, sce, ob, &mask);
+                                       me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask);
                                }
 
-                               tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
-                               BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, ob, &mask, true);
+                               tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
+                               BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true);
 
                                /* Copy autosmooth settings from original mesh. */
-                               Mesh *me = (Mesh *)ob->data;
+                               Mesh *me = (Mesh *)object_for_eval.data;
                                tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
                                tmpmesh->smoothresh = me->smoothresh;
                        }
@@ -1014,7 +1051,7 @@ Mesh *BKE_mesh_new_from_object(
        }
 
        /* Copy materials to new mesh */
-       switch (ob->type) {
+       switch (object_for_eval.type) {
                case OB_SURF:
                case OB_FONT:
                case OB_CURVE:
@@ -1024,9 +1061,9 @@ Mesh *BKE_mesh_new_from_object(
                        if (tmpcu->mat) {
                                for (i = tmpcu->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
-                                       tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                       tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
-                                       if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
+                                       if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
@@ -1035,7 +1072,7 @@ Mesh *BKE_mesh_new_from_object(
 
                case OB_MBALL:
                {
-                       MetaBall *tmpmb = (MetaBall *)ob->data;
+                       MetaBall *tmpmb = (MetaBall *)object_for_eval.data;
                        tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
                        tmpmesh->totcol = tmpmb->totcol;
 
@@ -1043,9 +1080,9 @@ Mesh *BKE_mesh_new_from_object(
                        if (tmpmb->mat) {
                                for (i = tmpmb->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
-                                       tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                       tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
-                                       if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
+                                       if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
@@ -1055,7 +1092,7 @@ Mesh *BKE_mesh_new_from_object(
 
                case OB_MESH:
                        if (!cage) {
-                               Mesh *origmesh = ob->data;
+                               Mesh *origmesh = object_for_eval.data;
                                tmpmesh->flag = origmesh->flag;
                                tmpmesh->mat = MEM_dupallocN(origmesh->mat);
                                tmpmesh->totcol = origmesh->totcol;
@@ -1063,9 +1100,9 @@ Mesh *BKE_mesh_new_from_object(
                                if (origmesh->mat) {
                                        for (i = origmesh->totcol; i-- > 0; ) {
                                                /* are we an object material or data based? */
-                                               tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                               tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
-                                               if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
+                                               if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
                                                        id_us_plus(&tmpmesh->mat[i]->id);
                                                }
                                        }