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:
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
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue