Bevel Fix for nonplanar faces / reflex angles

When beveling two adjacent edges, code used face normal instead
of the face-corner normal (these can be different for nonplanar
faces); the bevel may look uneven in such cases.
Switched to using corner normal, and needed to fix the case
where the edges meet at a reflex angle. Fixed a similar case
when beveling two edges with one non-beveled in between.
Also removed unnecessary argument from offset_meet.
This commit is contained in:
Howard Trickey 2013-11-20 07:10:35 -05:00
parent 25560a3734
commit 1158c1f7c0

@ -468,14 +468,12 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3])
* Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco.
* e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of
* the bevel vertex, e1 precedes e2 in CCW order.
* If on_right is true, offset edge is on right of both edges, where e1 enters v and
* e2 leave it. If on_right is false, then the offset edge is on the left.
* Offset edge is on right of both edges, where e1 enters v and e2 leave it.
* When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2),
* but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may
* lead to different offsets) then meeting point can be found be intersecting offset lines.
*/
static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
int on_right, float meetco[3])
static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float meetco[3])
{
float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3],
off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], ang;
@ -506,16 +504,15 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
slide_dist(e2, v, e2->offset_l, meetco);
}
else {
/* get normal to plane where meet point should be */
/* Get normal to plane where meet point should be,
* using cross product instead of f->no in case f is non-planar.
* If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip*/
cross_v3_v3v3(norm_v, dir2, dir1);
normalize_v3(norm_v);
if (!on_right)
if (dot_v3v3(norm_v, v->no) < 0.0f)
negate_v3(norm_v);
/* get vectors perp to each edge, perp to norm_v, and pointing into face */
if (f) {
copy_v3_v3(norm_v, f->no);
}
cross_v3_v3v3(norm_perp1, dir1, norm_v);
cross_v3_v3v3(norm_perp2, dir2, norm_v);
normalize_v3(norm_perp1);
@ -551,12 +548,12 @@ static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2,
* Prefer the one whose other end hasn't been constructed yet.
* Following will choose to change e2 if both have already been constructed. */
if (find_other_end_edge_half(bp, e1)) {
offset_meet(e1, emid, v, e1->fnext, TRUE, meetco);
offset_meet(e1, emid, v, e1->fnext, meetco);
/* now e2's left offset is probably different */
e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
}
else {
offset_meet(emid, e2, v, emid->fnext, TRUE, meetco);
offset_meet(emid, e2, v, emid->fnext, meetco);
/* now e1's right offset is probably different */
e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
}
@ -585,6 +582,14 @@ static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, Ed
/* calculate face normals at corner in case faces are nonplanar */
cross_v3_v3v3(f1no, dirmid, dir1);
cross_v3_v3v3(f2no, dirmid, dir2);
/* if e1-v-emid or emid-v-e2 are reflex angles, need to flip corner normals */
if (dot_v3v3(f1no, v->no) < 0.0f)
negate_v3(f1no);
if (dot_v3v3(f2no, v->no) < 0.0f)
negate_v3(f2no);
/* get vectors perpendicular to e1 and e2, pointing into the proper faces */
cross_v3_v3v3(norm_perp1, dir1, f1no);
normalize_v3(norm_perp1);
cross_v3_v3v3(norm_perp2, dir2, f2no);
@ -874,7 +879,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
/* handle only left side of beveled edge e here: next iteration should do right side */
if (e->prev->is_bev) {
BLI_assert(e->prev != e); /* see: wire edge special case */
offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co);
offset_meet(e->prev, e, bv->v, e->fprev, co);
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = v->ebev = e;
@ -899,7 +904,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
}
else {
/* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */
offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co);
offset_meet(e->prev, e, bv->v, e->fprev, co);
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = v->ebev = e;
@ -917,7 +922,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
}
else if (e->prev->is_bev) {
/* on-edge meet between e->prev and e */
offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co);
offset_meet(e->prev, e, bv->v, e->fprev, co);
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev;
v->elast = e;