[Bf-blender-cvs] [bdc15061fc5] master: Better bevel profile at extreme values of profile.

Howard Trickey noreply at git.blender.org
Mon Dec 4 15:38:37 CET 2017


Commit: bdc15061fc5cf0c0c9bd075894b3a475e482248e
Author: Howard Trickey
Date:   Mon Dec 4 09:30:40 2017 -0500
Branches: master
https://developer.blender.org/rBbdc15061fc5cf0c0c9bd075894b3a475e482248e

Better bevel profile at extreme values of profile.

Patch from Richard Erhardt, with some additions & modifications.
Changes bevel profile shape parameter so that can get arbitrarily
near square profile as parameter -> 1.
Adds code to make profile=0 case work, at least for cube corners,
so changed hard min of profile parameter to 0 from 0.15.

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

M	source/blender/bmesh/tools/bmesh_bevel.c
M	source/blender/editors/mesh/editmesh_bevel.c
M	source/blender/makesrna/intern/rna_modifier.c

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

diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 51a0fa4b2cc..2c6213dacce 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -117,7 +117,7 @@ typedef struct Profile {
 	float *prof_co;      /* seg+1 profile coordinates (triples of floats) */
 	float *prof_co_2;    /* like prof_co, but for seg power of 2 >= seg */
 } Profile;
-#define PRO_SQUARE_R 4.0f
+#define PRO_SQUARE_R 1e4f
 #define PRO_CIRCLE_R 2.0f
 #define PRO_LINE_R 1.0f
 #define PRO_SQUARE_IN_R 0.0f
