Fix T63252: Bind in Mesh Deform Modifier fails
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 4 Apr 2019 12:42:33 +0000 (14:42 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 4 Apr 2019 13:49:30 +0000 (15:49 +0200)
A regression since 64c8d72ef1ad.

The solution is to force modifier evaluation for an evaluated
object, and let it to copy binding data back to original when
is being evaluated for binding.

Reviewers: brecht

Reviewed By: brecht

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

source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/intern/modifier.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/object/object_modifier.c
source/blender/modifiers/intern/MOD_correctivesmooth.c
source/blender/modifiers/intern/MOD_meshdeform.c
source/blender/modifiers/intern/MOD_surfacedeform.c

index a375ed3..9f522c1 100644 (file)
@@ -403,6 +403,16 @@ void        modifier_path_init(char *path, int path_maxlen, const char *name);
 const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
 const char *modifier_path_relbase_from_global(struct Object *ob);
 
+/* Accessors of original/evaluated modifiers. */
+
+/* For a given modifier data, get corresponding original one.
+ * If the modifier data is already original, return it as-is. */
+struct ModifierData *modifier_get_original(struct ModifierData *md);
+struct ModifierData *modifier_get_evaluated(
+        struct Depsgraph* depsgraph,
+        struct Object *object,
+        struct ModifierData *md);
+
 /* wrappers for modifier callbacks that ensure valid normals */
 
 struct Mesh *modwrap_applyModifier(
index fe955ce..8f52e57 100644 (file)
@@ -885,3 +885,23 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, con
 
        return me;
 }
+
+ModifierData *modifier_get_original(ModifierData *md)
+{
+       if (md->orig_modifier_data == NULL) {
+               return md;
+       }
+       return md->orig_modifier_data;
+}
+
+struct ModifierData *modifier_get_evaluated(
+        Depsgraph* depsgraph,
+        Object *object,
+        ModifierData *md)
+{
+       Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+       if (object_eval == object) {
+               return md;
+       }
+       return modifiers_findByName(object_eval, md->name);
+}
index 34fea2e..66bd7a8 100644 (file)
@@ -1577,6 +1577,8 @@ void ED_mesh_deform_bind_callback(
         MeshDeformModifierData *mmd, Mesh *cagemesh,
         float *vertexcos, int totvert, float cagemat[4][4])
 {
+       MeshDeformModifierData *mmd_orig =
+               (MeshDeformModifierData *)modifier_get_original(&mmd->modifier);
        MeshDeformBind mdb;
        MVert *mvert;
        int a;
@@ -1602,23 +1604,23 @@ void ED_mesh_deform_bind_callback(
                mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
 
        /* solve */
-       harmonic_coordinates_bind(mmd, &mdb);
+       harmonic_coordinates_bind(mmd_orig, &mdb);
 
        /* assign bind variables */
-       mmd->bindcagecos = (float *)mdb.cagecos;
-       mmd->totvert = mdb.totvert;
-       mmd->totcagevert = mdb.totcagevert;
-       copy_m4_m4(mmd->bindmat, mmd->object->obmat);
+       mmd_orig->bindcagecos = (float *)mdb.cagecos;
+       mmd_orig->totvert = mdb.totvert;
+       mmd_orig->totcagevert = mdb.totcagevert;
+       copy_m4_m4(mmd_orig->bindmat, mmd_orig->object->obmat);
 
        /* transform bindcagecos to world space */
        for (a = 0; a < mdb.totcagevert; a++)
-               mul_m4_v3(mmd->object->obmat, mmd->bindcagecos + a * 3);
+               mul_m4_v3(mmd_orig->object->obmat, mmd_orig->bindcagecos + a * 3);
 
        /* free */
        MEM_freeN(mdb.vertexcos);
 
        /* compact weights */
-       modifier_mdef_compact_influences((ModifierData *)mmd);
+       modifier_mdef_compact_influences((ModifierData *)mmd_orig);
 
        end_progress_bar();
        waitcursor(0);
index c3a562d..1944d29 100644 (file)
@@ -93,23 +93,38 @@ static void modifier_skin_customdata_delete(struct Object *ob);
 
 /******************************** API ****************************/
 
-static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Scene *scene, Object *ob)
+static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object *ob)
 {
+       Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+       Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+       BKE_object_eval_reset(ob_eval);
        if (ob->type == OB_MESH) {
-               Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene, ob, &CD_MASK_BAREMESH);
+               Mesh *me_eval = mesh_create_eval_final_view(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
                BKE_id_free(NULL, me_eval);
        }
        else if (ob->type == OB_LATTICE) {
-               BKE_lattice_modifiers_calc(depsgraph, scene, ob);
+               BKE_lattice_modifiers_calc(depsgraph, scene_eval, ob_eval);
        }
        else if (ob->type == OB_MBALL) {
-               BKE_displist_make_mball(depsgraph, scene, ob);
+               BKE_displist_make_mball(depsgraph, scene_eval, ob_eval);
        }
        else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
-               BKE_displist_make_curveTypes(depsgraph, scene, ob, false, false, NULL);
+               BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false, false, NULL);
        }
 }
 
