Fix T99643: Vertex Crease fails with symmetry

Create a transform conversion type that only considers the Vertex
Custom Data.

This reduces the complexity of converting Meshes and slightly
optimizes the transformation.
This commit is contained in:
Germano Cavalcante 2022-07-19 11:43:38 -03:00
parent 597955d0a8
commit d14c2d549b
Notes: blender-bot 2024-05-08 11:36:44 +02:00
Referenced by commit 29c68e2523, Fix T99869: Edge crease no longer working
Referenced by issue #103783, Regression: Canceling vertex crease operation causes crash when mesh has vertex groups
Referenced by issue #99869, Edge crease no longer working
Referenced by issue #99643, Vertex Crease fails with symmetry
8 changed files with 319 additions and 41 deletions

View File

@ -39,6 +39,7 @@ set(SRC
transform_convert_mesh_edge.c
transform_convert_mesh_skin.c
transform_convert_mesh_uv.c
transform_convert_mesh_vert_cdata.c
transform_convert_nla.c
transform_convert_node.c
transform_convert_object.c

View File

@ -222,6 +222,7 @@ typedef enum {
TC_MESH_EDGES,
TC_MESH_SKIN,
TC_MESH_UV,
TC_MESH_VERT_CDATA,
TC_NLA_DATA,
TC_NODE_DATA,
TC_OBJECT,

View File

@ -823,6 +823,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_GPENCIL:
case TC_LATTICE_VERTS:
case TC_MBALL_VERTS:
case TC_MESH_VERT_CDATA:
case TC_MESH_UV:
case TC_MESH_SKIN:
case TC_OBJECT_TEXSPACE:
@ -905,6 +906,7 @@ static void init_proportional_edit(TransInfo *t)
case TC_MESH_EDGES:
case TC_MESH_SKIN:
case TC_MESH_UV:
case TC_MESH_VERT_CDATA:
case TC_NODE_DATA:
case TC_OBJECT:
case TC_PARTICLE_VERTS:
@ -939,7 +941,7 @@ static void init_proportional_edit(TransInfo *t)
if (ELEM(convert_type, TC_ACTION_DATA, TC_GRAPH_EDIT_DATA)) {
/* Distance has already been set. */
}
else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN)) {
else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN, TC_MESH_VERT_CDATA)) {
if (t->flag & T_PROP_CONNECTED) {
/* Already calculated by transform_convert_mesh_connectivity_distance. */
}
@ -984,6 +986,7 @@ static void init_TransDataContainers(TransInfo *t,
case TC_MESH_EDGES:
case TC_MESH_SKIN:
case TC_MESH_UV:
case TC_MESH_VERT_CDATA:
break;
case TC_ACTION_DATA:
case TC_GRAPH_EDIT_DATA:
@ -1095,6 +1098,7 @@ static eTFlag flags_from_data_type(eTConvertType data_type)
case TC_MBALL_VERTS:
case TC_MESH_VERTS:
case TC_MESH_SKIN:
case TC_MESH_VERT_CDATA:
return T_EDIT | T_POINTS;
case TC_MESH_EDGES:
return T_EDIT;
@ -1194,6 +1198,9 @@ static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armatur
if (t->mode == TFM_SKIN_RESIZE) {
convert_type = TC_MESH_SKIN;
}
else if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
convert_type = TC_MESH_VERT_CDATA;
}
else {
convert_type = TC_MESH_VERTS;
}
@ -1317,6 +1324,9 @@ void createTransData(bContext *C, TransInfo *t)
case TC_NLA_DATA:
createTransNlaData(C, t);
break;
case TC_MESH_VERT_CDATA:
createTransMeshVertCData(t);
break;
case TC_NODE_DATA:
createTransNodeData(t);
break;
@ -1623,6 +1633,9 @@ void recalcData(TransInfo *t)
case TC_MESH_UV:
recalcData_uv(t);
break;
case TC_MESH_VERT_CDATA:
recalcData_mesh_cdata(t);
break;
case TC_NLA_DATA:
recalcData_nla(t);
break;

View File

@ -252,6 +252,11 @@ void createTransUVs(bContext *C, TransInfo *t);
/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t);
/* transform_convert_mesh_vert_cdata.c */
void createTransMeshVertCData(TransInfo *t);
void recalcData_mesh_cdata(TransInfo *t);
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);