@@ -126,8 +126,10 @@ typedef struct Profile {
  * get even spacing on superellipse for current BevelParams seg
  * and pro_super_r. */
 typedef struct ProfileSpacing {
-	float *uvals;       /* seg+1 u values */
-	float *uvals_2;     /* seg_2+1 u values, seg_2 = power of 2 >= seg */
+	double *xvals;      /* seg+1 x values */
+	double *xvals_2;    /* seg_2+1 x values, seg_2 = power of 2 >= seg */
+	double *yvals;      /* seg+1 y values */
+	double *yvals_2;    /* seg_2+1 y values, seg_2 = power of 2 >= seg */
 	int seg_2;          /* the seg_2 value */
 } ProfileSpacing;
 
@@ -1383,56 +1385,21 @@ static void make_unit_cube_map(
 	r_mat[3][3] = 1.0f;
 }
 
-/* Get the coordinate on the superellipse (exponent r),
- * at parameter value u.  u goes from u to 2 as the
- * superellipse moves on the quadrant (0,1) to (1,0). */
-static void superellipse_co(float u, float r, float r_co[2])
+/* Get the coordinate on the superellipse (x^r + y^r = 1),
+ * at parameter value x (or, if !rbig, mirrored (y=x)-line).
+ * rbig should be true if r > 1.0 and false if <= 1.0.
+ * Assume r > 0.0 */
+static double superellipse_co(double x, float r, bool rbig)
 {
-	float t;
-	
-	if (u <= 0.0f) {
-		r_co[0] = 0.0f;
-		r_co[1] = 1.0f;
-	}
-	else if (u >= 2.0f) {
-		r_co[0] = 1.0f;
-		r_co[1] = 0.0f;
-	}
-	else if (r == PRO_LINE_R) {
-		t = u / 2.0f;
-		r_co[0] = t;
-		r_co[1] = 1.0f - t;
-		
-	}
-	else if (r == PRO_SQUARE_IN_R) {
-		if (u < 1.0f) {
-			r_co[0] = 0.0f;
-			r_co[1] = 1.0f - u;
-		}
-		else {
-			r_co[0] = u - 1.0f;
-			r_co[1] = 0.0f;
-		}
-	}
-	else if (r == PRO_SQUARE_R) {
-		if (u < 1.0f) {
-			r_co[0] = u;
-			r_co[1] = 1.0f;
-		}
-		else {
-			r_co[0] = 1.0f;
-			r_co[1] = 2.0f - u;
-		}
-		
+	BLI_assert(r > 0.0f);
+
+	/* If r<1, mirror the superellipse function by (y=x)-line to get a numerically stable range
+	 * Possible because of symmetry, later mirror back. */
+	if (rbig) {
+		return pow((1.0 - pow(x, r)), (1.0 / r));
 	}
 	else {
-		t = u * (float)M_PI / 4.0f;  /* angle from y axis */
-		r_co[0] = sinf(t);
-		r_co[1] = cosf(t);
-		if (r != PRO_SQUARE_R) {
-			r_co[0] = pow(r_co[0], 2.0f / r);
-			r_co[1] = pow(r_co[1], 2.0f / r);
-		}
+		return 1.0 - pow((1.0 - pow(1.0 - x, r)), (1.0 / r));
 	}
 }
 
@@ -1478,7 +1445,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int n,
 static void calculate_profile(BevelParams *bp, BoundVert *bndv)
 {
 	int i, k, ns;
-	const float *uvals;
+	const double *xvals, *yvals;
 	float co[3], co2[3], p[3], m[4][4];
 	float *prof_co, *prof_co_k;
 	float r;
@@ -1504,17 +1471,19 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv)
 	for (i = 0; i < 2; i++) {
 		if (i == 0) {
 			ns = bp->seg;
-			uvals = bp->pro_spacing.uvals;
+			xvals = bp->pro_spacing.xvals;
+			yvals = bp->pro_spacing.yvals;
 			prof_co = pro->prof_co;
 		}
 		else {
 			if (!need_2)
 				break;  /* shares coords with pro->prof_co */
 			ns = bp->pro_spacing.seg_2;
-			uvals = bp->pro_spacing.uvals_2;
+			xvals = bp->pro_spacing.xvals_2;
+			yvals = bp->pro_spacing.yvals_2;
 			prof_co = pro->prof_co_2;
 		}
-		BLI_assert((r == PRO_LINE_R || uvals != NULL) && prof_co != NULL);
+		BLI_assert((r == PRO_LINE_R || (xvals != NULL && yvals != NULL)) && prof_co != NULL);
 		for (k = 0; k <= ns; k++) {
 			if (k == 0)
 				copy_v3_v3(co, pro->coa);
@@ -1522,7 +1491,8 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv)
 				copy_v3_v3(co, pro->cob);
 			else {
 				if (map_ok) {
-					superellipse_co(uvals[k], r, p);
+					p[0] = xvals[k];
+					p[1] = yvals[k];
 					p[2] = 0.0f;
 					mul_v3_m4v3(co, m, p);
 				}
@@ -2581,9 +2551,8 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm0)
 	return vm1;
 }
 
-/* Special case for cube corner, when r is PRO_SQUARE_R,
- * meaning straight sides */
-static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg)
+/* Special case for cube corner, when r is PRO_SQUARE_R, meaning straight sides */
+static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg)
 {
 	VMesh *vm;
 	float co[3];
@@ -2613,6 +2582,46 @@ static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg)
 	return vm;
 }
 