+static void object_force_modifier_bind_simple_options(
+        Depsgraph *depsgraph,
+        Object *object,
+        ModifierData *md)
+{
+       ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md);
+       const int mode = md_eval->mode;
+       md_eval->mode |= eModifierMode_Realtime;
+       object_force_modifier_update_for_bind(depsgraph, object);
+       md_eval->mode = mode;
+}
+
 ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
 {
        ModifierData *md = NULL, *new_md = NULL;
@@ -1926,19 +1941,17 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
                csmd->bind_coords_num = 0;
        }
        else {
-               /* signal to modifier to recalculate */
-               csmd->bind_coords_num = (unsigned int)-1;
+               /* Signal to modifier to recalculate. */
+               CorrectiveSmoothModifierData *csmd_eval =
+                       (CorrectiveSmoothModifierData *)modifier_get_evaluated(depsgraph, ob, &csmd->modifier);
+               csmd_eval->bind_coords_num = (unsigned int)-1;
 
                /* Force modifier to run, it will call binding routine
                 * (this has to happen outside of depsgraph evaluation). */
-               const int mode = csmd->modifier.mode;
-               csmd->modifier.mode |= eModifierMode_Realtime;
-               object_force_modifier_update_for_bind(depsgraph, scene, ob);
-               csmd->modifier.mode = mode;
+               object_force_modifier_bind_simple_options(depsgraph, ob, &csmd->modifier);
        }
 
-       /* We need ID_RECALC_COPY_ON_WRITE to ensure (un)binding is flushed to CoW copies of the object... */
-       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
 
        return OPERATOR_FINISHED;
@@ -1979,7 +1992,6 @@ static bool meshdeform_poll(bContext *C)
 static int meshdeform_bind_exec(bContext *C, wmOperator *op)
 {
        Depsgraph *depsgraph = CTX_data_depsgraph(C);
-       Scene *scene = CTX_data_scene(C);
        Object *ob = ED_object_active_context(C);
        MeshDeformModifierData *mmd = (MeshDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_MeshDeform);
 
@@ -2002,16 +2014,14 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
        }
        else {
                /* Force modifier to run, it will call binding routine (this has to happen outside of depsgraph evaluation). */
-               const int mode = mmd->modifier.mode;
-               mmd->modifier.mode |= eModifierMode_Realtime;
-               mmd->bindfunc = ED_mesh_deform_bind_callback;
-               object_force_modifier_update_for_bind(depsgraph, scene, ob);
-               mmd->modifier.mode = mode;
-               mmd->bindfunc = NULL;
+               MeshDeformModifierData *mmd_eval =
+                       (MeshDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &mmd->modifier);
+               mmd_eval->bindfunc = ED_mesh_deform_bind_callback;
+               object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier);
+               mmd_eval->bindfunc = NULL;
        }
 
-       /* We need ID_RECALC_COPY_ON_WRITE to ensure (un)binding is flushed to CoW copies of the object... */
-       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
        return OPERATOR_FINISHED;
 }
@@ -2188,7 +2198,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
 
        if (free) {
                BKE_ocean_free_modifier_cache(omd);
-               DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+               DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
                WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
                return OPERATOR_FINISHED;
        }
@@ -2288,7 +2298,6 @@ static bool laplaciandeform_poll(bContext *C)
 
 static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene = CTX_data_scene(C);
        Object *ob = ED_object_active_context(C);
        Depsgraph *depsgraph = CTX_data_depsgraph(C);
        LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_LaplacianDeform);
@@ -2304,15 +2313,25 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
                lmd->flag |= MOD_LAPLACIANDEFORM_BIND;
        }
 
+       LaplacianDeformModifierData *lmd_eval =
+               (LaplacianDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &lmd->modifier);
+       lmd_eval->flag = lmd->flag;
+
        /* Force modifier to run, it will call binding routine
         * (this has to happen outside of depsgraph evaluation). */
-       const int mode = lmd->modifier.mode;
-       lmd->modifier.mode |= eModifierMode_Realtime;
-       object_force_modifier_update_for_bind(depsgraph, scene, ob);
-       lmd->modifier.mode = mode;
+       object_force_modifier_bind_simple_options(depsgraph, ob, &lmd->modifier);
 
