Added options for how bevel amount is measured.
Now there is an 'Offset Type' dropdown on tool shelf with types: Offset - current method, offset of new edge from old along sliding face Width - width of new bevel face (if segments=1) Depth - amount a chamfering plane moves down from original edge Percent - percent of way sliding edges move along their adjacent edges The different options mainly are useful when beveling more than one edge at once. Leaving as a TODO to put these in the modifier, as doing that has more permanent effects so want to let users shake out problems with this first.
This commit is contained in:
@@ -1557,6 +1557,7 @@ static BMOpDefine bmo_bevel_def = {
|
||||
/* slots_in */
|
||||
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */
|
||||
{"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 */
|
||||
{"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
|
||||
{{'\0'}},
|
||||
|
@@ -117,6 +117,14 @@ enum {
|
||||
BMOP_POKE_BOUNDS
|
||||
};
|
||||
|
||||
/* Bevel offset_type slot values */
|
||||
enum {
|
||||
BEVEL_AMT_OFFSET,
|
||||
BEVEL_AMT_WIDTH,
|
||||
BEVEL_AMT_DEPTH,
|
||||
BEVEL_AMT_PERCENT
|
||||
};
|
||||
|
||||
extern const BMOpDefine *bmo_opdefines[];
|
||||
extern const int bmo_opdefines_total;
|
||||
|
||||
|
@@ -35,9 +35,10 @@
|
||||
|
||||
void bmo_bevel_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
const float offset = BMO_slot_float_get(op->slots_in, "offset");
|
||||
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 offset = BMO_slot_float_get(op->slots_in, "offset");
|
||||
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");
|
||||
|
||||
if (offset > 0) {
|
||||
BMOIter siter;
|
||||
@@ -58,7 +59,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
BM_mesh_bevel(bm, offset, seg, vonly, false, false, NULL, -1);
|
||||
BM_mesh_bevel(bm, offset, offset_type, seg, vonly, false, false, NULL, -1);
|
||||
|
||||
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
|
||||
}
|
||||
|
@@ -73,7 +73,8 @@ typedef struct EdgeHalf {
|
||||
struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */
|
||||
struct BoundVert *rightv; /* right boundary vert, if beveled */
|
||||
int seg; /* how many segments for the bevel */
|
||||
float offset; /* offset for this edge */
|
||||
float offset_l; /* offset for this edge, on left side */
|
||||
float offset_r; /* offset for this edge, on right side */
|
||||
bool is_bev; /* is this edge beveled? */
|
||||
bool is_rev; /* is e->v2 the vertex at this end? */
|
||||
bool is_seam; /* is e a seam for custom loopdata (e.g., UVs)? */
|
||||
@@ -128,6 +129,7 @@ typedef struct BevelParams {
|
||||
MemArena *mem_arena; /* use for all allocs while bevel runs, if we need to free we can switch to mempool */
|
||||
|
||||
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 */
|
||||
bool vertex_only; /* bevel vertices only */
|
||||
bool use_weights; /* bevel amount affected by weights on edges or verts */
|
||||
@@ -469,7 +471,7 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
|
||||
if (ang < 100.0f * BEVEL_EPSILON) {
|
||||
/* special case: e1 and e2 are parallel; put offset point perp to both, from v.
|
||||
* need to find a suitable plane.
|
||||
* if offsets are different, we're out of luck: just use e1->offset */
|
||||
* if offsets are different, we're out of luck: just use e1->offset_r */
|
||||
if (f)
|
||||
copy_v3_v3(norm_v, f->no);
|
||||
else
|
||||
@@ -477,14 +479,14 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
|
||||
cross_v3_v3v3(norm_perp1, dir1, norm_v);
|
||||
normalize_v3(norm_perp1);
|
||||
copy_v3_v3(off1a, v->co);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
|
||||
copy_v3_v3(meetco, off1a);
|
||||
}
|
||||
else if (fabsf(ang - (float)M_PI) < 100.0f * BEVEL_EPSILON) {
|
||||
/* special case e1 and e2 are antiparallel, so bevel is into
|
||||
* a zero-area face. Just make the offset point on the
|
||||
* common line, at offset distance from v. */
|
||||
slide_dist(e2, v, e2->offset, meetco);
|
||||
slide_dist(e2, v, e2->offset_l, meetco);
|
||||
}
|
||||
else {
|
||||
/* get normal to plane where meet point should be */
|
||||
@@ -504,10 +506,10 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
|
||||
|
||||
/* get points that are offset distances from each line, then another point on each line */
|
||||
copy_v3_v3(off1a, v->co);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
|
||||
add_v3_v3v3(off1b, off1a, dir1);
|
||||
copy_v3_v3(off2a, v->co);
|
||||
madd_v3_v3fl(off2a, norm_perp2, e2->offset);
|
||||
madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
|
||||
add_v3_v3v3(off2b, off2a, dir2);
|
||||
|
||||
/* intersect the lines; by construction they should be on the same plane and not parallel */
|
||||
@@ -552,10 +554,10 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
|
||||
|
||||
/* get points that are offset distances from each line, then another point on each line */
|
||||
copy_v3_v3(off1a, v->co);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset);
|
||||
madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
|
||||
sub_v3_v3v3(off1b, off1a, dir1);
|
||||
copy_v3_v3(off2a, v->co);
|
||||
madd_v3_v3fl(off2a, norm_perp2, e2->offset);
|
||||
madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
|
||||
add_v3_v3v3(off2b, off2a, dir2);
|
||||
|
||||
ang = angle_v3v3(dir1, dir2);
|
||||
@@ -564,7 +566,7 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
|
||||
copy_v3_v3(meetco, off1a);
|
||||
}
|
||||
else if (fabsf(ang - (float)M_PI) < 100.0f * BEVEL_EPSILON) {
|
||||
slide_dist(e2, v, e2->offset, meetco);
|
||||
slide_dist(e2, v, e2->offset_l, meetco);
|
||||
}
|
||||
else {
|
||||
iret = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
|
||||
@@ -612,7 +614,7 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, floa
|
||||
cross_v3_v3v3(fdir, no, dir);
|
||||
normalize_v3(fdir);
|
||||
copy_v3_v3(r, v->co);
|
||||
madd_v3_v3fl(r, fdir, e->offset);
|
||||
madd_v3_v3fl(r, fdir, left? e->offset_l : e->offset_r);
|
||||
}
|
||||
|
||||
/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */
|
||||
@@ -818,7 +820,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
|
||||
v->efirst = v->elast = e;
|
||||
e->rightv = v;
|
||||
/* make artifical extra point along unbeveled edge, and form triangle */
|
||||
slide_dist(e->next, bv->v, e->offset, co);
|
||||
slide_dist(e->next, bv->v, e->offset_l, co);
|
||||
v = add_new_bound_vert(mem_arena, vm, co);
|
||||
v->efirst = v->elast = e->next;
|
||||
e->next->leftv = e->next->rightv = v;
|
||||
@@ -828,7 +830,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
|
||||
return;
|
||||
}
|
||||
|
||||
lastd = bp->vertex_only ? bv->offset : e->offset;
|
||||
lastd = bp->vertex_only ? bv->offset : e->offset_l;
|
||||
vm->boundstart = NULL;
|
||||
do {
|
||||
if (e->is_bev) {
|
||||
@@ -1921,6 +1923,18 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the angle between the two faces adjacent to e.
|
||||
* If there are not two, return 0. */
|
||||
static float edge_face_angle(EdgeHalf *e) {
|
||||
if (e->fprev && e->fnext) {
|
||||
/* angle between faces is supplement of angle between face normals */
|
||||
return (float)M_PI - angle_normalized_v3v3(e->fprev->no, e->fnext->no);
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* take care, this flag isn't cleared before use, it just so happens that its not set */
|
||||
#define BM_BEVEL_EDGE_TAG_ENABLE(bme) BM_ELEM_API_FLAG_ENABLE( (bme), _FLAG_OVERLAP)
|
||||
#define BM_BEVEL_EDGE_TAG_DISABLE(bme) BM_ELEM_API_FLAG_DISABLE( (bme), _FLAG_OVERLAP)
|
||||
@@ -1937,7 +1951,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
|
||||
BMFace *f;
|
||||
BMIter iter, iter2;
|
||||
EdgeHalf *e;
|
||||
float weight;
|
||||
float weight, z;
|
||||
int i, found_shared_face, ccw_test_sum;
|
||||
int nsel = 0;
|
||||
int ntot = 0;
|
||||
@@ -2053,16 +2067,6 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
|
||||
e->seg = 0;
|
||||
}
|
||||
e->is_rev = (bme->v2 == v);
|
||||
if (e->is_bev) {
|
||||
e->offset = bp->offset;
|
||||
if (bp->use_weights) {
|
||||
weight = BM_elem_float_data_get(&bm->edata, bme, CD_BWEIGHT);
|
||||
e->offset *= weight;
|
||||
}
|
||||
}
|
||||
else {
|
||||
e->offset = 0.0f;
|
||||
}
|
||||
}
|
||||
/* find wrap-around shared face */
|
||||
BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) {
|
||||
@@ -2098,6 +2102,50 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
|
||||
for (i = 0, e = bv->edges; i < ntot; i++, e++) {
|
||||
e->next = &bv->edges[(i + 1) % ntot];
|
||||
e->prev = &bv->edges[(i + ntot - 1) % ntot];
|
||||
|
||||
/* set offsets */
|
||||
if (e->is_bev) {
|
||||
/* Convert distance as specified by user into offsets along
|
||||
* faces on left side and right side of this edgehalf.
|
||||
* Except for percent method, offset will be same on each side. */
|
||||
switch (bp->offset_type) {
|
||||
case BEVEL_AMT_OFFSET:
|
||||
e->offset_l = bp->offset;
|
||||
break;
|
||||
case BEVEL_AMT_WIDTH:
|
||||
z = fabs(2.0f * sinf(edge_face_angle(e) / 2.0f));
|
||||
if (z < BEVEL_EPSILON)
|
||||
e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
|
||||
else
|
||||
e->offset_l = bp->offset / z;
|
||||
break;
|
||||
case BEVEL_AMT_DEPTH:
|
||||
z = fabs(cosf(edge_face_angle(e) / 2.0f));
|
||||
if (z < BEVEL_EPSILON)
|
||||
e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
|
||||
else
|
||||
e->offset_l = bp->offset / z;
|
||||
break;
|
||||
case BEVEL_AMT_PERCENT:
|
||||
e->offset_l = BM_edge_calc_length(e->prev->e) * bp->offset / 100.0f;
|
||||
e->offset_r = BM_edge_calc_length(e->next->e) * bp->offset / 100.0f;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(!"bad bevel offset kind");
|
||||
e->offset_l = bp->offset;
|
||||
}
|
||||
if (bp->offset_type != BEVEL_AMT_PERCENT)
|
||||
e->offset_r = e->offset_l;
|
||||
if (bp->use_weights) {
|
||||
weight = BM_elem_float_data_get(&bm->edata, bme, CD_BWEIGHT);
|
||||
e->offset_l *= weight;
|
||||
e->offset_r *= weight;
|
||||
}
|
||||
}
|
||||
else {
|
||||
e->offset_l = e->offset_r = 0.0f;
|
||||
}
|
||||
|
||||
BM_BEVEL_EDGE_TAG_DISABLE(e->e);
|
||||
if (e->fprev && e->fnext)
|
||||
e->is_seam = !contig_ldata_across_edge(bm, e->e, e->fprev, e->fnext);
|
||||
@@ -2370,7 +2418,7 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
|
||||
*
|
||||
* \warning all tagged edges _must_ be manifold.
|
||||
*/
|
||||
void BM_mesh_bevel(BMesh *bm, const float offset, const float segments,
|
||||
void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments,
|
||||
const bool vertex_only, const bool use_weights, const bool limit_offset,
|
||||
const struct MDeformVert *dvert, const int vertex_group)
|
||||
{
|
||||
@@ -2380,6 +2428,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments,
|
||||
BevelParams bp = {NULL};
|
||||
|
||||
bp.offset = offset;
|
||||
bp.offset_type = offset_type;
|
||||
bp.seg = segments;
|
||||
bp.vertex_only = vertex_only;
|
||||
bp.use_weights = use_weights;
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
struct MDeformVert;
|
||||
|
||||
void BM_mesh_bevel(BMesh *bm, const float offset, const float segments,
|
||||
void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments,
|
||||
const bool vertex_only, const bool use_weights, const bool limit_offset,
|
||||
const struct MDeformVert *dvert, const int vertex_group);
|
||||
|
||||
|
@@ -131,6 +131,7 @@ static bool edbm_bevel_calc(wmOperator *op)
|
||||
BMEditMesh *em = opdata->em;
|
||||
BMOperator bmop;
|
||||
const float offset = RNA_float_get(op->ptr, "offset");
|
||||
const int offset_type = RNA_enum_get(op->ptr, "offset_type");
|
||||
const int segments = RNA_int_get(op->ptr, "segments");
|
||||
const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
|
||||
|
||||
@@ -140,8 +141,8 @@ static bool edbm_bevel_calc(wmOperator *op)
|
||||
}
|
||||
|
||||
EDBM_op_init(em, &bmop, op,
|
||||
"bevel geom=%hev offset=%f segments=%i vertex_only=%b",
|
||||
BM_ELEM_SELECT, offset, segments, vertex_only);
|
||||
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i",
|
||||
BM_ELEM_SELECT, offset, segments, vertex_only, offset_type);
|
||||
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
|
||||
@@ -256,12 +257,14 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
BevelData *opdata = op->customdata;
|
||||
int use_dist = true;
|
||||
bool use_dist = true;
|
||||
bool is_percent = false;
|
||||
float mdiff[2];
|
||||
float factor;
|
||||
|
||||
mdiff[0] = opdata->mcenter[0] - event->mval[0];
|
||||
mdiff[1] = opdata->mcenter[1] - event->mval[1];
|
||||
is_percent = (RNA_int_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
|
||||
|
||||
if (use_dist) {
|
||||
factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
|
||||
@@ -286,7 +289,13 @@ static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
|
||||
if (factor < 0.0f) factor = 0.0f;
|
||||
}
|
||||
else {
|
||||
CLAMP(factor, 0.0f, 1.0f);
|
||||
if (is_percent) {
|
||||
factor *= 100.0f;
|
||||
CLAMP(factor, 0.0f, 100.0f);
|
||||
}
|
||||
else {
|
||||
CLAMP(factor, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return factor;
|
||||
@@ -361,6 +370,14 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
|
||||
void MESH_OT_bevel(wmOperatorType *ot)
|
||||
{
|
||||
static EnumPropertyItem offset_type_items[] = {
|
||||
{BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"},
|
||||
{BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"},
|
||||
{BEVEL_AMT_DEPTH, "DEPTH", 0, "Depth", "Amount is perpendicular distance from original edge to bevel face"},
|
||||
{BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Bevel";
|
||||
ot->description = "Edge Bevel";
|
||||
@@ -376,7 +393,8 @@ void MESH_OT_bevel(wmOperatorType *ot)
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
|
||||
|
||||
RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Offset", "", 0.0f, 1.0f);
|
||||
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
|
||||
RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
|
||||
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
|
||||
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices");
|
||||
}
|
||||
|
@@ -158,7 +158,8 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
|
||||
}
|
||||
}
|
||||
|
||||
BM_mesh_bevel(bm, bmd->value, bmd->res,
|
||||
/* TODO: add offset_kind to modifier properties to, and pass in as 3rd arg here */
|
||||
BM_mesh_bevel(bm, bmd->value, 0, bmd->res,
|
||||
vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
|
||||
dvert, vgroup);
|
||||
|
||||
|
Reference in New Issue
Block a user