add length average option to 'Follow Active Quads' unwrap, gives nicer results.

This commit is contained in:
Campbell Barton 2013-01-04 07:57:33 +00:00
parent 6fabbcb4dd
commit ab913fe15d
2 changed files with 72 additions and 9 deletions

@ -26,6 +26,7 @@ from bpy.types import Operator
def extend(obj, operator, EXTEND_MODE): def extend(obj, operator, EXTEND_MODE):
import bmesh import bmesh
me = obj.data me = obj.data
# script will fail without UVs # script will fail without UVs
@ -46,12 +47,12 @@ def extend(obj, operator, EXTEND_MODE):
faces = [f for f in bm.faces if f.select and len(f.verts) == 4] faces = [f for f in bm.faces if f.select and len(f.verts) == 4]
for f in faces:
f.tag = False
f_act.tag = True
# our own local walker # our own local walker
def walk_face_init(faces, f_act):
for f in faces:
f.tag = False
f_act.tag = True
def walk_face(f): def walk_face(f):
# all faces in this list must be tagged # all faces in this list must be tagged
f.tag = True f.tag = True
@ -73,6 +74,30 @@ def extend(obj, operator, EXTEND_MODE):
faces_a, faces_b = faces_b, faces_a faces_a, faces_b = faces_b, faces_a
faces_b.clear() faces_b.clear()
def walk_edgeloop(l):
"""
Could make this a generic function
"""
e_first = l.edge
e = None
while True:
e = l.edge
yield e
# don't step past non-manifold edges
if e.is_manifold:
# welk around the quad and then onto the next face
l = l.link_loop_radial_next
if len(l.face.verts) == 4:
l = l.link_loop_next.link_loop_next
if l.edge is e_first:
break
else:
break
else:
break
def extrapolate_uv(fac, def extrapolate_uv(fac,
l_a_outer, l_a_inner, l_a_outer, l_a_inner,
l_b_outer, l_b_inner): l_b_outer, l_b_inner):
@ -119,7 +144,9 @@ def extend(obj, operator, EXTEND_MODE):
l_a_uv = [l[uv_act].uv for l in l_a] l_a_uv = [l[uv_act].uv for l in l_a]
l_b_uv = [l[uv_act].uv for l in l_b] l_b_uv = [l[uv_act].uv for l in l_b]
if EXTEND_MODE == 'LENGTH': if EXTEND_MODE == 'LENGTH_AVERAGE':
fac = edge_lengths[l_b[2].edge.index][0] / edge_lengths[l_a[1].edge.index][0]
elif EXTEND_MODE == 'LENGTH':
a0, b0, c0 = l_a[3].vert.co, l_a[0].vert.co, l_b[3].vert.co a0, b0, c0 = l_a[3].vert.co, l_a[0].vert.co, l_b[3].vert.co
a1, b1, c1 = l_a[2].vert.co, l_a[1].vert.co, l_b[2].vert.co a1, b1, c1 = l_a[2].vert.co, l_a[1].vert.co, l_b[2].vert.co
@ -140,6 +167,40 @@ def extend(obj, operator, EXTEND_MODE):
l_a_uv[2], l_a_uv[1], l_a_uv[2], l_a_uv[1],
l_b_uv[2], l_b_uv[1]) l_b_uv[2], l_b_uv[1])
# -------------------------------------------
# Calculate average length per loop if needed
if EXTEND_MODE == 'LENGTH_AVERAGE':
bm.edges.index_update()
edge_lengths = [None] * len(bm.edges)
for f in faces:
# we know its a quad
l_quad = f.loops[:]
l_pair_a = (l_quad[0], l_quad[2])
l_pair_b = (l_quad[1], l_quad[3])
for l_pair in (l_pair_a, l_pair_b):
if edge_lengths[l_pair[0].edge.index] is None:
edge_length_store = [-1.0]
edge_length_accum = 0.0
edge_length_total = 0
for l in l_pair:
if edge_lengths[l.edge.index] is None:
for e in walk_edgeloop(l):
if edge_lengths[e.index] is None:
edge_lengths[e.index] = edge_length_store
edge_length_accum += e.calc_length()
edge_length_total += 1
edge_length_store[0] = edge_length_accum / edge_length_total
# done with average length
# ------------------------
walk_face_init(faces, f_act)
for f_triple in walk_face(f_act): for f_triple in walk_face(f_act):
apply_uv(*f_triple) apply_uv(*f_triple)
@ -162,8 +223,10 @@ class FollowActiveQuads(Operator):
name="Edge Length Mode", name="Edge Length Mode",
description="Method to space UV edge loops", description="Method to space UV edge loops",
items=(('EVEN', "Even", "Space all UVs evenly"), items=(('EVEN', "Even", "Space all UVs evenly"),
('LENGTH', "Length", "Average space UVs edge length of each loop")), ('LENGTH', "Length", "Average space UVs edge length of each loop"),
default='LENGTH', ('LENGTH_AVERAGE', "Length Average", "Average space UVs edge length of each loop"),
),
default='LENGTH_AVERAGE',
) )
@classmethod @classmethod

@ -188,7 +188,7 @@ static bool buildNavMesh(const RecastData *recastParams, int nverts, float *vert
/* zero dimensions cause zero alloc later on [#33758] */ /* zero dimensions cause zero alloc later on [#33758] */
if (width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {
BKE_report(reports, RPT_ERROR, "Object has no volume"); BKE_report(reports, RPT_ERROR, "Object has a width or height of zero");
return false; return false;
} }