[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