View File

@ -1408,7 +1408,6 @@ static void VertsToTransData(TransInfo *t,
TransDataExtension *tx,
BMEditMesh *em,
BMVert *eve,
float *bweight,
const struct TransIslandData *island_data,
const int island_index)
{
@ -1449,11 +1448,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
td->val = bweight;
td->ival = *bweight;
}
else if (t->mode == TFM_SHRINKFATTEN) {
if (t->mode == TFM_SHRINKFATTEN) {
td->ext = tx;
tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
}
@ -1589,17 +1584,6 @@ void createTransEditVerts(TransInfo *t)
"TransObData ext");
}
int cd_vert_bweight_offset = -1;
int cd_vert_crease_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
else if (t->mode == TFM_VERT_CREASE) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
}
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
@ -1632,15 +1616,9 @@ void createTransEditVerts(TransInfo *t)
td_mirror++;
}
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
(cd_vert_crease_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
NULL;
/* Do not use the island center in case we are using islands
* only to get axis for snap/rotate to normal... */
VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index);
VertsToTransData(t, tob, tx, em, eve, &island_data, island_index);
if (tx) {
tx++;
}

View File

@ -0,0 +1,290 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup edtransform
*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_editmesh.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "ED_mesh.h"
#include "DEG_depsgraph_query.h"
#include "transform.h"
#include "transform_orientations.h"
#include "transform_convert.h"
/* -------------------------------------------------------------------- */
/** \name Edit Mesh #CD_BWEIGHT and #CD_CREASE Transform Creation
* \{ */
static float *tc_mesh_cdata_transdata_center(const struct TransIslandData *island_data,
const int island_index,
BMVert *eve)
{
if (island_data->center && island_index != -1) {
return island_data->center[island_index];
}
return eve->co;
}
static void tc_mesh_cdata_transdata_create(TransDataBasic *td,
BMEditMesh *em,
BMVert *eve,
float *weight,
const struct TransIslandData *island_data,
const int island_index)
{
BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
td->loc = weight;
td->iloc[0] = *weight;
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
td->flag |= TD_SELECTED;
}
copy_v3_v3(td->center, tc_mesh_cdata_transdata_center(island_data, island_index, eve));
td->extra = eve;
}
void createTransMeshVertCData(TransInfo *t)
{
BLI_assert(ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE));
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
Mesh *me = tc->obedit->data;
BMesh *bm = em->bm;
BMVert *eve;
BMIter iter;
float mtx[3][3], smtx[3][3];
int a;
const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
struct TransIslandData island_data = {NULL};
struct TransMirrorData mirror_data = {NULL};
struct TransMeshDataCrazySpace crazyspace_data = {NULL};
/* Support other objects using PET to adjust these, unless connected is enabled. */
if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
continue;
}
int cd_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
else {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
cd_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
}
if (cd_offset == -1) {
continue;
}
int data_len = 0;
if (prop_mode) {
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
data_len++;
}
}
}
else {
data_len = bm->totvertsel;
}
if (data_len == 0) {
continue;
}
const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
if (is_island_center) {
/* In this specific case, near-by vertices will need to know
* the island of the nearest connected vertex. */
const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
(t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(em->selectmode & SCE_SELECT_VERTEX));
const bool calc_island_center = false;
const bool calc_island_axismtx = false;
transform_convert_mesh_islands_calc(
em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data);
}
copy_m3_m4(mtx, tc->obedit->obmat);
/* we use a pseudo-inverse so that when one of the axes is scaled to 0,
* matrix inversion still works and we can still moving along the other */
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
/* Original index of our connected vertex when connected distances are calculated.
* Optional, allocate if needed. */
int *dists_index = NULL;
float *dists = NULL;
if (prop_mode & T_PROP_CONNECTED) {
dists = MEM_mallocN(bm->totvert * sizeof(float), __func__);
if (is_island_center) {
dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__);
}
transform_convert_mesh_connectivity_distance(em->bm, mtx, dists, dists_index);
}
/* Create TransDataMirror. */
if (tc->use_mirror_axis_any) {
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
bool use_select = (t->flag & T_PROP_EDIT) == 0;
const bool mirror_axis[3] = {
tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z};
transform_convert_mesh_mirrordata_calc(
em, use_select, use_topology, mirror_axis, &mirror_data);
if (mirror_data.vert_map) {
tc->data_mirror_len = mirror_data.mirror_elem_len;
tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
__func__);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
if (mirror_data.vert_map[a].index != -1) {
data_len--;
}
}
}
}
}
/* Detect CrazySpace [tm]. */
transform_convert_mesh_crazyspace_detect(t, tc, em, &crazyspace_data);
/* Create TransData. */
BLI_assert(data_len >= 1);
tc->data_len = data_len;
tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
TransData *td = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
continue;
}
int island_index = -1;
if (island_data.island_vert_map) {
const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
island_index = island_data.island_vert_map[connected_index];
}
float *weight = BM_ELEM_CD_GET_VOID_P(eve, cd_offset);
if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
tc_mesh_cdata_transdata_create(
(TransDataBasic *)td_mirror, em, eve, weight, &island_data, island_index);
int elem_index = mirror_data.vert_map[a].index;
BMVert *v_src = BM_vert_at_index(bm, elem_index);
td_mirror->flag |= mirror_data.vert_map[a].flag;
td_mirror->loc_src = BM_ELEM_CD_GET_VOID_P(v_src, cd_offset);
td_mirror++;
}
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
tc_mesh_cdata_transdata_create(
(TransDataBasic *)td, em, eve, weight, &island_data, island_index);
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
createSpaceNormal(td->axismtx, eve->no);
}
else {
/* Setting normals */
copy_v3_v3(td->axismtx[2], eve->no);
td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
}
if (prop_mode) {
if (prop_mode & T_PROP_CONNECTED) {
td->dist = dists[a];
}
else {
td->flag |= TD_NOTCONNECTED;
td->dist = FLT_MAX;
}
}
/* CrazySpace */
transform_convert_mesh_crazyspace_transdata_set(
mtx,
smtx,
crazyspace_data.defmats ? crazyspace_data.defmats[a] : NULL,
crazyspace_data.quats && BM_elem_flag_test(eve, BM_ELEM_TAG) ?
crazyspace_data.quats[a] :
NULL,
td);
td++;
}
}
transform_convert_mesh_islanddata_free(&island_data);
transform_convert_mesh_mirrordata_free(&mirror_data);
transform_convert_mesh_crazyspace_free(&crazyspace_data);
if (dists) {
MEM_freeN(dists);
}
if (dists_index) {
MEM_freeN(dists_index);
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Recalc Mesh Data
* \{ */
static void tc_mesh_cdata_apply_to_mirror(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->use_mirror_axis_any) {
TransDataMirror *td_mirror = tc->data_mirror;
for (int i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
td_mirror->loc[0] = td_mirror->loc_src[0];
}
}
}
}
void recalcData_mesh_cdata(TransInfo *t)
{
bool is_canceling = t->state == TRANS_CANCEL;
/* mirror modifier clipping? */
if (!is_canceling) {
if (!(t->flag & T_NO_MIRROR)) {
tc_mesh_cdata_apply_to_mirror(t);
}
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BKE_editmesh_looptri_and_normals_calc(em);
}
}
/** \} */

View File

@ -44,16 +44,11 @@ static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t),
TransData *td,
const float weight)
{
if (td->val == NULL) {
if (td->loc == NULL) {
return;
}
*td->val = td->ival + weight * td->factor;
if (*td->val < 0.0f) {
*td->val = 0.0f;
}
if (*td->val > 1.0f) {
*td->val = 1.0f;
}
*td->loc = td->iloc[0] + weight * td->factor;
CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v,

View File

@ -44,17 +44,12 @@ static void transdata_elem_crease(const TransInfo *UNUSED(t),
TransData *td,
const float crease)
{
if (td->val == NULL) {
if (td->loc == NULL) {
return;
}
*td->val = td->ival + crease * td->factor;
if (*td->val < 0.0f) {
*td->val = 0.0f;
}
if (*td->val > 1.0f) {
*td->val = 1.0f;
}
*td->loc = td->iloc[0] + crease * td->factor;
CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_crease_fn(void *__restrict iter_data_v,