Transform: generalized custom-data correction support
authorGermano Cavalcante <germano.costa@ig.com.br>
Wed, 1 Jul 2020 07:45:27 +0000 (17:45 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 1 Jul 2020 07:49:38 +0000 (17:49 +1000)
Support custom-data correction based on surrounding geometry for all
transformation modes of the mesh transform operators.

The is the same logic used in Vert and Edge Slide.

In order not to change the current default behavior,
this property does not affect Vert and Edge Slide modes.

12 files changed:
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/bmesh/intern/bmesh_interp.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_convert.h
source/blender/editors/transform/transform_convert_mesh.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_mode.c
source/blender/editors/transform/transform_mode_edge_slide.c
source/blender/editors/transform/transform_mode_vert_slide.c
source/blender/makesdna/DNA_scene_defaults.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_scene.c

index ef071cbc179dfbd83aed65ad0624427d318ba867..a52cc8bf79121119dc0c986ee7ecaeb527d1e994 100644 (file)
@@ -187,6 +187,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
     bl_context = ".mesh_edit"  # dot on purpose (access from topbar)
     bl_label = "Options"
     bl_options = {'DEFAULT_CLOSED'}
+    bl_ui_units_x = 12
 
     @classmethod
     def poll(cls, context):
@@ -198,11 +199,15 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
         layout.use_property_split = True
         layout.use_property_decorate = False
 
+        tool_settings = context.tool_settings
         ob = context.active_object
         mesh = ob.data
 
         split = layout.split()
 
+        row = layout.row(align=True, heading="Transform")
+        row.prop(tool_settings, "use_correct_custom_data")
+
         row = layout.row(heading="Mirror")
         sub = row.row(align=True)
         sub.prop(mesh, "use_mirror_x", text="X", toggle=True)
index 27c03f0a84f83ddb7bcec67af4dc593a62b132b4..82502227a9af40eec4333e363ea541392eac3d6c 100644 (file)
@@ -744,9 +744,21 @@ void BM_loop_interp_from_face(
   float co[2];
   int i;
 
-  /* convert the 3d coords into 2d for projection */
-  BLI_assert(BM_face_is_normal_valid(f_src));
-  axis_dominant_v3_to_m3(axis_mat, f_src->no);
+  /* Convert the 3d coords into 2d for projection. */
+  float axis_dominant[3];
+  if (!is_zero_v3(f_src->no)) {
+    BLI_assert(BM_face_is_normal_valid(f_src));
+    copy_v3_v3(axis_dominant, f_src->no);
+  }
+  else {
+    /* Rare case in which all the vertices of the face are aligned.
+     * Get a random axis that is orthogonal to the tangent. */
+    float vec[3];
+    BM_face_calc_tangent_auto(f_src, vec);
+    ortho_v3_v3(axis_dominant, vec);
+    normalize_v3(axis_dominant);
+  }
+  axis_dominant_v3_to_m3(axis_mat, axis_dominant);
 
   i = 0;
   l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
index b9e6258c1ba392233b0e8eec6560ac5aabeb3087..eb60273fc79d4796092dcac7158adca16ff63712 100644 (file)
@@ -526,8 +526,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
     }
 
     /* redraw UV editor */
-    if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) &&
-        (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
+    const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ?
+                                         UVCALC_TRANSFORM_CORRECT_SLIDE :
+                                         UVCALC_TRANSFORM_CORRECT;
+
+    if ((t->data_type == TC_MESH_VERTS) && (t->settings->uvcalc_flag & uvcalc_correct_flag)) {
       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
     }
 
@@ -1784,7 +1787,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
 
   if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
     RNA_property_boolean_set(
-        op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
+        op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0);
   }
 }
 
index a94bd609d949c70ab10e190024cdb20ba9824d47..f7eea286983e0f14f1402f735bfa4bbac7f7d280 100644 (file)
@@ -47,7 +47,7 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
 void clipUVData(TransInfo *t);
 
 /* transform_convert_mesh.c */