-       /* We need ID_RECALC_COPY_ON_WRITE to ensure (un)binding is flushed to CoW copies of the object... */
-       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+       /* This is hard to know from the modifier itself whether the evaluation is
+        * happening for binding or not. So we copy all the required data here. */
+       lmd->total_verts = lmd_eval->total_verts;
+       if (lmd_eval->vertexco == NULL) {
+               MEM_SAFE_FREE(lmd->vertexco);
+       }
+       else {
+               lmd->vertexco = MEM_dupallocN(lmd_eval->vertexco);
+       }
+
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
        return OPERATOR_FINISHED;
 }
@@ -2351,7 +2370,6 @@ static bool surfacedeform_bind_poll(bContext *C)
 
 static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene = CTX_data_scene(C);
        Object *ob = ED_object_active_context(C);
        Depsgraph *depsgraph = CTX_data_depsgraph(C);
        SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)edit_modifier_property_get(op, ob, eModifierType_SurfaceDeform);
@@ -2367,15 +2385,15 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
                smd->flags |= MOD_SDEF_BIND;
        }
 
+       SurfaceDeformModifierData *smd_eval =
+               (SurfaceDeformModifierData *)modifier_get_evaluated(depsgraph, ob, &smd->modifier);
+       smd_eval->flags = smd->flags;
+
        /* Force modifier to run, it will call binding routine
         * (this has to happen outside of depsgraph evaluation). */
-       const int mode = smd->modifier.mode;
-       smd->modifier.mode |= eModifierMode_Realtime;
-       object_force_modifier_update_for_bind(depsgraph, scene, ob);
-       smd->modifier.mode = mode;
+       object_force_modifier_bind_simple_options(depsgraph, ob, &smd->modifier);
 
-       /* We need ID_RECALC_COPY_ON_WRITE to ensure (un)binding is flushed to CoW copies of the object... */
-       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+       DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
        WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
        return OPERATOR_FINISHED;
 }
index ac1c0d4..d9e6ed7 100644 (file)
@@ -45,6 +45,9 @@
 #include "BLI_strict_flags.h"
 
 
+#include "DEG_depsgraph_query.h"
+
+
 // #define DEBUG_TIME
 
 #include "PIL_time.h"
