[Bf-blender-cvs] [49aa701] master: Add profile control parameter to Bevel.

Howard Trickey noreply at git.blender.org
Wed Jan 8 13:45:12 CET 2014


Commit: 49aa701645e97ea7a6f698e4063a5327f6c79815
Author: Howard Trickey
Date:   Wed Jan 8 07:40:01 2014 -0500
https://developer.blender.org/rB49aa701645e97ea7a6f698e4063a5327f6c79815

Add profile control parameter to Bevel.

Parameter controls concavity / convexity.
    <.25 means: concave inward
    .25 means: straight slanted
    >.25 means: concave outward
    .5 means: circular (the default)
    1 means: straight along original sides
For now, there is a hard lower limit of .15
because more work is needed to get decent
results in the range below that.

The profile is actually a superellipse, and the
parameter is 1/4 of the exponent in the implicit equation
for a superellipse, except at the extreme values of 0 and 1.

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

M	source/blender/bmesh/intern/bmesh_opdefines.c
M	source/blender/bmesh/operators/bmo_bevel.c
M	source/blender/bmesh/tools/bmesh_bevel.c
M	source/blender/bmesh/tools/bmesh_bevel.h
M	source/blender/editors/mesh/editmesh_bevel.c
M	source/blender/modifiers/intern/MOD_bevel.c

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

diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 97624ec..b469793 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1559,6 +1559,7 @@ static BMOpDefine bmo_bevel_def = {
 	 {"offset", BMO_OP_SLOT_FLT},           /* amount to offset beveled edge */
 	 {"offset_type", BMO_OP_SLOT_INT},      /* how to measure offset (enum) */
 	 {"segments", BMO_OP_SLOT_INT},         /* number of segments in bevel */
+	 {"profile", BMO_OP_SLOT_FLT},          /* profile shape, 0->1 (.5=>round) */
 	 {"vertex_only", BMO_OP_SLOT_BOOL},	/* only bevel vertices, not edges */
 	 {{'\0'}},
 	},
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index 4eec15d..07a2e67 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -39,6 +39,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
 	const int   offset_type = BMO_slot_int_get(op->slots_in,   "offset_type");
 	const int   seg         = BMO_slot_int_get(op->slots_in,   "segments");
 	const bool  vonly       = BMO_slot_bool_get(op->slots_in,  "vertex_only");
+	const float profile     = BMO_slot_float_get(op->slots_in, "profile");
 
 	if (offset > 0) {
 		BMOIter siter;
@@ -59,7 +60,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
 			}
 		}
 
-		BM_mesh_bevel(bm, offset, offset_type, seg, vonly, false, false, NULL, -1);
+		BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1);
 
 		BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
 	}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 984632d..4a6032a 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -89,14 +89,20 @@ typedef struct EdgeHalf {
 } EdgeHalf;
 
 /* Profile specification.
- * For now, only have round profiles and straight profiles, so only need midpoint.
+ * Many interesting profiles are in family of superellipses:
+ *     (abs(x/a))^r + abs(y/b))^r = 1
+ * r==2 => ellipse; r==1 => line; r < 1 => concave; r > 1 => bulging out.
+ * Special cases: let r==0 mean straight-inward, and r==4 mean straight outward
  * The start and end points of the profile are stored separately.
- * TODO: generalize to superellipse profiles.
  */
 typedef struct Profile {
-	bool flat;
+	float super_r;       /* superellipse r parameter */
 	float midco[3];      /* mid control point for profile */
 } Profile;
+#define PRO_SQUARE_R 4.0f
+#define PRO_CIRCLE_R 2.0f
+#define PRO_LINE_R 1.0f
+#define PRO_SQUARE_IN_R 0.0f
 
 /* An element in a cyclic boundary of a Vertex Mesh (VMesh) */
 typedef struct BoundVert {
@@ -150,6 +156,7 @@ typedef struct BevelParams {
 	float offset;           /* blender units to offset each side of a beveled edge */
 	int offset_type;        /* how offset is measured; enum defined in bmesh_operators.h */
 	int seg;                /* number of segments in beveled edge profile */
+	float pro_super_r;      /* superellipse parameter for edge profile */
 	bool vertex_only;       /* bevel vertices only */
 	bool use_weights;       /* bevel amount affected by weights on edges or verts */
 	bool preserve_widths;	/* should bevel prefer widths over angles, if forced to choose? */
@@ -182,7 +189,7 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float
 		tail->next = ans;
 		vm->boundstart->prev = ans;
 	}
-	ans->profile.flat = true;
+	ans->profile.super_r = PRO_LINE_R;
 	vm->count++;
 	return ans;
 }