+/* Special case for cube corner, when r is PRO_SQUARE_IN_R, meaning inward
+ * straight sides.
+ * We mostly don't want a VMesh at all for this case -- just a three-way weld
+ * with a triangle in the middle for odd nseg */
+static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg)
+{
+	VMesh *vm;
+	float co[3];
+	float b;
+	int i, k, ns2, odd;
+
+	ns2 = nseg / 2;
+	odd = nseg % 2;
+	vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
+	vm->count = 0;  // reset, so following loop will end up with correct count
+	for (i = 0; i < 3; i++) {
+		zero_v3(co);
+		co[i] = 1.0f;
+		add_new_bound_vert(mem_arena, vm, co);
+	}
+	if (odd)
+		b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2);
+	else
+		b = 2.0f / (float)nseg;
+	for (i = 0; i < 3; i++) {
+		for (k = 0; k <= ns2; k++) {
+			co[i] = 1.0f - (float)k * b;
+			co[(i + 1) % 3] = 0.0f;
+			co[(i + 2) % 3] = 0.0f;
+			copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
+			co[(i + 1) % 3] = 1.0f - (float)k * b;
+			co[(i + 2) % 3] = 0.0f;
+			co[i] = 0.0f;
+			copy_v3_v3(mesh_vert(vm, i, 0, nseg - k)->co, co);
+		}
+	}
+	return vm;
+}
+
+
 /* Make a VMesh with nseg segments that covers the unit radius sphere octant
  * with center at (0,0,0).
  * This has BoundVerts at (1,0,0), (0,1,0) and (0,0,1), with quarter circle arcs
@@ -2629,7 +2638,9 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
 	float co[3], coc[3];
 
 	if (r == PRO_SQUARE_R)
-		return make_cube_corner_straight(mem_arena, nseg);
+		return make_cube_corner_square(mem_arena, nseg);
+	else if (r == PRO_SQUARE_IN_R)
+		return make_cube_corner_square_in(mem_arena, nseg);
 
 	/* initial mesh has 3 sides, 2 segments */
 	vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL);
@@ -2687,6 +2698,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
 			}
 		}
 	}
+
 	return vm1;
 }
 
@@ -2944,6 +2956,87 @@ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, flo
 	return beste_d2;
 }
 
+static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr)
+{
+	VMesh *vm = bv->vmesh;
+	BoundVert *v;
+	int i, ns2;
+	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);
+
+	ns2 = vm->seg / 2;
+	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);
+		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, boundvert_rep_face(v, NULL));
+			BLI_array_append(ve, NULL);
+		}
+	} while ((v = v->next) != vm->boundstart);
+	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);
+}
+
+/* Special case of bevel_build_rings when tri-corner and profile is 0.
+ * There is no corner mesh except, if nseg odd, for a center poly.
+ * Boundary verts merge with previous ones according to pattern:
+ * (i, 0, k) merged with (i+1, 0, ns-k) for k <= ns/2 */
+static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh *vm1)
+{
+	int n, ns, ns2, odd, i, k;
+	VMesh *vm;
+
+	vm = bv->vmesh;
+	n = vm->count;
+	ns = vm->seg;
+	ns2 = ns / 2;
+	odd = ns % 2;
+
+	for (i = 0; i < n; i++) {
+		for (k = 1; k < ns; k++) {
+			copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co);
+			if (i > 0 && k <= ns2) {
+				mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v;
+			}
+			else if (i == n - 1 && k > ns2) {
+				mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, 0, 0, ns - k)->v;
+			}
+			else {
+				create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
+			}
+		}
+	}
+	if (odd) {
+		for (i = 0; i < n; i++) {
+			mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v;
+		}
+		build_center_ngon(bm, bv, bp->mat_nr);
+	}
+}
+
 /*
  * 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,
@@ -2968,12 +3061,21 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
 
 	vpipe = pipe_test(bv);
 
-	if (vpipe)
+	if (vpipe) {
 		vm1 = pipe_adj_vmesh(bp, bv, vpipe);
-	else if (tri_corner_test(bp, bv))
+	}
+	else if (tri_corner_test(bp, bv)) {
 		vm1 = tri_corner_adj_vmesh(bp, bv);
-	else
+		/* the PRO_SQUARE_IN_R profile has boundary edges that merge
+		 * and no internal ring polys except possibly center ngon */
+		if (bp->pro_super_r == PRO_SQUARE_IN_R) {
+			build_square_in_vmesh(bp, bm, bv, vm1);
+			return;
+		}
+	}
+	else {
 		vm1 = adj_vmesh(bp, bv);
+	}
 
 	/* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
 	vm = bv->vmesh;
@@ -3086,42 +3188,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
 
 	/* 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(v

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list