@@ -558,7 +561,7 @@ static void calc_deltas(
 
 
 static void correctivesmooth_modifier_do(
-        ModifierData *md, Object *ob, Mesh *mesh,
+        ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh,
         float (*vertexCos)[3], unsigned int numVerts,
         struct BMEditMesh *em)
 {
@@ -580,10 +583,20 @@ static void correctivesmooth_modifier_do(
            /* signal to recalculate, whoever sets MUST also free bind coords */
            (csmd->bind_coords_num == (unsigned int)-1))
        {
-               BLI_assert(csmd->bind_coords == NULL);
-               csmd->bind_coords = MEM_dupallocN(vertexCos);
-               csmd->bind_coords_num = numVerts;
-               BLI_assert(csmd->bind_coords != NULL);
+               if (DEG_is_active(depsgraph)) {
+                       BLI_assert(csmd->bind_coords == NULL);
+                       csmd->bind_coords = MEM_dupallocN(vertexCos);
+                       csmd->bind_coords_num = numVerts;
+                       BLI_assert(csmd->bind_coords != NULL);
+                       /* Copy bound data to the original modifier. */
+                       CorrectiveSmoothModifierData *csmd_orig =
+                               (CorrectiveSmoothModifierData *)modifier_get_original(&csmd->modifier);
+                       csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
+                       csmd_orig->bind_coords_num = csmd->bind_coords_num;
+               }
+               else {
+                       modifier_setError(md, "Attempt to bind from inactive dependency graph");
+               }
        }
 
        if (UNLIKELY(use_only_smooth)) {
@@ -711,7 +724,7 @@ static void deformVerts(
 {
        Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
 
-       correctivesmooth_modifier_do(md, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
+       correctivesmooth_modifier_do(md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, NULL);
 
        if (mesh_src != mesh) {
                BKE_id_free(NULL, mesh_src);
@@ -725,7 +738,7 @@ static void deformVertsEM(
 {
        Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
 
-       correctivesmooth_modifier_do(md, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
+       correctivesmooth_modifier_do(md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (unsigned int)numVerts, editData);
 
        if (mesh_src != mesh) {
                BKE_id_free(NULL, mesh_src);
index 310b05d..7ae03cc 100644 (file)
@@ -298,14 +298,6 @@ static void meshdeformModifier_do(
         */
        Object *ob_target = mmd->object;
        cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
-#if 0  /* This shall not be needed if we always get evaluated target object... */
-       if (cagemesh == NULL && mmd->bindcagecos == NULL && ob == DEG_get_original_object(ob)) {
-               /* Special case, binding happens outside of depsgraph evaluation, so we can build our own
-                * target mesh if needed. */
-               cagemesh = mesh_create_eval_final_view(ctx->depsgraph, DEG_get_input_scene(ctx->depsgraph), mmd->object, &CD_MASK_BAREMESH);
-               free_cagemesh = cagemesh != NULL;
-       }
-#endif
        if (cagemesh == NULL) {
                modifier_setError(md, "Cannot get mesh from cage object");
                return;
@@ -321,13 +313,11 @@ static void meshdeformModifier_do(
        /* bind weights if needed */
        if (!mmd->bindcagecos) {
                /* progress bar redraw can make this recursive .. */
+               if (!DEG_is_active(ctx->depsgraph)) {
+                       modifier_setError(md, "Attempt to bind from inactive dependency graph");
+                       goto finally;
+               }
                if (!recursive_bind_sentinel) {
-                       if (ob != DEG_get_original_object(ob)) {
-                               BLI_assert(!"Trying to bind inside of depsgraph evaluation");
-                               modifier_setError(md, "Trying to bind inside of depsgraph evaluation");
-                               goto finally;
-                       }
-
                        recursive_bind_sentinel = 1;
                        mmd->bindfunc(mmd, cagemesh, (float *)vertexCos, numVerts, cagemat);
                        recursive_bind_sentinel = 0;
index 44307b4..46f4f9c 100644 (file)
@@ -1124,7 +1124,7 @@ static void deformVert(
 
 static void surfacedeformModifier_do(
         ModifierData *md,
-        const ModifierEvalContext *UNUSED(ctx),
+        const ModifierEvalContext *ctx,
         float (*vertexCos)[3], unsigned int numverts, Object *ob)
 {
        SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
@@ -1133,30 +1133,19 @@ static void surfacedeformModifier_do(
 
        /* Exit function if bind flag is not set (free bind data if any). */
        if (!(smd->flags & MOD_SDEF_BIND)) {
-               /* Note: with new CoW system, we expect unbinding to be done by a special call from main thread,
-                * outside of depsgraph evaluation (see object_force_modifier_update_for_bind() in object_modifier.c). */
                if (smd->verts != NULL) {
-                       if (ob != DEG_get_original_object(ob)) {
-                               BLI_assert(!"Trying to unbind inside of depsgraph evaluation");
-                               modifier_setError(md, "Trying to unbind inside of depsgraph evaluation");
-                       }
-                       else {
-                               freeData(md);
+                       if (!DEG_is_active(ctx->depsgraph)) {
+                               modifier_setError(md, "Attempt to bind from inactive dependency graph");
+                               return;
                        }
+                       ModifierData *md_orig = modifier_get_original(md);
+                       freeData(md_orig);
                }
                return;
        }
 
        Object *ob_target = smd->target;
        target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
-#if 0  /* Should not be needed anymore since we always get that mesh from eval object ? */
-       if (target == NULL && smd->verts == NULL && ob == DEG_get_original_object(ob)) {
-               /* Special case, binding happens outside of depsgraph evaluation, so we can build our own
-                * target mesh if needed. */
-               target = mesh_create_eval_final_view(ctx->depsgraph, DEG_get_input_scene(ctx->depsgraph), smd->target, CD_MASK_BAREMESH);
-               free_target = target != NULL;
-       }
-#endif
        if (!target) {
                modifier_setError(md, "No valid target mesh");
                return;
@@ -1166,20 +1155,19 @@ static void surfacedeformModifier_do(
        tnumpoly = target->totpoly;
 
        /* If not bound, execute bind. */
-       /* Note: with new CoW system, we expect binding to be done by a special call from main thread,
-        * outside of depsgraph evaluation (see object_force_modifier_update_for_bind() in object_modifier.c). */
        if (smd->verts == NULL) {
-               if (ob != DEG_get_original_object(ob)) {
-                       BLI_assert(!"Trying to bind inside of depsgraph evaluation");
-                       modifier_setError(md, "Trying to bind inside of depsgraph evaluation");
+               if (!DEG_is_active(ctx->depsgraph)) {
+                       modifier_setError(md, "Attempt to unbind from inactive dependency graph");
                        return;
                }
+
+               SurfaceDeformModifierData *smd_orig = (SurfaceDeformModifierData *)modifier_get_original(md);
                float tmp_mat[4][4];
 
                invert_m4_m4(tmp_mat, ob->obmat);
-               mul_m4_m4m4(smd->mat, tmp_mat, ob_target->obmat);
+               mul_m4_m4m4(smd_orig->mat, tmp_mat, ob_target->obmat);
 
-               if (!surfacedeformBind(smd, vertexCos, numverts, tnumpoly, tnumverts, target)) {
+               if (!surfacedeformBind(smd_orig, vertexCos, numverts, tnumpoly, tnumverts, target)) {
                        smd->flags &= ~MOD_SDEF_BIND;
                }
                /* Early abort, this is binding 'call', no need to perform whole evaluation. */