@@ -825,13 +832,13 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3],
 /* If there is a bndv->ebev edge, find the mid control point if necessary.
  * It is the closest point on the beveled edge to the line segment between
  * bndv and bndv->next.  */
-static void set_profile_params(BoundVert *bndv)
+static void set_profile_params(BevelParams *bp, BoundVert *bndv)
 {
 	EdgeHalf *e;
 
 	e = bndv->ebev;
 	if (e) {
-		bndv->profile.flat = false;
+		bndv->profile.super_r = bp->pro_super_r;
 		project_to_edge(e->e, bndv->nv.co, bndv->next->nv.co,
 		                bndv->profile.midco);
 	}
@@ -1001,23 +1008,46 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
 /* Find the point on given profile at parameter u which goes from 0 to 2 as
  * the profile is moved from va to vb. */
 static void get_profile_point(const Profile *pro, const float va[3], const float vb[3], float u, float r_co[3])
- {
-	float p[3], angle;
+{
+	float p[3], vo[3], angle, r, w;
 	float m[4][4];
 
 	if (u <= 0.0f)
 		copy_v3_v3(r_co, va);
 	else if (u >= 2.0f)
 		copy_v3_v3(r_co, vb);
-	else if (pro->flat || !make_unit_square_map(va, pro->midco, vb, m)) {
-		interp_v3_v3v3(r_co, va, vb, u / 2.0f);
-	}
 	else {
-		angle = u * (float)M_PI / 4.0f;  /* angle from y axis */
-		p[0] = sinf(angle);
-		p[1] = cosf(angle);
-		p[2] = 0.0f;
-		mul_v3_m4v3(r_co, m, p);
+		r = pro->super_r;
+		if (r == 1.0f || !make_unit_square_map(va, pro->midco, vb, m)) {
+			interp_v3_v3v3(r_co, va, vb, u / 2.0f);
+		}
+		else if (r == PRO_SQUARE_IN_R) {
+			/* square inward concave */
+			zero_v3(p);
+			mul_v3_m4v3(vo, m, p);
+			if (u <= 1.0f)
+				interp_v3_v3v3(r_co, va, vo, u);
+			else
+				interp_v3_v3v3(r_co, vo, vb, u - 1.0f);
+		}
+		else if (r >= PRO_SQUARE_R) {
+			/* square outward convex */
+			if (u <= 1.0f)
+				interp_v3_v3v3(r_co, va, pro->midco, u);
+			else
+				interp_v3_v3v3(r_co, pro->midco, vb, u - 1.0f);
+        }
+		else {
+			angle = u * (float)M_PI / 4.0f;  /* angle from y axis */
+			p[0] = sinf(angle);
+			p[1] = cosf(angle);
+			p[2] = 0.0f;
+			if (r != PRO_CIRCLE_R) {
+				w = powf(powf(p[0], r) + pow(p[1], r), -1.0f / r);
+				mul_v2_fl(p, w);
+			}
+			mul_v3_m4v3(r_co, m, p);
+		}
 	}
 }
 
@@ -1065,11 +1095,43 @@ static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[
 }
 #endif
 
-/* Snapping a direction co to a unit radius sphere is just normalizing co.
- * TODO: generalize to superellipsoid */
-static void snap_to_sphere(float co[3])
+/* Snap a direction co to a superellipsoid with parameter super_r */
+static void snap_to_superellipsoid(float co[3], const float super_r)
 {
-	normalize_v3(co);
+	float a, b, c, x, y, z, r, rinv;
+
+	r = super_r;
+	if (r == PRO_CIRCLE_R) {
+		normalize_v3(co);
+		return;
+	}
+
+	x = a = max_ff(0.0f, co[0]);
+	y = b = max_ff(0.0f, co[1]);
+	z = c = max_ff(0.0f, co[2]);
+	if (r <= 0.0f)
+		r = 0.1f;
+	rinv = 1.0f / r;
+	if (a == 0.0f) {
+		if (b == 0.0f) {
+			x = 0.0f;
+			y = 0.0f;
+			z = powf(c, rinv);
+		}
+		else {
+			x = 0.0f;
+			y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
+			z = c * y / b;
+		}
+	}
+	else {
+		x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
+		y = b * x / a;
+		z = c * x / a;
+	}
+	co[0] = x;
+	co[1] = y;
+	co[2] = z;
 }
 
 static void snap_to_profile(BoundVert *bndv, EdgeHalf *e, float co[3])
@@ -1087,14 +1149,14 @@ static void snap_to_profile(BoundVert *bndv, EdgeHalf *e, float co[3])
 	closest_to_plane_v3(vb0, plane, vb);
 	closest_to_plane_v3(vmid0, plane, bndv->profile.midco);
 	if (make_unit_square_map(va0, vmid0, vb0, m)) {
-		/* Transform co and project it onto sphere */
+		/* Transform co and project it onto superellipse */
 		if (!invert_m4_m4(minv, m)) {
 			/* shouldn't happen */
 			BLI_assert(!"failed inverse during profile snap");
 			return;
 		}
 		mul_v3_m4v3(p, minv, co);
-		snap_to_sphere(p);
+		snap_to_superellipsoid(p, bndv->profile.super_r);
 		mul_v3_m4v3(snap, m, p);
 		copy_v3_v3(co, snap);
 	}
@@ -1207,7 +1269,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
 		else {
 			adjust_bound_vert(e->next->leftv, co);
 		}
-		set_profile_params(vm->boundstart);
+		set_profile_params(bp, vm->boundstart);
 		return;
 	}
 
@@ -1311,7 +1373,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
 
 	v = vm->boundstart;
 	do {
-		set_profile_params(v);
+		set_profile_params(bp, v);
 	} while ((v = v->next) != vm->boundstart);
 
 	if (bv->selcount == 1 && bv->edgecount == 3) {
@@ -2247,12 +2309,44 @@ static VMesh *cubic_subdiv(MemArena *mem_arena, 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)
+{
+	VMesh *vm;
+	float co[3];
+	int i, j, k, ns2;
+
+    ns2 = nseg / 2;
+	vm = new_adj_subdiv_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);
+	}
+	for (i = 0; i < 3; i++) {
+		for (j = 0; j <= ns2; j++) {
+			for (k = 0; k <= ns2; k++) {
+				if (!is_canon(vm, i, j, k))
+					continue;
+				co[i] = 1.0f;
+				co[(i + 1) % 3] = (float) k * 2.0 / (float) nseg;
+				co[(i + 2) % 3] = (float) j * 2.0 / (float) nseg;
+				copy_v3_v3(mesh_vert(vm, i, j, k)->co, co);
+			}
+		}
+	}
+	vmesh_copy_equiv_verts(vm);
+	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
  * on the faces for the orthogonal planes through the origin.
  */
-static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg)
+static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg, float r)
 {
 	VMesh *vm0, *vm1;
 	BoundVert *bndv;
@@ -2260,6 +2354,9 @@ static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg)
 	float co[3], coa[3], cob[3], coc[3];
 	float w;
 
+	if (r == PRO_SQUARE_R)
+		return make_cube_corner_straight(mem_arena, nseg);
+
 	/* initial mesh has 3 sides, 2 segments */
 	vm0 = new_adj_subdiv_vmesh(mem_arena, 3, 2, NULL);
 	vm0->count = 0;  // reset, so following loop will end up with correct count
@@ -2276,6 +2373,7 @@ static VMesh *make_cube_corner_adj_vmesh(MemArena *mem_arena, int nseg)
 		coc[i] = 1.0f;
 		coc[(i + 1) % 3] = 1.0f;
 		coc[(i + 2) % 3] = 0.0f;
+		bndv->profile.super_r = r;
 		copy_v

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list