Vert/Edge Slide: better UV interpolation
Ignore faces which the sliding vert is outside of.
This commit is contained in:
@@ -925,12 +925,15 @@ struct LoopWalkCtx {
|
||||
/* reference for this contiguous fan */
|
||||
const void *data_ref;
|
||||
int data_len;
|
||||
|
||||
/* accumulate 'LoopGroupCD.weight' to make unit length */
|
||||
float weight_accum;
|
||||
|
||||
/* both arrays the size of the 'BM_vert_face_count(v)'
|
||||
* each contiguous fan gets a slide of these arrays */
|
||||
void **data_array;
|
||||
int *data_index_array;
|
||||
float *weight_array;
|
||||
/* accumulate 'LoopGroupCD.weight' to make unit length */
|
||||
float weight_accum;
|
||||
};
|
||||
|
||||
/* Store vars to pass into 'CustomData_bmesh_interp' */
|
||||
@@ -939,6 +942,8 @@ struct LoopGroupCD {
|
||||
void **data;
|
||||
/* weights (aligned with 'data') */
|
||||
float *data_weights;
|
||||
/* index-in-face */
|
||||
int *data_index;
|
||||
/* number of loops in the fan */
|
||||
int data_len;
|
||||
};
|
||||
@@ -948,6 +953,7 @@ static void bm_loop_walk_add(struct LoopWalkCtx *lwc, BMLoop *l)
|
||||
const float w = BM_loop_calc_face_angle(l);
|
||||
BM_elem_flag_enable(l, BM_ELEM_INTERNAL_TAG);
|
||||
lwc->data_array[lwc->data_len] = BM_ELEM_CD_GET_VOID_P(l, lwc->cd_layer_offset);
|
||||
lwc->data_index_array[lwc->data_len] = BM_elem_index_get(l);
|
||||
lwc->weight_array[lwc->data_len] = w;
|
||||
lwc->weight_accum += w;
|
||||
|
||||
@@ -1001,11 +1007,14 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_
|
||||
loop_num = 0;
|
||||
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||
BM_elem_flag_disable(l, BM_ELEM_INTERNAL_TAG);
|
||||
BM_elem_index_set(l, loop_num); /* set_dirty! */
|
||||
loop_num++;
|
||||
}
|
||||
bm->elem_index_dirty |= BM_LOOP;
|
||||
|
||||
lwc.data_len = 0;
|
||||
lwc.data_array = BLI_memarena_alloc(lwc.arena, sizeof(void *) * loop_num);
|
||||
lwc.data_index_array = BLI_memarena_alloc(lwc.arena, sizeof(int) * loop_num);
|
||||
lwc.weight_array = BLI_memarena_alloc(lwc.arena, sizeof(float) * loop_num);
|
||||
|
||||
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
|
||||
@@ -1017,6 +1026,7 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_
|
||||
|
||||
/* assign len-last */
|
||||
lf->data = &lwc.data_array[lwc.data_len];
|
||||
lf->data_index = &lwc.data_index_array[lwc.data_len];
|
||||
lf->data_weights = &lwc.weight_array[lwc.data_len];
|
||||
lwc.weight_accum = 0.0f;
|
||||
|
||||
@@ -1040,12 +1050,48 @@ LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_
|
||||
return groups;
|
||||
}
|
||||
|
||||
static void bm_vert_loop_groups_data_layer_merge__single(BMesh *bm, void *lf_p, void *data, int type)
|
||||
static void bm_vert_loop_groups_data_layer_merge__single(
|
||||
BMesh *bm, void *lf_p, void *data, int type)
|
||||
{
|
||||
struct LoopGroupCD *lf = lf_p;
|
||||
int i;
|
||||
const float *data_weights;
|
||||
|
||||
CustomData_bmesh_interp(&bm->ldata, lf->data, lf->data_weights, NULL, lf->data_len, data);
|
||||
data_weights = lf->data_weights;
|
||||
|
||||
CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data);
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
CustomData_copy_elements(type, data, lf->data[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bm_vert_loop_groups_data_layer_merge_weights__single(
|
||||
BMesh *bm, void *lf_p, void *data, int type, const float *loop_weights)
|
||||
{
|
||||
struct LoopGroupCD *lf = lf_p;
|
||||
int i;
|
||||
const float *data_weights;
|
||||
|
||||
/* re-weight */
|
||||
float *temp_weights = BLI_array_alloca(temp_weights, lf->data_len);
|
||||
float weight_accum = 0.0f;
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
float w = loop_weights[lf->data_index[i]] * lf->data_weights[i];
|
||||
temp_weights[i] = w;
|
||||
weight_accum += w;
|
||||
}
|
||||
|
||||
if (LIKELY(weight_accum != 0.0f)) {
|
||||
mul_vn_fl(temp_weights, lf->data_len, 1.0f / weight_accum);
|
||||
data_weights = temp_weights;
|
||||
}
|
||||
else {
|
||||
data_weights = lf->data_weights;
|
||||
}
|
||||
|
||||
CustomData_bmesh_interp(&bm->ldata, lf->data, data_weights, NULL, lf->data_len, data);
|
||||
|
||||
for (i = 0; i < lf->data_len; i++) {
|
||||
CustomData_copy_elements(type, data, lf->data[i], 1);
|
||||
@@ -1066,4 +1112,19 @@ void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, int layer
|
||||
} while ((groups = groups->next));
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #BM_vert_loop_groups_data_layer_merge
|
||||
* that takes an array of loop-weights (aligned with #BM_LOOPS_OF_VERT iterator)
|
||||
*/
|
||||
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, LinkNode *groups, int layer_n, const float *loop_weights)
|
||||
{
|
||||
int type = bm->ldata.layers[layer_n].type;
|
||||
int size = CustomData_sizeof(type);
|
||||
void *data = alloca(size);
|
||||
|
||||
do {
|
||||
bm_vert_loop_groups_data_layer_merge_weights__single(bm, groups->link, data, type, loop_weights);
|
||||
} while ((groups = groups->next));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -54,5 +54,6 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source,
|
||||
void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f);
|
||||
struct LinkNode *BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, int layer_n, struct MemArena *arena);
|
||||
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, int layer_n);
|
||||
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, struct LinkNode *groups, int layer_n, const float *loop_weights);
|
||||
|
||||
#endif /* __BMESH_INTERP_H__ */
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "DNA_movieclip_types.h"
|
||||
#include "DNA_scene_types.h" /* PET modes */
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rect.h"
|
||||
@@ -5269,6 +5270,8 @@ static void slide_origdata_create_data(
|
||||
|
||||
sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
|
||||
sod->origverts = BLI_ghash_ptr_new_ex(__func__, v_num);
|
||||
|
||||
for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) {
|
||||
BMIter fiter;
|
||||
BMFace *f;
|
||||
@@ -5294,6 +5297,64 @@ static void slide_origdata_create_data(
|
||||
else {
|
||||
sv->cd_loop_groups = NULL;
|
||||
}
|
||||
|
||||
BLI_ghash_insert(sod->origverts, sv->v, sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If we're sliding the vert, return its original location, if not, the current location is good.
|
||||
*/
|
||||
static const float *slide_origdata_orig_vert_co(SlideOrigData *sod, BMVert *v)
|
||||
{
|
||||
TransDataGenericSlideVert *sv = BLI_ghash_lookup(sod->origverts, v);
|
||||
return sv ? sv->co_orig_3d : v->co;
|
||||
}
|
||||
|
||||
static void slide_origdata_interp_data_vert(
|
||||
SlideOrigData *sod, BMesh *bm, bool is_final,
|
||||
TransDataGenericSlideVert *sv)
|
||||
{
|
||||
BMIter liter;
|
||||
BMLoop *l;
|
||||
int j;
|
||||
float *loop_weights;
|
||||
const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
|
||||
|
||||
// BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
|
||||
l = BM_iter_new(&liter, bm, BM_LOOPS_OF_VERT, sv->v);
|
||||
loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, liter.count) : NULL;
|
||||
for (j = 0 ; l; l = BM_iter_step(&liter), j++) {
|
||||
BMFace *f_copy; /* the copy of 'f' */
|
||||
|
||||
f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
|
||||
|
||||
/* only loop data, no vertex data since that contains shape keys,
|
||||
* and we do not want to mess up other shape keys */
|
||||
BM_loop_interp_from_face(bm, l, f_copy, false, is_final);
|
||||
|
||||
/* make sure face-attributes are correct (e.g. MTexPoly) */
|
||||
BM_elem_attrs_copy(sod->bm_origfaces, bm, f_copy, l->f);
|
||||
|
||||
/* weight the loop */
|
||||
if (do_loop_weight) {
|
||||
const float *v_prev = slide_origdata_orig_vert_co(sod, l->prev->v);
|
||||
const float *v_next = slide_origdata_orig_vert_co(sod, l->next->v);
|
||||
const float dist = dist_signed_squared_to_corner_v3v3v3(sv->v->co, v_prev, sv->co_orig_3d, v_next, f_copy->no);
|
||||
const float eps = 0.00001f;
|
||||
loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
|
||||
}
|
||||
}
|
||||
|
||||
if (do_loop_weight) {
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5305,33 +5366,13 @@ static void slide_origdata_interp_data(
|
||||
{
|
||||
if (sod->use_origfaces) {
|
||||
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
|
||||
BMesh *bm = em->bm;
|
||||
unsigned int i;
|
||||
|
||||
const int *layer_math_map = sod->layer_math_map;
|
||||
|
||||
for (i = 0; i < v_num; i++, sv = (void *)(((char *)sv) + v_stride)) {
|
||||
|
||||
if (sv->cd_loop_groups) {
|
||||
BMIter fiter;
|
||||
BMLoop *l;
|
||||
int j;
|
||||
|
||||
BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
|
||||
BMFace *f_copy; /* the copy of 'f' */
|
||||
|
||||
f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
|
||||
|
||||
/* only loop data, no vertex data since that contains shape keys,
|
||||
* and we do not want to mess up other shape keys */
|
||||
BM_loop_interp_from_face(em->bm, l, f_copy, false, is_final);
|
||||
|
||||
/* make sure face-attributes are correct (e.g. MTexPoly) */
|
||||
BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f);
|
||||
}
|
||||
|
||||
for (j = 0; j < sod->layer_math_map_num; j++) {
|
||||
BM_vert_loop_groups_data_layer_merge(em->bm, sv->cd_loop_groups[j], layer_math_map[j]);
|
||||
}
|
||||
slide_origdata_interp_data_vert(sod, bm, is_final, sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5351,6 +5392,11 @@ static void slide_origdata_free_date(
|
||||
sod->origfaces = NULL;
|
||||
}
|
||||
|
||||
if (sod->origverts) {
|
||||
BLI_ghash_free(sod->origverts, NULL, NULL);
|
||||
sod->origverts = NULL;
|
||||
}
|
||||
|
||||
if (sod->arena) {
|
||||
BLI_memarena_free(sod->arena);
|
||||
sod->arena = NULL;
|
||||
|
||||
@@ -204,19 +204,20 @@ struct GHash;
|
||||
typedef struct TransDataGenericSlideVert {
|
||||
struct BMVert *v;
|
||||
struct LinkNode **cd_loop_groups;
|
||||
float co_orig_3d[3];
|
||||
} TransDataGenericSlideVert;
|
||||
|
||||
typedef struct TransDataEdgeSlideVert {
|
||||
/* TransDataGenericSlideVert */
|
||||
struct BMVert *v;
|
||||
struct LinkNode **cd_loop_groups;
|
||||
float v_co_orig[3];
|
||||
/* end generic */
|
||||
|
||||
struct BMVert *v_a, *v_b;
|
||||
float v_co_orig[3];
|
||||
|
||||
float edge_len;
|
||||
|
||||
struct BMVert *v_a, *v_b;
|
||||
|
||||
/* add origvert.co to get the original locations */
|
||||
float dir_a[3], dir_b[3];
|
||||
|
||||
@@ -228,6 +229,7 @@ typedef struct TransDataEdgeSlideVert {
|
||||
typedef struct SlideOrigData {
|
||||
/* flag that is set when origfaces is initialized */
|
||||
bool use_origfaces;
|
||||
struct GHash *origverts; /* map {BMVert: TransDataGenericSlideVert} */
|
||||
struct GHash *origfaces;
|
||||
struct BMesh *bm_origfaces;
|
||||
|
||||
@@ -261,9 +263,9 @@ typedef struct TransDataVertSlideVert {
|
||||
/* TransDataGenericSlideVert */
|
||||
BMVert *v;
|
||||
struct LinkNode **cd_loop_groups;
|
||||
float co_orig_3d[3];
|
||||
/* end generic */
|
||||
|
||||
float co_orig_3d[3];
|
||||
float co_orig_2d[2];
|
||||
float (*co_link_orig_3d)[3];
|
||||
float (*co_link_orig_2d)[2];
|
||||
|
||||
Reference in New Issue
Block a user