[Bf-blender-cvs] [39ce0a9] master: 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.

Howard Trickey noreply at git.blender.org
Wed Aug 12 16:24:25 CEST 2015


Commit: 39ce0a99165782536eb55acc9d173c46d3071063
Author: Howard Trickey
Date:   Wed Aug 12 10:18:58 2015 -0400
Branches: master
https://developer.blender.org/rB39ce0a99165782536eb55acc9d173c46d3071063

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.

===================================================================

M	source/blender/bmesh/tools/bmesh_bevel.c

===================================================================

diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b47f56d..a7f8854 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->vert

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list