[Bf-blender-cvs] [bd9ed0228b8] master: Fix bevel profile=1 problems, see T39132, T38458, T40278, T51010, T53783.

Howard Trickey noreply at git.blender.org
Mon Feb 5 20:24:53 CET 2018


Commit: bd9ed0228b8455167a404c11121f0d4d46e4c689
Author: Howard Trickey
Date:   Mon Feb 5 14:21:43 2018 -0500
Branches: master
https://developer.blender.org/rBbd9ed0228b8455167a404c11121f0d4d46e4c689

Fix bevel profile=1 problems, see T39132, T38458, T40278, T51010,
T53783.

Before, profile=1 ("square outside") only worked well in a few cases
(some "pipes", cube corners). This makes it work well pretty much
everywhere.

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

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 51238c92505..e89f54349f7 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -2170,7 +2170,6 @@ static void adjust_offsets(BevelParams *bp)
 				v->visited = true;
 				if (vnext->visited) {
 					if (vnext != vchainstart) {
-						printf("WHOOPS, adjusting offsets, expected cycle!\n");
 						break;
 					}
 					adjust_the_cycle_or_chain(vchainstart, true);
@@ -3187,6 +3186,173 @@ static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh
 	}
 }
 
+/* copy whichever of a and b is closer to v into r */
+static void closer_v3_v3v3v3(float r[3], float a[3], float b[3], float v[3])
+{
+	if (len_squared_v3v3(a, v) <= len_squared_v3v3(b, v))
+		copy_v3_v3(r, a);
+	else
+		copy_v3_v3(r, b);
+}
+
+/* Special case of VMesh when profile == 1 and there are 3 or more beveled edges.
+ * We want the effect of parallel offset lines (n/2 of them) on each side of the center, for even n.
+ * Wherever they intersect with each other between two successive beveled edges, those intersections
+ * are part of the vmesh rings.
+ * We have to move the boundary edges too -- the usual method is to make one profile plane between
+ * successive BoundVerts, but for the effect we want here, there will be two planes, one on each side
+ * of the original edge.
+ */
+static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
+{
+	int n, ns, ns2, odd, i, j, k, ikind, im1, clstride;
+	float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3];
+	float *on_edge_cur, *on_edge_prev, *p;
+	float ns2inv, finalfrac, ang;
+	BoundVert *bndv;
+	EdgeHalf *e1, *e2;
+	VMesh *vm;
+	float *centerline;
+
+	n = bv->vmesh->count;
+	ns = bv->vmesh->seg;
+	ns2 = ns / 2;
+	odd = ns % 2;
+	ns2inv = 1.0f / (float) ns2;
+	vm = new_adj_vmesh(bp->mem_arena, n, ns, bv->vmesh->boundstart);
+	clstride = 3 * (ns2 + 1);
+	centerline = MEM_mallocN(clstride * n * sizeof(float), "bevel");
+
+	/* find on_edge, place on bndv[i]'s elast where offset line would meet,
+	 * averaging with position where next sector's offset line would meet */
+	bndv = vm->boundstart;
+	for (i = 0; i < n; i++) {
+		copy_v3_v3(bndco, bndv->nv.co);
+		e1 = bndv->efirst;
+		e2 = bndv->elast;
+		sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co);
+		sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co);
+		add_v3_v3v3(co1, bndco, dir1);
+		add_v3_v3v3(co2, bndco, dir2);
+		/* intersect e1 with line through bndv parallel to e2 to get v1co */
+		ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2);
+
+		if (ikind == 0) {
+			/* Placeholder: this should get eliminated by min dist test with adjacent edge */
+			mid_v3_v3v3(v1co, e1->e->v1->co, e1->e->v2->co);
+		}
+		else {
+			/* if the lines are skew (ikind == 2), want meet1 which is on e1 */
+			copy_v3_v3(v1co, meet1);
+		}
+		/* intersect e2 with line through bndv parallel to e1 to get v2co */
+		ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2);
+		if (ikind == 0) {
+			mid_v3_v3v3(v2co, e2->e->v1->co, e2->e->v2->co);
+		}
+		else {
+			copy_v3_v3(v2co, meet1);
+		}
+
+		/* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */
+		on_edge_cur = centerline + clstride * i;
+		on_edge_prev = centerline + clstride * ((i == 0) ? n - 1 : i - 1);
+		if (i == 0) {
+			copy_v3_v3(on_edge_cur, v2co);
+			copy_v3_v3(on_edge_prev, v1co);
+		}
+		else if (i == n - 1) {
+			closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co);
+			closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
+		}
+		else {
+			copy_v3_v3(on_edge_cur, v2co);
+			closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
+		}
+		bndv = bndv->next;
+	}
+
+	/* fill in rest of centerlines by interpolation */
+	copy_v3_v3(co2, bv->v->co);
+	bndv = vm->boundstart;
+	for (i = 0; i < n; i++) {
+		if (odd) {
+			ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co);
+			if (ang > BEVEL_SMALL_ANG) {
+				/* finalfrac is length along arms of isoceles triangle with top angle 2*ang
+				 * such that the base of the triangle is 1.
+				 * This is used in interpolation along centerline in odd case.
+				 * To avoid too big a drop from bv, cap finalfrac a 0.8 arbitrarily */
+				finalfrac = 0.5f / sin(ang);
+				if (finalfrac > 0.8f)
+					finalfrac = 0.8f;
+			}
+			else {
+				finalfrac = 0.8f;
+			}
+			ns2inv = 1.0f / (ns2 + finalfrac);
+		}
+
+		p = centerline + clstride * i;
+		copy_v3_v3(co1, p);
+		p += 3;
+		for (j = 1; j <= ns2; j++) {
+			interp_v3_v3v3(p, co1, co2, j * ns2inv);
+			p += 3;
+		}
+		bndv = bndv->next;
+	}
+
+	/* coords of edges and mid or near-mid line */
+	bndv = vm->boundstart;
+	for (i = 0; i < n; i++) {
+		copy_v3_v3(co1, bndv->nv.co);
+		copy_v3_v3(co2, centerline + clstride * (i == 0 ? n - 1 : i - 1));
+		for (j = 0; j < ns2 + odd; j++) {
+			interp_v3_v3v3(mesh_vert(vm, i, j, 0)->co, co1, co2, j * ns2inv);
+		}
+		copy_v3_v3(co2, centerline + clstride * i);
+		for (k = 1; k <= ns2; k++) {
+			interp_v3_v3v3(mesh_vert(vm, i, 0, k)->co, co1, co2, k * ns2inv);
+		}
+		bndv = bndv->next;
+	}
+	if (!odd)
+		copy_v3_v3(mesh_vert(vm, 0, ns2, ns2)->co, bv->v->co);
+	vmesh_copy_equiv_verts(vm);
+
+	/* fill in interior points by interpolation from edges to centerlines */
+	bndv = vm->boundstart;
+	for (i = 0; i < n; i++) {
+		im1 = (i == 0) ? n - 1 : i - 1;
+		for (j = 1; j < ns2 + odd; j++) {
+			for (k = 1; k <= ns2; k++) {
+				ikind = isect_line_line_v3(
+					mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k,
+					mesh_vert(vm, i, j, 0)->co, centerline + clstride * i + 3 * j,
+					meet1, meet2);
+				if (ikind == 0) {
+					/* how can this happen? fall back on interpolation in one direction if it does */
+					interp_v3_v3v3(mesh_vert(vm, i, j, k)->co,
+						mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k, j * ns2inv);
+				}
+				else if (ikind == 1) {
+					copy_v3_v3(mesh_vert(vm, i, j, k)->co, meet1);
+				}
+				else {
+					mid_v3_v3v3(mesh_vert(vm, i, j, k)->co, meet1, meet2);
+				}
+			}
+		}
+		bndv = bndv->next;
+	}
+
+	vmesh_copy_equiv_verts(vm);
+
+	MEM_freeN(centerline);
+	return vm;
+}
+
 /*
  * 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,
@@ -3209,9 +3375,13 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
 	odd = ns % 2;
 	BLI_assert(n >= 3 && ns > 1);
 
+
 	vpipe = pipe_test(bv);
 
-	if (vpipe) {
+	if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd) {
+		vm1 = square_out_adj_vmesh(bp, bv);
+	}
+	else if (vpipe) {
 		vm1 = pipe_adj_vmesh(bp, bv, vpipe);
 	}
 	else if (tri_corner_test(bp, bv)) {



More information about the Bf-blender-cvs mailing list