Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2015-08-12 17:18:58 +0300
committerHoward Trickey <howard.trickey@gmail.com>2015-08-12 17:18:58 +0300
commit39ce0a99165782536eb55acc9d173c46d3071063 (patch)
tree0c0e27f7c13b6f5df76aa81b9367a692b801755c /source/blender/bmesh
parent4eefba091dfe8c7228c657d83ba1ae3fc62fd2b4 (diff)
Fix T44049, edge bevel with sometimes breaks UVs.
Fairly large changes to bevel code to do a better job of keeping UVs from crossing islands, etc. Updated http://wiki.blender.org/index.php/Dev:2.5/Source/Modeling/Bevel to explain algorithm used for maintaining UVs. Updated the bevel_regression.blend tests in lib tests.
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c494
1 files changed, 383 insertions, 111 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b47f56d1cb4..a7f8854a966 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -53,6 +53,7 @@
#define BEVEL_EPSILON 1e-6f
#define BEVEL_EPSILON_SQ 1e-12f
#define BEVEL_EPSILON_BIG 1e-4f
+#define BEVEL_EPSILON_BIG_SQ 1e-8f
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
@@ -345,33 +346,64 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
}
/* Return a good representative face (for materials, etc.) for faces
- * created around/near BoundVert v */
-static BMFace *boundvert_rep_face(BoundVert *v)
+ * created around/near BoundVert v.
+ * Sometimes care about a second choice, if there is one.
+ * If r_fother paramenter is non-NULL and there is another, different,
+ * possible frep, return the other one in that parameter. */
+static BMFace *boundvert_rep_face(BoundVert *v, BMFace **r_fother)
{
- BLI_assert(v->efirst != NULL && v->elast != NULL);
- if (v->efirst->fnext == v->elast->fprev)
- return v->efirst->fnext;
- else if (v->efirst->fnext)
- return v->efirst->fnext;
- else
- return v->elast->fprev;
+ BMFace *frep, *frep2;
+
+ frep2 = NULL;
+ if (v->ebev) {
+ frep = v->ebev->fprev;
+ if (v->efirst->fprev != frep)
+ frep2 = v->efirst->fprev;
+ }
+ else {
+ frep = v->efirst->fprev;
+ if (frep) {
+ if (v->elast->fnext != frep)
+ frep2 = v->elast->fnext;
+ else if (v->efirst->fnext != frep)
+ frep2 = v->efirst->fnext;
+ else if (v->elast->fprev != frep)
+ frep2 = v->efirst->fprev;
+ }
+ else if (v->efirst->fnext) {
+ frep = v->efirst->fnext;
+ if (v->elast->fnext != frep)
+ frep2 = v->elast->fnext;
+ }
+ else if (v->elast->fprev) {
+ frep = v->elast->fprev;
+ }
+ }
+ if (r_fother)
+ *r_fother = frep2;
+ return frep;
}
/**
* Make ngon from verts alone.
* Make sure to properly copy face attributes and do custom data interpolation from
* corresponding elements of face_arr, if that is non-NULL, else from facerep.
+ * If edge_arr is non-NULL, then for interpolation purposes only, the corresponding
+ * elements of vert_arr are snapped to any non-NULL edges in that array.
* If mat_nr >= 0 then the material of the face is set to that.
*
* \note ALL face creation goes through this function, this is important to keep!
*/
static BMFace *bev_create_ngon(
BMesh *bm, BMVert **vert_arr, const int totv,
- BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
+ BMFace **face_arr, BMFace *facerep, BMEdge **edge_arr,
+ int mat_nr, bool do_interp)
{
BMIter iter;
BMLoop *l;
BMFace *f, *interp_f;
+ BMEdge *bme;
+ float save_co[3];
int i;
f = BM_face_create_verts(bm, vert_arr, totv, facerep, BM_CREATE_NOP, true);
@@ -389,8 +421,19 @@ static BMFace *bev_create_ngon(
else {
interp_f = facerep;
}
- if (interp_f)
+ if (interp_f) {
+ bme = NULL;
+ if (edge_arr)
+ bme = edge_arr[i];
+ if (bme) {
+ copy_v3_v3(save_co, l->v->co);
+ closest_to_line_segment_v3(l->v->co, save_co, bme->v1->co, bme->v2->co);
+ }
BM_loop_interp_from_face(bm, l, interp_f, true, true);
+ if (bme) {
+ copy_v3_v3(l->v->co, save_co);
+ }
+ }
i++;
}
}
@@ -407,24 +450,28 @@ static BMFace *bev_create_ngon(
return f;
}
-static BMFace *bev_create_quad_tri(
+static BMFace *bev_create_quad(
BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *facerep, int mat_nr, bool do_interp)
+ BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4,
+ int mat_nr)
{
BMVert *varr[4] = {v1, v2, v3, v4};
- return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, mat_nr, do_interp);
+ BMFace *farr[4] = {f1, f2, f3, f4};
+ return bev_create_ngon(bm, varr, 4, farr, f1, NULL, mat_nr, true);
}
-static BMFace *bev_create_quad_tri_ex(
+static BMFace *bev_create_quad_ex(
BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
+ BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4,
+ BMEdge *e1, BMEdge *e2, BMEdge *e3, BMEdge *e4,
+ int mat_nr)
{
BMVert *varr[4] = {v1, v2, v3, v4};
BMFace *farr[4] = {f1, f2, f3, f4};
- return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, mat_nr, true);
+ BMEdge *earr[4] = {e1, e2, e3, e4};
+ return bev_create_ngon(bm, varr, 4, farr, f1, earr, mat_nr, true);
}
-
/* Is Loop layer layer_index contiguous across shared vertex of l1 and l2? */
static bool contig_ldata_across_loops(
BMesh *bm, BMLoop *l1, BMLoop *l2,
@@ -486,49 +533,6 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
return true;
}
-/**
- * Like bev_create_quad_tri, but when verts straddle an old edge.
- * <pre>
- * e
- * |
- * v1+---|---+v4
- * | | |
- * | | |
- * v2+---|---+v3
- * |
- * f1 | f2
- * </pre>
- *
- * Most CustomData for loops can be interpolated in their respective
- * faces' loops, but for UVs and other 'has_math_cd' layers, only
- * do this if the UVs are continuous across the edge e, otherwise pick
- * one side (f1, arbitrarily), and interpolate them all on that side.
- * For face data, use f1 (arbitrarily) as face representative.
- */
-static BMFace *bev_create_quad_straddle(
- BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *f1, BMFace *f2, int mat_nr, bool is_seam)
-{
- BMFace *f, *facerep;
- BMLoop *l;
- BMIter iter;
-
- f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, mat_nr, false);
-
- if (!f)
- return NULL;
-
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- if (is_seam || l->v == v1 || l->v == v2)
- facerep = f1;
- else
- facerep = f2;
- if (facerep)
- BM_loop_interp_from_face(bm, l, facerep, true, true);
- }
- return f;
-}
-
/* Merge (using average) all the UV values for loops of v's faces.
* Caller should ensure that no seams are violated by doing this. */
static void bev_merge_uvs(BMesh *bm, BMVert *v)
@@ -564,6 +568,47 @@ static void bev_merge_uvs(BMesh *bm, BMVert *v)
}
}
+/* Merge (using average) the UV values for two specific loops of v: those for faces containing v,
+ * and part of faces that share edge bme */
+static void bev_merge_edge_uvs(BMesh *bm, BMEdge *bme, BMVert *v)
+{
+ BMIter iter;
+ MLoopUV *luv;
+ BMLoop *l, *l1, *l2;
+ float uv[2];
+ int num_of_uv_layers = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
+ int i;
+
+ l1 = NULL;
+ l2 = NULL;
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ if (l->e == bme)
+ l1 = l;
+ else if (l->prev->e == bme)
+ l2 = l;
+ }
+ if (l1 == NULL || l2 == NULL)
+ return;
+
+ for (i = 0; i < num_of_uv_layers; i++) {
+ int cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, i);
+
+ if (cd_loop_uv_offset == -1)
+ return;
+
+ zero_v2(uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
+ add_v2_v2(uv, luv->uv);
+ mul_v2_fl(uv, 0.5f);
+ luv = BM_ELEM_CD_GET_VOID_P(l1, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, uv);
+ luv = BM_ELEM_CD_GET_VOID_P(l2, cd_loop_uv_offset);
+ copy_v2_v2(luv->uv, uv);
+ }
+}
+
/* Calculate coordinates of a point a distance d from v on e->e and return it in slideco */
static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3])
{
@@ -1523,6 +1568,20 @@ static void set_bound_vert_seams(BevVert *bv)
} while ((v = v->next) != bv->vmesh->boundstart);
}
+static int count_bound_vert_seams(BevVert *bv)
+{
+ int ans, i;
+
+ if (!bv->any_seam)
+ return 0;
+
+ ans = 0;
+ for (i = 0; i < bv->edgecount; i++)
+ if (bv->edges[i].is_seam)
+ ans++;
+ return ans;
+}
+
#ifndef PRE_275_ALGORITHM
/* Is e between two planes where angle between is 180? */
static bool eh_on_plane(EdgeHalf *e)
@@ -2948,6 +3007,63 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
return vm;
}
+static void get_incident_edges(BMFace *f, BMVert *v, BMEdge **r_e1, BMEdge **r_e2)
+{
+ BMIter iter;
+ BMEdge *e;
+
+ *r_e1 = NULL;
+ *r_e2 = NULL;
+ if (!f)
+ return;
+ BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) {
+ if (e->v1 == v || e->v2 == v) {
+ if (*r_e1 == NULL)
+ *r_e1 = e;
+ else if (*r_e2 == NULL)
+ *r_e2 = e;
+ }
+ }
+}
+
+static BMEdge *find_closer_edge(float *co, BMEdge *e1, BMEdge *e2)
+{
+ float dsq1, dsq2;
+
+ BLI_assert(e1 != NULL && e2 != NULL);
+ dsq1 = dist_squared_to_line_segment_v3(co, e1->v1->co, e1->v2->co);
+ dsq2 = dist_squared_to_line_segment_v3(co, e2->v1->co, e2->v2->co);
+ if (dsq1 < dsq2)
+ return e1;
+ else
+ return e2;
+}
+
+/* Snap co to the closest edge of face f. Return the edge in *r_snap_e,
+ * the coordinates of snap point in r_ snap_co,
+ * and the distance squared to the snap point as function return */
+static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, float *r_snap_co)
+{
+ BMIter iter;
+ BMEdge *beste = NULL;
+ float d2, beste_d2;
+ BMEdge *e;
+ float closest[3];
+
+ beste_d2 = 1e20;
+ BM_ITER_ELEM(e, &iter, f, BM_EDGES_OF_FACE) {
+ closest_to_line_segment_v3(closest, co, e->v1->co, e->v2->co);
+ d2 = len_squared_v3v3(closest, co);
+ if (d2 < beste_d2) {
+ beste_d2 = d2;
+ beste = e;
+ copy_v3_v3(r_snap_co, closest);
+ }
+ }
+ *r_snap_e = beste;
+ return beste_d2;
+}
+
/*
* Given that the boundary is built and the boundary BMVerts have been made,
* calculate the positions of the interior mesh points for the M_ADJ pattern,
@@ -2958,7 +3074,9 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
VMesh *vm1, *vm;
BoundVert *v;
BMVert *bmv1, *bmv2, *bmv3, *bmv4;
- BMFace *f, *f2, *f23;
+ BMFace *f, *f2;
+ BMEdge *bme, *bme1, *bme2, *bme3;
+ EdgeHalf *e;
BoundVert *vpipe;
int mat_nr = bp->mat_nr;
@@ -2996,8 +3114,14 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
v = vm->boundstart;
do {
i = v->index;
- f = boundvert_rep_face(v);
- f2 = boundvert_rep_face(v->next);
+ f = boundvert_rep_face(v, NULL);
+ f2 = boundvert_rep_face(v->next, NULL);
+ if (bp->vertex_only)
+ e = v->efirst;
+ else
+ e = v->ebev;
+ BLI_assert(e != NULL);
+ bme = e->e;
/* For odd ns, make polys with lower left corner at (i,j,k) for
* j in [0, ns2-1], k in [0, ns2]. And then the center ngon.
* For even ns,
@@ -3009,11 +3133,47 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
bmv3 = mesh_vert(vm, i, j + 1, k + 1)->v;
bmv4 = mesh_vert(vm, i, j + 1, k)->v;
BLI_assert(bmv1 && bmv2 && bmv3 && bmv4);
- f23 = f;
- if (odd && k == ns2 && f2 && !v->any_seam)
- f23 = f2;
- bev_create_quad_tri_ex(bm, bmv1, bmv2, bmv3, bmv4,
- f, f23, f23, f, mat_nr);
+ if (bp->vertex_only) {
+ if (j < k) {
+ if (k == ns2 && j == ns2 - 1)
+ bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ NULL, NULL, v->next->efirst->e, bme, mat_nr);
+ else
+ bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ }
+ else if (j > k) {
+ bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2, mat_nr);
+ }
+ else { /* j == k */
+ /* only one edge attached to v, since vertex_only */
+ if (e->is_seam)
+ bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f2,
+ bme, NULL, bme, NULL, mat_nr);
+ else
+ bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f2, f2, f2, f,
+ bme, NULL, bme, NULL, mat_nr);
+ }
+ }
+ else { /* edge bevel */
+ if (odd) {
+ if (k == ns2) {
+ if (e->is_seam)
+ bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ NULL, bme, bme, NULL, mat_nr);
+ else
+ bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f2, f2, f, mat_nr);
+ }
+ else
+ bev_create_quad(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f, mat_nr);
+ }
+ else {
+ bme1 = k == ns2 - 1 ? bme : NULL;
+ bme3 = j == ns2 - 1 ? v->prev->ebev->e : NULL;
+ bme2 = bme1 != NULL ? bme1 : bme3;
+ bev_create_quad_ex(bm, bmv1, bmv2, bmv3, bmv4, f, f, f, f,
+ NULL, bme1, bme2, bme3, mat_nr);
+ }
+ }
}
}
} while ((v = v->next) != vm->boundstart);
@@ -3032,66 +3192,147 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
}
}
} while ((v = v->next) != vm->boundstart);
- if (!bv->any_seam)
- bev_merge_uvs(bm, mesh_vert(vm, 0, ns2, ns2)->v);
+ bmv1 = mesh_vert(vm, 0, ns2, ns2)->v;
+ if (bp->vertex_only || count_bound_vert_seams(bv) <= 1)
+ bev_merge_uvs(bm, bmv1);
}
/* center ngon */
if (odd) {
+ BMFace *frep;
+ BMEdge *frep_e1, *frep_e2, *frep_e;
BMVert **vv = NULL;
BMFace **vf = NULL;
+ BMEdge **ve = NULL;
BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+ if (bv->any_seam) {
+ frep = boundvert_rep_face(vm->boundstart, NULL);
+ get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ }
+ else {
+ frep = NULL;
+ frep_e1 = frep_e2 = NULL;
+ }
v = vm->boundstart;
do {
i = v->index;
BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
- BLI_array_append(vf, v->any_seam ? f : boundvert_rep_face(v));
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
+ }
+ else {
+ BLI_array_append(vf, frep);
+ BLI_array_append(ve, NULL);
+ }
} while ((v = v->next) != vm->boundstart);
- f = boundvert_rep_face(vm->boundstart);
- bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, mat_nr, true);
+ bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true);
BLI_array_free(vv);
+ BLI_array_free(vf);
+ BLI_array_free(ve);
}
}
+/* If we make a poly out of verts around bv, snapping to rep frep, will uv poly have zero area?
+ * The uv poly is made by snapping all outside-of-frep vertices to the closest edge in frep.
+ * Assume that this funciton is called when the only inside-of-frep vertex is vm->boundstart.
+ * The poly will have zero area if the distance of that first vertex to some edge e is zero, and all
+ * the other vertices snap to e or snap to an edge at a point that is essentially on e too. */
+static bool is_bad_uv_poly(BevVert *bv, BMFace *frep)
+{
+ BoundVert *v;
+ BMEdge *snape, *firste;
+ float co[3];
+ VMesh *vm = bv->vmesh;
+ float d2;
+
+ v = vm->boundstart;
+ d2 = snap_face_dist_squared(v->nv.v->co, frep, &firste, co);
+ if (d2 > BEVEL_EPSILON_BIG_SQ || firste == NULL)
+ return false;
+
+ for (v = v->next; v != vm->boundstart; v = v->next) {
+ snap_face_dist_squared(v->nv.v->co, frep, &snape, co);
+ if (snape != firste) {
+ d2 = dist_to_line_v3(co, firste->v1->co, firste->v2->co);
+ if (d2 > BEVEL_EPSILON_BIG_SQ)
+ return false;
+ }
+ }
+ return true;
+}
+
static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
{
- BMFace *f;
+ BMFace *f, *frep, *frep2;
int n, k;
VMesh *vm = bv->vmesh;
BoundVert *v;
- BMFace *frep;
+ BMEdge *frep_e1, *frep_e2, *frep_e;
BMVert **vv = NULL;
BMFace **vf = NULL;
+ BMEdge **ve = NULL;
BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
- frep = boundvert_rep_face(vm->boundstart);
+ if (bv->any_seam) {
+ frep = boundvert_rep_face(vm->boundstart, &frep2);
+ if (frep2 && frep && is_bad_uv_poly(bv, frep)) {
+ frep = frep2;
+ }
+ get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ }
+ else {
+ frep = NULL;
+ frep_e1 = frep_e2 = NULL;
+ }
v = vm->boundstart;
n = 0;
do {
/* accumulate vertices for vertex ngon */
/* also accumulate faces in which uv interpolation is to happen for each */
BLI_array_append(vv, v->nv.v);
- BLI_array_append(vf, bv->any_seam ? frep : boundvert_rep_face(v));
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(v->nv.v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, n > 0 ? frep_e : NULL);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
n++;
if (v->ebev && v->ebev->seg > 1) {
for (k = 1; k < v->ebev->seg; k++) {
BLI_array_append(vv, mesh_vert(vm, v->index, 0, k)->v);
- BLI_array_append(vf, bv->any_seam ? frep : boundvert_rep_face(v));
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(mesh_vert(vm, v->index, 0, k)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, k < v->ebev->seg / 2 ? NULL : frep_e);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
n++;
}
}
} while ((v = v->next) != vm->boundstart);
if (n > 2) {
- f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), bp->mat_nr, true);
+ f = bev_create_ngon(bm, vv, n, vf, frep, ve, bp->mat_nr, true);
}
else {
f = NULL;
}
BLI_array_free(vv);
+ BLI_array_free(vf);
+ BLI_array_free(ve);
return f;
}
@@ -3688,7 +3929,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
if (do_rebuild) {
n = BLI_array_count(vv);
- f_new = bev_create_ngon(bm, vv, n, NULL, f, -1, true);
+ f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true);
for (k = 0; k < BLI_array_count(vv_fix); k++) {
bev_merge_uvs(bm, vv_fix[k]);
@@ -3886,18 +4127,20 @@ static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex
}
}
-
/*
* Build the polygons along the selected Edge
*/
static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
{
BevVert *bv1, *bv2;
- BMVert *bmv1, *bmv2, *bmv3, *bmv4, *bmv1i, *bmv2i, *bmv3i, *bmv4i;
+ BMVert *bmv1, *bmv2, *bmv3, *bmv4;
VMesh *vm1, *vm2;
EdgeHalf *e1, *e2;
- BMEdge *bme1, *bme2;
+ BMEdge *bme1, *bme2, *center_bme;
BMFace *f1, *f2, *f;
+ BMVert *verts[4];
+ BMFace *faces[4];
+ BMEdge *edges[4];
int k, nseg, i1, i2, odd, mid;
int mat_nr = bp->mat_nr;
@@ -3914,11 +4157,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
BLI_assert(e1 && e2);
- /* v4 v3
- * \ /
- * e->v1 - e->v2
- * / \
- * v1 v2
+ /*
+ * bme->v1
+ * / | \
+ * v1--|--v4
+ * | | |
+ * | | |
+ * v2--|--v3
+ * \ | /
+ * bme->v2
*/
nseg = e1->seg;
BLI_assert(nseg > 0 && nseg == e2->seg);
@@ -3932,42 +4179,67 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
f1 = e1->fprev;
f2 = e1->fnext;
+ faces[0] = faces[1] = f1;
+ faces[2] = faces[3] = f2;
i1 = e1->leftv->index;
i2 = e2->leftv->index;
vm1 = bv1->vmesh;
vm2 = bv2->vmesh;
- if (nseg == 1) {
- bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam);
- }
- else {
- bmv1i = bmv1;
- bmv2i = bmv2;
- odd = nseg % 2;
- mid = nseg / 2;
- for (k = 1; k <= nseg; k++) {
- bmv4i = mesh_vert(vm1, i1, 0, k)->v;
- bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v;
- if (odd && k == mid + 1) {
- bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, mat_nr, e1->is_seam);
+ verts[0] = bmv1;
+ verts[1] = bmv2;
+ odd = nseg % 2;
+ mid = nseg / 2;
+ center_bme = NULL;
+ for (k = 1; k <= nseg; k++) {
+ verts[3] = mesh_vert(vm1, i1, 0, k)->v;
+ verts[2] = mesh_vert(vm2, i2, 0, nseg - k)->v;
+ if (odd && k == mid + 1) {
+ if (e1->is_seam) {
+ /* straddles a seam: choose to interpolate in f1 and snap right edge to bme */
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
}
else {
- f = (k <= mid) ? f1 : f2;
- bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, mat_nr, true);
+ /* straddles but not a seam: interpolate left half in f1, right half in f2 */
+ bev_create_ngon(bm, verts, 4, faces, NULL, NULL, mat_nr, true);
}
- bmv1i = bmv4i;
- bmv2i = bmv3i;
}
- if (!odd && !e1->is_seam) {
- bev_merge_uvs(bm, mesh_vert(vm1, i1, 0, mid)->v);
- bev_merge_uvs(bm, mesh_vert(vm2, i2, 0, mid)->v);
+ else if (!odd && k == mid) {
+ /* left poly that touches an even center line on right */
+ edges[0] = edges[1] = NULL;
+ edges[2] = edges[3] = bme;
+ bev_create_ngon(bm, verts, 4, NULL, f1, edges, mat_nr, true);
+ center_bme = BM_edge_exists(verts[2], verts[3]);
+ BLI_assert(center_bme != NULL);
+ }
+ else if (!odd && k == mid + 1) {
+ /* right poly that touches an even center line on left */
+ edges[0] = edges[1] = bme;
+ edges[2] = edges[3] = NULL;
+ bev_create_ngon(bm, verts, 4, NULL, f2, edges, mat_nr, true);
}
+ else {
+ /* doesn't cross or touch the center line, so interpolate in appropriate f1 or f2 */
+ f = (k <= mid) ? f1 : f2;
+ bev_create_ngon(bm, verts, 4, NULL, f, NULL, mat_nr, true);
+ }
+ verts[0] = verts[3];
+ verts[1] = verts[2];
+ }
+ if (!odd) {
+ if (!e1->is_seam)
+ bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm1, i1, 0, mid)->v);
+ if (!e2->is_seam)
+ bev_merge_edge_uvs(bm, center_bme, mesh_vert(vm2, i2, 0, mid)->v);
}
/* Fix UVs along end edge joints. A nop unless other side built already. */
- if (!e1->is_seam && bv1->vmesh->mesh_kind == M_NONE)
+ /* TODO: if some seam, may want to do selective merge */
+ if (!bv1->any_seam && bv1->vmesh->mesh_kind == M_NONE)
bev_merge_end_uvs(bm, bv1, e1);
- if (!e2->is_seam && bv2->vmesh->mesh_kind == M_NONE)
+ if (!bv2->any_seam && bv2->vmesh->mesh_kind == M_NONE)
bev_merge_end_uvs(bm, bv2, e2);
/* Copy edge data to first and last edge */