-void trans_mesh_customdata_correction_init(TransInfo *t, struct TransDataContainer *tc);
+void trans_mesh_customdata_correction_init(TransInfo *t);
 
 /* transform_convert_sequencer.c */
 int transform_convert_sequencer_get_snap_bound(TransInfo *t);
index fcb599401c4130c55948332ad7478f11916cb50f..1c286415ea65b66d8661eaf7dd836e1b5bda16d8 100644 (file)
@@ -1068,18 +1068,29 @@ static void create_trans_vert_customdata_layer(BMVert *v,
   BLI_ghash_insert(tcld->origverts, v, r_tcld_vert);
 }
 
-void trans_mesh_customdata_correction_init(TransInfo *t, TransDataContainer *tc)
+static void trans_mesh_customdata_correction_init_container(TransInfo *t, TransDataContainer *tc)
 {
-  if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
-    return;
-  }
-
   if (tc->custom.type.data) {
     /* Custom data correction has initiated before. */
     BLI_assert(tc->custom.type.free_cb == trans_mesh_customdata_free_cb);
     return;
   }
 
+  if (!ELEM(t->mode,
+            TFM_TRANSLATION,
+            TFM_ROTATION,
+            TFM_RESIZE,
+            TFM_TOSPHERE,
+            TFM_SHEAR,
+            TFM_BEND,
+            TFM_SHRINKFATTEN,
+            TFM_TRACKBALL,
+            TFM_PUSHPULL,
+            TFM_ALIGN)) {
+    /* Currently only modes that change the position of vertices are supported. */
+    return;
+  }
+
   BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
   BMesh *bm = em->bm;
 
@@ -1096,7 +1107,6 @@ void trans_mesh_customdata_correction_init(TransInfo *t, TransDataContainer *tc)
     return;
   }
 
-  /* create copies of faces for customdata projection */
   bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
 
   struct GHash *origfaces = BLI_ghash_ptr_new(__func__);
@@ -1160,6 +1170,19 @@ void trans_mesh_customdata_correction_init(TransInfo *t, TransDataContainer *tc)
   tc->custom.type.free_cb = trans_mesh_customdata_free_cb;
 }
 
+void trans_mesh_customdata_correction_init(TransInfo *t)
+{
+  const char uvcalc_correct_flag = ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) ?
+                                       UVCALC_TRANSFORM_CORRECT_SLIDE :
+                                       UVCALC_TRANSFORM_CORRECT;
+
+  if (t->settings->uvcalc_flag & uvcalc_correct_flag) {
+    FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+      trans_mesh_customdata_correction_init_container(t, tc);
+    }
+  }
+}
+
 /**
  * If we're sliding the vert, return its original location, if not, the current location is good.
  */
@@ -1375,13 +1398,9 @@ void recalcData_mesh(TransInfo *t)
     }
   }
 
-  if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
-    FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-      trans_mesh_customdata_correction_apply(tc, false);
-    }
-  }
-
   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+    trans_mesh_customdata_correction_apply(tc, false);
+
     DEG_id_tag_update(tc->obedit->data, 0); /* sets recalc flags */
     BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
     EDBM_mesh_normals_update(em);
@@ -1399,7 +1418,7 @@ void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
   const bool canceled = (t->state == TRANS_CANCEL);
   const bool use_automerge = !canceled && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
 
-  if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+  if (TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.type.data != NULL) {
     /* Handle multires re-projection, done
      * on transform completion since it's
      * really slow -joeedh. */
index c6d8c4356fabeda7896230c30eab67a1a39aaf30..cce6ef1f3bd444a78e9734f5fa58e952723b6407 100644 (file)
@@ -375,15 +375,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
     if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
       if (RNA_property_is_set(op->ptr, prop)) {
         if (RNA_property_boolean_get(op->ptr, prop)) {
-          t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
+          t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT_SLIDE;
         }
         else {
-          t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT;
+          t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT_SLIDE;
         }
       }
       else {
         RNA_property_boolean_set(
-            op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
+            op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0);
       }
     }
   }
