From c3b5c726c7a76b17d3fa3a4bb1f9e9db2e61ee18 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Mon, 7 Jan 2013 21:42:40 +0000 Subject: [PATCH] * Fix for #31581. The issue was that we scaled the face prior to projecting it. The original paper suggests to simply interpolate between the two points of an edge if the distance of the point to that edge is smaller than a threshold. * Fixed both 3D and 2D code to utilize this. Possibly other places in blender where this scaling is done will have to be adjusted. * Changed vertex interpolation to use 2D interpolation, since it already did projection on plane and 2d calculations are faster. * Also added notifier on hard recalc when uvcalc_transfor_correction is used. Results in instant feedback on UV editor when edge sliding. --- source/blender/blenlib/intern/math_geom.c | 67 +++++++++++++++++--- source/blender/bmesh/intern/bmesh_interp.c | 34 ++-------- source/blender/editors/transform/transform.c | 7 +- 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index a643c893cdb..91939b4d883 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2335,14 +2335,25 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ { /* TODO: t1 and t2 overlap each iter, we could call this only once per iter and reuse previous value */ float totweight, t1, t2, len, *vmid, *vprev, *vnext; - int i; + int i, inext, icur; + bool edge_interp = false; totweight = 0.0f; for (i = 0; i < n; i++) { + icur = i; + inext = (i == n - 1) ? 0 : i + 1; + vmid = v[i]; vprev = (i == 0) ? v[n - 1] : v[i - 1]; - vnext = (i == n - 1) ? v[0] : v[i + 1]; + vnext = v[inext]; + + /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close + * to borders of face. In that case, do simple linear interpolation between the two edges */ + if (dist_to_line_segment_v3(co, vmid, vnext) < 10*FLT_EPSILON) { + edge_interp = true; + break; + } t1 = mean_value_half_tan_v3(co, vprev, vmid); t2 = mean_value_half_tan_v3(co, vmid, vnext); @@ -2352,25 +2363,49 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ totweight += w[i]; } - if (totweight != 0.0f) { - for (i = 0; i < n; i++) { - w[i] /= totweight; + if (edge_interp) { + float len_cur = len_v3v3(co, vmid); + float len_next = len_v3v3(co, vnext); + float edge_len = len_cur + len_next; + for (i = 0; i < n; i++) + w[i] = 0.0; + + w[icur] = len_next/edge_len; + w[inext] = len_cur/edge_len; + } + else { + if (totweight != 0.0f) { + for (i = 0; i < n; i++) { + w[i] /= totweight; + } } } } + void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2]) { /* TODO: t1 and t2 overlap each iter, we could call this only once per iter and reuse previous value */ float totweight, t1, t2, len, *vmid, *vprev, *vnext; - int i; + int i, inext, icur; + bool edge_interp = false; totweight = 0.0f; for (i = 0; i < n; i++) { + icur = i; + inext = (i == n - 1) ? 0 : i + 1; + vmid = v[i]; vprev = (i == 0) ? v[n - 1] : v[i - 1]; - vnext = (i == n - 1) ? v[0] : v[i + 1]; + vnext = v[inext]; + + /* Mark Mayer et al algorithm that is used here does not operate well if vertex is close + * to borders of face. In that case, do simple linear interpolation between the two edges */ + if (dist_to_line_segment_v2(co, vmid, vnext) < 10*FLT_EPSILON) { + edge_interp = true; + break; + } t1 = mean_value_half_tan_v2(co, vprev, vmid); t2 = mean_value_half_tan_v2(co, vmid, vnext); @@ -2380,9 +2415,21 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ totweight += w[i]; } - if (totweight != 0.0f) { - for (i = 0; i < n; i++) { - w[i] /= totweight; + if (edge_interp) { + float len_cur = len_v2v2(co, vmid); + float len_next = len_v2v2(co, vnext); + float edge_len = len_cur + len_next; + for (i = 0; i < n; i++) + w[i] = 0.0; + + w[icur] = len_next/edge_len; + w[inext] = len_cur/edge_len; + } + else { + if (totweight != 0.0f) { + for (i = 0; i < n; i++) { + w[i] /= totweight; + } } } } diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 4ec91b8d8d7..1afaf851e2a 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -606,9 +606,9 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, void **vblocks = do_vertex ? BLI_array_alloca(vblocks, source->len) : NULL; void **blocks = BLI_array_alloca(blocks, source->len); float (*cos)[3] = BLI_array_alloca(cos, source->len); + float (*cos_2d)[2] = BLI_array_alloca(cos_2d, source->len); float *w = BLI_array_alloca(w, source->len); - float co[3]; - float cent[3] = {0.0f, 0.0f, 0.0f}; + float co[2]; int i, ax, ay; BM_elem_attrs_copy(bm, bm, source, target->f); @@ -617,7 +617,6 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, l_iter = l_first = BM_FACE_FIRST_LOOP(source); do { copy_v3_v3(cos[i], l_iter->v->co); - add_v3_v3(cent, cos[i]); w[i] = 0.0f; blocks[i] = l_iter->head.data; @@ -634,28 +633,17 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, axis_dominant_v3(&ax, &ay, source->no); - /* scale source face coordinates a bit, so points sitting directly on an - * edge will work. */ - mul_v3_fl(cent, 1.0f / (float)source->len); for (i = 0; i < source->len; i++) { - float vec[3], tmp[3]; - sub_v3_v3v3(vec, cent, cos[i]); - mul_v3_fl(vec, 0.001f); - add_v3_v3(cos[i], vec); - - copy_v3_v3(tmp, cos[i]); - cos[i][0] = tmp[ax]; - cos[i][1] = tmp[ay]; - cos[i][2] = 0.0f; + cos_2d[i][0] = cos[i][ax]; + cos_2d[i][1] = cos[i][ay]; } /* interpolate */ co[0] = target->v->co[ax]; co[1] = target->v->co[ay]; - co[2] = 0.0f; - interp_weights_poly_v3(w, cos, source->len, co); + interp_weights_poly_v2(w, cos_2d, source->len, co); CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data); if (do_vertex) { CustomData_bmesh_interp(&bm->vdata, vblocks, w, NULL, source->len, target->v->head.data); @@ -676,30 +664,18 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source) void **blocks = BLI_array_alloca(blocks, source->len); float (*cos)[3] = BLI_array_alloca(cos, source->len); float *w = BLI_array_alloca(w, source->len); - float cent[3] = {0.0f, 0.0f, 0.0f}; int i; i = 0; l_iter = l_first = BM_FACE_FIRST_LOOP(source); do { copy_v3_v3(cos[i], l_iter->v->co); - add_v3_v3(cent, cos[i]); w[i] = 0.0f; blocks[i] = l_iter->v->head.data; i++; } while ((l_iter = l_iter->next) != l_first); - /* scale source face coordinates a bit, so points sitting directly on an - * edge will work. */ - mul_v3_fl(cent, 1.0f / (float)source->len); - for (i = 0; i < source->len; i++) { - float vec[3]; - sub_v3_v3v3(vec, cent, cos[i]); - mul_v3_fl(vec, 0.01f); - add_v3_v3(cos[i], vec); - } - /* interpolate */ interp_weights_poly_v3(w, cos, source->len, v->co); CustomData_bmesh_interp(&bm->vdata, blocks, w, NULL, source->len, v->head.data); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 3b443e8bbac..78a8bd47668 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -462,7 +462,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); else WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - + + if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); + /* for realtime animation record - send notifiers recognised by animation editors */ // XXX: is this notifier a lame duck? if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) @@ -5424,7 +5427,7 @@ void projectSVData(TransInfo *t, int final) } } - + if (!affected) continue;