Transform: generalized custom-data correction support

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.
This commit is contained in:
Germano Cavalcante 2020-07-01 17:45:27 +10:00 committed by Campbell Barton
parent 8d3c4aa2d7
commit 4387aff99e
Notes: blender-bot 2023-02-14 09:44:56 +01:00
Referenced by issue #83161, Crash when moving ruler endpoints and opening or closing the toolshelf
Referenced by issue #79581, Polishing Correct Face Attributes
Referenced by issue #78695, Bevel improvements for "Correct Face Attributes"
12 changed files with 81 additions and 28 deletions

View 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)

View 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);

View 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);
}
}

View 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);

View 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. */

View 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);
}
}
}

View 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); */

View 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;
}
}

View 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;
}
}

View File

@ -327,7 +327,7 @@
.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, \
\

View 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

View 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(