index baf4bba80dfe2dfecdbf91389210f33c18d57893..831ea90b4e459c992b587935be69884b5f2642d1 100644 (file)
@@ -1271,6 +1271,12 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
       break;
   }
 
+  if (t->data_type == TC_MESH_VERTS) {
+    /* Init Custom Data correction.
+     * Ideally this should be called when creating the TransData. */
+    trans_mesh_customdata_correction_init(t);
+  }
+
   /* TODO(germano): Some of these operations change the `t->mode`.
    * This can be bad for Redo.
    * BLI_assert(t->mode == mode); */
index f4eb0685af07ab6dc87c231e6055674845127b16..bad24cfc86cf88626eaf7a1de02128333eab32e4 100644 (file)
@@ -1537,7 +1537,6 @@ void initEdgeSlide_ex(
     if (sld) {
       tc->custom.mode.data = sld;
       tc->custom.mode.free_cb = freeEdgeSlideVerts;
-      trans_mesh_customdata_correction_init(t, tc);
       ok = true;
     }
   }
index a6b37bf1df8d1c5322a12f5fb66bb86a7345d412..4b75c362da9ee9e9239fcdf085dbb7adc41f0693 100644 (file)
@@ -652,7 +652,6 @@ void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
     if (sld) {
       tc->custom.mode.data = sld;
       tc->custom.mode.free_cb = freeVertSlideVerts;
-      trans_mesh_customdata_correction_init(t, tc);
       ok = true;
     }
   }
index fa69b6c7a8d86c2c73c571f3b826bba7c9e1f3fc..7f01e58f2afdf6254098ef8fa1f4e473ba2648d0 100644 (file)
     .doublimit = 0.001, \
     .vgroup_weight = 1.0f, \
     .uvcalc_margin = 0.001f, \
-    .uvcalc_flag = UVCALC_TRANSFORM_CORRECT, \
+    .uvcalc_flag = UVCALC_TRANSFORM_CORRECT_SLIDE, \
     .unwrapper = 1, \
     .select_thresh = 0.01f, \
  \
index 624323c42f6bbebbcfefde36c4a5c2b4ffbd6e86..dd62ddb640f1bfbae3c80d26303ba9d1e4e206be 100644 (file)
@@ -2235,10 +2235,12 @@ enum {
 #define UVCALC_FILLHOLES (1 << 0)
 /** would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
 #define UVCALC_NO_ASPECT_CORRECT (1 << 1)
-/** adjust UV's while transforming to avoid distortion */
-#define UVCALC_TRANSFORM_CORRECT (1 << 2)
+/** Adjust UV's while transforming with Vert or Edge Slide. */
+#define UVCALC_TRANSFORM_CORRECT_SLIDE (1 << 2)
 /** Use mesh data after subsurf to compute UVs*/
 #define UVCALC_USESUBSURF (1 << 3)
+/** adjust UV's while transforming to avoid distortion */
+#define UVCALC_TRANSFORM_CORRECT (1 << 4)
 
 /* ToolSettings.uv_flag */
 #define UV_SYNC_SELECTION 1
index 10b9e588ba1e622fab44ab1b2f2b200647e16acb..cb6bb767f8671275205a2479970b4b0ed8e58bcc 100644 (file)
@@ -3090,6 +3090,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
       prop, "Transform Parents", "Transform the parents, leaving the children in place");
   RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
 
+  prop = RNA_def_property(srna, "use_correct_custom_data", PROP_BOOLEAN, PROP_NONE);
+  RNA_def_property_boolean_sdna(prop, NULL, "uvcalc_flag", UVCALC_TRANSFORM_CORRECT);
+  RNA_def_property_ui_text(
+      prop,
+      "Correct Face Attributes",
+      "Correct data such as UV coordinates and loop colors when transforming");
+  RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
   prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);
   RNA_def_property_boolean_sdna(prop, NULL, "automerge", AUTO_MERGE);
   RNA_def_property_ui_text(