From fbfa3999e18908db281d7c5b886f42020c581eb5 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 19 Oct 2018 14:42:27 +0200 Subject: [PATCH] Fix T57284: poor result UV unwrapping concave n-gon. --- .../editors/uvedit/uvedit_parametrizer.c | 121 +++++++++--------- .../editors/uvedit/uvedit_parametrizer.h | 3 +- .../editors/uvedit/uvedit_unwrap_ops.c | 4 +- 3 files changed, 61 insertions(+), 67 deletions(-) diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 79e804725e5..352bfbf9a9e 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -34,6 +34,8 @@ #include "BLI_heap.h" #include "BLI_boxpack_2d.h" #include "BLI_convexhull_2d.h" +#include "BLI_polyfill_2d.h" +#include "BLI_polyfill_2d_beautify.h" #include "uvedit_parametrizer.h" @@ -219,6 +221,8 @@ enum PHandleState { typedef struct PHandle { enum PHandleState state; MemArena *arena; + MemArena *polyfill_arena; + Heap *polyfill_heap; PChart *construction_chart; PHash *hash_verts; @@ -4119,6 +4123,8 @@ ParamHandle *param_construct_begin(void) handle->construction_chart = p_chart_new(handle); handle->state = PHANDLE_STATE_ALLOCATED; handle->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param construct arena"); + handle->polyfill_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "param polyfill arena"); + handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE); handle->aspx = 1.0f; handle->aspy = 1.0f; handle->do_aspect = false; @@ -4162,82 +4168,71 @@ void param_delete(ParamHandle *handle) } BLI_memarena_free(phandle->arena); + BLI_memarena_free(phandle->polyfill_arena); + BLI_heap_free(phandle->polyfill_heap, NULL); MEM_freeN(phandle); } static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float **co, float **uv, - ParamBool *pin, ParamBool *select, const float normal[3]) + ParamBool *pin, ParamBool *select) { - int *boundary = BLI_array_alloca(boundary, nverts); + /* Allocate memory for polyfill. */ + PHandle *phandle = (PHandle *)handle; + MemArena *arena = phandle->polyfill_arena; + Heap *heap = phandle->polyfill_heap; + unsigned int nfilltri = nverts - 2; + unsigned int (*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri); + float (*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts); - /* boundary vertex indexes */ - for (int i = 0; i < nverts; i++) { - boundary[i] = i; + /* Calc normal, flipped: to get a positive 2d cross product. */ + float normal[3]; + zero_v3(normal); + + const float *co_curr, *co_prev = co[nverts-1]; + for (int j = 0; j < nverts; j++) { + co_curr = co[j]; + add_newell_cross_v3_v3v3(normal, co_prev, co_curr); + co_prev = co_curr; + } + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; } - while (nverts > 2) { - float minangle = FLT_MAX; - float minshape = FLT_MAX; - int i, mini = 0; - - /* find corner with smallest angle */ - for (i = 0; i < nverts; i++) { - int v0 = boundary[(i + nverts - 1) % nverts]; - int v1 = boundary[i]; - int v2 = boundary[(i + 1) % nverts]; - float angle = p_vec_angle(co[v0], co[v1], co[v2]); - float n[3]; - - normal_tri_v3(n, co[v0], co[v1], co[v2]); - - if (normal && (dot_v3v3(n, normal) < 0.0f)) - angle = (float)(2.0 * M_PI) - angle; - - float other_angle = p_vec_angle(co[v2], co[v0], co[v1]); - float shape = fabsf((float)M_PI - angle - 2.0f * other_angle); - - if (fabsf(angle - minangle) < 0.01f) { - /* for nearly equal angles, try to get well shaped triangles */ - if (shape < minshape) { - minangle = angle; - minshape = shape; - mini = i; - } - } - else if (angle < minangle) { - minangle = angle; - minshape = shape; - mini = i; - } - } - - /* add triangle in corner */ - { - int v0 = boundary[(mini + nverts - 1) % nverts]; - int v1 = boundary[mini]; - int v2 = boundary[(mini + 1) % nverts]; - - ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; - float *tri_co[3] = {co[v0], co[v1], co[v2]}; - float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]}; - ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; - ParamBool tri_select[3] = {select[v0], select[v1], select[v2]}; - - param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select, NULL); - } - - /* remove corner */ - if (mini + 1 < nverts) - memmove(boundary + mini, boundary + mini + 1, (nverts - mini - 1) * sizeof(int)); - - nverts--; + /* Project verts to 2d. */ + float axis_mat[3][3]; + axis_dominant_v3_to_m3_negate(axis_mat, normal); + for (int j = 0; j < nverts; j++) { + mul_v2_m3v3(projverts[j], axis_mat, co[j]); } + + BLI_polyfill_calc_arena(projverts, nverts, 1, tris, arena); + + /* Beautify helps avoid thin triangles that give numerical problems. */ + BLI_polyfill_beautify(projverts, nverts, tris, arena, heap); + + /* Add triangles. */ + for (int j = 0; j < nfilltri; j++) { + unsigned int *tri = tris[j]; + unsigned int v0 = tri[0]; + unsigned int v1 = tri[1]; + unsigned int v2 = tri[2]; + + ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]}; + float *tri_co[3] = {co[v0], co[v1], co[v2]}; + float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]}; + ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]}; + ParamBool tri_select[3] = {select[v0], select[v1], select[v2]}; + + param_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select); + } + + BLI_memarena_clear(arena); } void param_face_add(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float *co[4], float *uv[4], - ParamBool *pin, ParamBool *select, float normal[3]) + ParamBool *pin, ParamBool *select) { PHandle *phandle = (PHandle *)handle; @@ -4247,7 +4242,7 @@ void param_face_add(ParamHandle *handle, ParamKey key, int nverts, if (nverts > 4) { /* ngon */ - p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select, normal); + p_add_ngon(handle, key, nverts, vkeys, co, uv, pin, select); } else if (nverts == 4) { /* quad */ diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index 2714bc33769..e42944f3da4 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -62,8 +62,7 @@ void param_face_add(ParamHandle *handle, float *co[4], float *uv[4], ParamBool *pin, - ParamBool *select, - float face_normal[3]); + ParamBool *select); void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 582ba989997..088ed42b0c0 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -254,7 +254,7 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene, select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); } - param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no); + param_face_add(handle, key, i, vkeys, co, uv, pin, select); } static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm, @@ -478,7 +478,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset); texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset); - param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL); + param_face_add(handle, key, 4, vkeys, co, uv, pin, select); } /* these are calculated from original mesh too */