Fix bevel profile=1 problems, see T39132, T38458, T40278, T51010,
T53783. Before, profile=1 ("square outside") only worked well in a few cases (some "pipes", cube corners). This makes it work well pretty much everywhere.
This commit is contained in:
parent
f9fcda533b
commit
bd9ed0228b
|
@ -2170,7 +2170,6 @@ static void adjust_offsets(BevelParams *bp)
|
|||
v->visited = true;
|
||||
if (vnext->visited) {
|
||||
if (vnext != vchainstart) {
|
||||
printf("WHOOPS, adjusting offsets, expected cycle!\n");
|
||||
break;
|
||||
}
|
||||
adjust_the_cycle_or_chain(vchainstart, true);
|
||||
|
@ -3187,6 +3186,173 @@ static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh
|
|||
}
|
||||
}
|
||||
|
||||
/* copy whichever of a and b is closer to v into r */
|
||||
static void closer_v3_v3v3v3(float r[3], float a[3], float b[3], float v[3])
|
||||
{
|
||||
if (len_squared_v3v3(a, v) <= len_squared_v3v3(b, v))
|
||||
copy_v3_v3(r, a);
|
||||
else
|
||||
copy_v3_v3(r, b);
|
||||
}
|
||||
|
||||
/* Special case of VMesh when profile == 1 and there are 3 or more beveled edges.
|
||||
* We want the effect of parallel offset lines (n/2 of them) on each side of the center, for even n.
|
||||
* Wherever they intersect with each other between two successive beveled edges, those intersections
|
||||
* are part of the vmesh rings.
|
||||
* We have to move the boundary edges too -- the usual method is to make one profile plane between
|
||||
* successive BoundVerts, but for the effect we want here, there will be two planes, one on each side
|
||||
* of the original edge.
|
||||
*/
|
||||
static VMesh *square_out_adj_vmesh(BevelParams *bp, BevVert *bv)
|
||||
{
|
||||
int n, ns, ns2, odd, i, j, k, ikind, im1, clstride;
|
||||
float bndco[3], dir1[3], dir2[3], co1[3], co2[3], meet1[3], meet2[3], v1co[3], v2co[3];
|
||||
float *on_edge_cur, *on_edge_prev, *p;
|
||||
float ns2inv, finalfrac, ang;
|
||||
BoundVert *bndv;
|
||||
EdgeHalf *e1, *e2;
|
||||
VMesh *vm;
|
||||
float *centerline;
|
||||
|
||||
n = bv->vmesh->count;
|
||||
ns = bv->vmesh->seg;
|
||||
ns2 = ns / 2;
|
||||
odd = ns % 2;
|
||||
ns2inv = 1.0f / (float) ns2;
|
||||
vm = new_adj_vmesh(bp->mem_arena, n, ns, bv->vmesh->boundstart);
|
||||
clstride = 3 * (ns2 + 1);
|
||||
centerline = MEM_mallocN(clstride * n * sizeof(float), "bevel");
|
||||
|
||||
/* find on_edge, place on bndv[i]'s elast where offset line would meet,
|
||||
* averaging with position where next sector's offset line would meet */
|
||||
bndv = vm->boundstart;
|
||||
for (i = 0; i < n; i++) {
|
||||
copy_v3_v3(bndco, bndv->nv.co);
|
||||
e1 = bndv->efirst;
|
||||
e2 = bndv->elast;
|
||||
sub_v3_v3v3(dir1, e1->e->v1->co, e1->e->v2->co);
|
||||
sub_v3_v3v3(dir2, e2->e->v1->co, e2->e->v2->co);
|
||||
add_v3_v3v3(co1, bndco, dir1);
|
||||
add_v3_v3v3(co2, bndco, dir2);
|
||||
/* intersect e1 with line through bndv parallel to e2 to get v1co */
|
||||
ikind = isect_line_line_v3(e1->e->v1->co, e1->e->v2->co, bndco, co2, meet1, meet2);
|
||||
|
||||
if (ikind == 0) {
|
||||
/* Placeholder: this should get eliminated by min dist test with adjacent edge */
|
||||
mid_v3_v3v3(v1co, e1->e->v1->co, e1->e->v2->co);
|
||||
}
|
||||
else {
|
||||
/* if the lines are skew (ikind == 2), want meet1 which is on e1 */
|
||||
copy_v3_v3(v1co, meet1);
|
||||
}
|
||||
/* intersect e2 with line through bndv parallel to e1 to get v2co */
|
||||
ikind = isect_line_line_v3(e2->e->v1->co, e2->e->v2->co, bndco, co1, meet1, meet2);
|
||||
if (ikind == 0) {
|
||||
mid_v3_v3v3(v2co, e2->e->v1->co, e2->e->v2->co);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(v2co, meet1);
|
||||
}
|
||||
|
||||
/* want on_edge[i] to be min dist to bv->v of v2co and the v1co of next iteration */
|
||||
on_edge_cur = centerline + clstride * i;
|
||||
on_edge_prev = centerline + clstride * ((i == 0) ? n - 1 : i - 1);
|
||||
if (i == 0) {
|
||||
copy_v3_v3(on_edge_cur, v2co);
|
||||
copy_v3_v3(on_edge_prev, v1co);
|
||||
}
|
||||
else if (i == n - 1) {
|
||||
closer_v3_v3v3v3(on_edge_cur, on_edge_cur, v2co, bv->v->co);
|
||||
closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(on_edge_cur, v2co);
|
||||
closer_v3_v3v3v3(on_edge_prev, on_edge_prev, v1co, bv->v->co);
|
||||
}
|
||||
bndv = bndv->next;
|
||||
}
|
||||
|
||||
/* fill in rest of centerlines by interpolation */
|
||||
copy_v3_v3(co2, bv->v->co);
|
||||
bndv = vm->boundstart;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (odd) {
|
||||
ang = 0.5f * angle_v3v3v3(bndv->nv.co, co1, bndv->next->nv.co);
|
||||
if (ang > BEVEL_SMALL_ANG) {
|
||||
/* finalfrac is length along arms of isoceles triangle with top angle 2*ang
|
||||
* such that the base of the triangle is 1.
|
||||
* This is used in interpolation along centerline in odd case.
|
||||
* To avoid too big a drop from bv, cap finalfrac a 0.8 arbitrarily */
|
||||
finalfrac = 0.5f / sin(ang);
|
||||
if (finalfrac > 0.8f)
|
||||
finalfrac = 0.8f;
|
||||
}
|
||||
else {
|
||||
finalfrac = 0.8f;
|
||||
}
|
||||
ns2inv = 1.0f / (ns2 + finalfrac);
|
||||
}
|
||||
|
||||
p = centerline + clstride * i;
|
||||
copy_v3_v3(co1, p);
|
||||
p += 3;
|
||||
for (j = 1; j <= ns2; j++) {
|
||||
interp_v3_v3v3(p, co1, co2, j * ns2inv);
|
||||
p += 3;
|
||||
}
|
||||
bndv = bndv->next;
|
||||
}
|
||||
|
||||
/* coords of edges and mid or near-mid line */
|
||||
bndv = vm->boundstart;
|
||||
for (i = 0; i < n; i++) {
|
||||
copy_v3_v3(co1, bndv->nv.co);
|
||||
copy_v3_v3(co2, centerline + clstride * (i == 0 ? n - 1 : i - 1));
|
||||
for (j = 0; j < ns2 + odd; j++) {
|
||||
interp_v3_v3v3(mesh_vert(vm, i, j, 0)->co, co1, co2, j * ns2inv);
|
||||
}
|
||||
copy_v3_v3(co2, centerline + clstride * i);
|
||||
for (k = 1; k <= ns2; k++) {
|
||||
interp_v3_v3v3(mesh_vert(vm, i, 0, k)->co, co1, co2, k * ns2inv);
|
||||
}
|
||||
bndv = bndv->next;
|
||||
}
|
||||
if (!odd)
|
||||
copy_v3_v3(mesh_vert(vm, 0, ns2, ns2)->co, bv->v->co);
|
||||
vmesh_copy_equiv_verts(vm);
|
||||
|
||||
/* fill in interior points by interpolation from edges to centerlines */
|
||||
bndv = vm->boundstart;
|
||||
for (i = 0; i < n; i++) {
|
||||
im1 = (i == 0) ? n - 1 : i - 1;
|
||||
for (j = 1; j < ns2 + odd; j++) {
|
||||
for (k = 1; k <= ns2; k++) {
|
||||
ikind = isect_line_line_v3(
|
||||
mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k,
|
||||
mesh_vert(vm, i, j, 0)->co, centerline + clstride * i + 3 * j,
|
||||
meet1, meet2);
|
||||
if (ikind == 0) {
|
||||
/* how can this happen? fall back on interpolation in one direction if it does */
|
||||
interp_v3_v3v3(mesh_vert(vm, i, j, k)->co,
|
||||
mesh_vert(vm, i, 0, k)->co, centerline + clstride * im1 + 3 * k, j * ns2inv);
|
||||
}
|
||||
else if (ikind == 1) {
|
||||
copy_v3_v3(mesh_vert(vm, i, j, k)->co, meet1);
|
||||
}
|
||||
else {
|
||||
mid_v3_v3v3(mesh_vert(vm, i, j, k)->co, meet1, meet2);
|
||||
}
|
||||
}
|
||||
}
|
||||
bndv = bndv->next;
|
||||
}
|
||||
|
||||
vmesh_copy_equiv_verts(vm);
|
||||
|
||||
MEM_freeN(centerline);
|
||||
return vm;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
|
@ -3209,9 +3375,13 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
|
|||
odd = ns % 2;
|
||||
BLI_assert(n >= 3 && ns > 1);
|
||||
|
||||
|
||||
vpipe = pipe_test(bv);
|
||||
|
||||
if (vpipe) {
|
||||
if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd) {
|
||||
vm1 = square_out_adj_vmesh(bp, bv);
|
||||
}
|
||||
else if (vpipe) {
|
||||
vm1 = pipe_adj_vmesh(bp, bv, vpipe);
|
||||
}
|
||||
else if (tri_corner_test(bp, bv)) {
|
||||
|
|
Loading…
Reference in New Issue