[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