Merge pull request #19 from franMarz/Align-World-not-aligning-#5-franMarz-patch

World Align fix, Thx franMarz, for this fix..
master TexTools_2.8x
SavMartin 4 years ago committed by GitHub
commit 7dcaafa6aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,6 +19,10 @@ class op(bpy.types.Operator):
bl_description = "Align selected UV islands to world / gravity directions" bl_description = "Align selected UV islands to world / gravity directions"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bool_face = bpy.props.BoolProperty(name="Per face", default=False, description="Use if every face is an island in uv space; this speeds up the script dramatically.")
bool_simple = bpy.props.BoolProperty(name="Simple align", default=False, description="Only process one edge per island, enough for nearly undistorted uvs.")
steps = bpy.props.IntProperty(name="Iterations", min=1, max=100, soft_min=1, soft_max=5, default=1, description="Using multiple steps (up to 5, usually 2 or 3) is useful in certain cases, especially uv hulls with high localized distortion.")
# is_global = bpy.props.BoolProperty( # is_global = bpy.props.BoolProperty(
# name = "Global Axis", # name = "Global Axis",
# description = "Global or local object axis alignment", # description = "Global or local object axis alignment",
@ -51,14 +55,16 @@ class op(bpy.types.Operator):
return True return True
def execute(self, context): def execute(self, context):
main(self) main(self, context)
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
def main(context): def main(self, context):
print("\n________________________\nis_global") print("\n________________________\nis_global")
#Store selection #Store selection
@ -75,18 +81,20 @@ def main(context):
bm = bmesh.from_edit_mesh(bpy.context.active_object.data); bm = bmesh.from_edit_mesh(bpy.context.active_object.data);
uv_layers = bm.loops.layers.uv.verify(); uv_layers = bm.loops.layers.uv.verify();
islands = utilities_uv.getSelectionIslands() if self.bool_face:
islands = [[f] for f in bm.faces if f.select and f.loops[0][uv_layers].select]
else:
islands = utilities_uv.getSelectionIslands()
for faces in islands: for faces in islands:
# Get average viewport normal of UV island
avg_normal = Vector((0,0,0)) avg_normal = Vector((0,0,0))
for face in faces: if self.bool_face:
avg_normal+=face.normal avg_normal = faces[0].normal
avg_normal/=len(faces) else:
# Get average viewport normal of UV island
# avg_normal = (obj.matrix_world*avg_normal).normalized() for face in faces:
avg_normal+=face.normal
avg_normal/=len(faces)
# Which Side # Which Side
x = 0 x = 0
@ -94,29 +102,32 @@ def main(context):
z = 2 z = 2
max_size = max(abs(avg_normal.x), abs(avg_normal.y), abs(avg_normal.z)) max_size = max(abs(avg_normal.x), abs(avg_normal.y), abs(avg_normal.z))
# Use multiple steps for i in range(self.steps): # Use multiple steps
for i in range(3):
if(abs(avg_normal.x) == max_size): if(abs(avg_normal.x) == max_size):
print("x normal") print("x normal")
align_island(obj, bm, uv_layers, faces, y, z, avg_normal.x < 0, False) if self.bool_simple:
align_island_simple(obj, bm, uv_layers, faces, y, z, avg_normal.x < 0, False)
else:
align_island(obj, bm, uv_layers, faces, y, z, avg_normal.x < 0, False)
elif(abs(avg_normal.y) == max_size): elif(abs(avg_normal.y) == max_size):
print("y normal") print("y normal")
align_island(obj, bm, uv_layers, faces, x, z, avg_normal.y > 0, False) if self.bool_simple:
align_island_simple(obj, bm, uv_layers, faces, x, z, avg_normal.y > 0, False)
else:
align_island(obj, bm, uv_layers, faces, x, z, avg_normal.y > 0, False)
elif(abs(avg_normal.z) == max_size): elif(abs(avg_normal.z) == max_size):
print("z normal") print("z normal")
align_island(obj, bm, uv_layers, faces, x, y, False, avg_normal.z < 0) if self.bool_simple:
align_island_simple(obj, bm, uv_layers, faces, x, z, avg_normal.y > 0, False)
else:
align_island(obj, bm, uv_layers, faces, x, y, False, avg_normal.z < 0)
print("align island: faces {}x n:{}, max:{}".format(len(faces), avg_normal, max_size)) print("align island: faces {}x n:{}, max:{}".format(len(faces), avg_normal, max_size))
#Restore selection #Restore selection
utilities_uv.selection_restore() utilities_uv.selection_restore()
def align_island(obj, bm, uv_layers, faces, x=0, y=1, flip_x=False, flip_y=False): def align_island(obj, bm, uv_layers, faces, x=0, y=1, flip_x=False, flip_y=False):
# Find lowest and highest verts # Find lowest and highest verts
@ -126,166 +137,135 @@ def align_island(obj, bm, uv_layers, faces, x=0, y=1, flip_x=False, flip_y=False
axis_names = ['x', 'y', 'z'] axis_names = ['x', 'y', 'z']
print("Align shell {}x at {},{} flip {},{}".format(len(faces), axis_names[x], axis_names[y], flip_x, flip_y)) print("Align shell {}x at {},{} flip {},{}".format(len(faces), axis_names[x], axis_names[y], flip_x, flip_y))
# print(" Min #{} , Max #{} along '{}'".format(minmax_vert[0].index, minmax_vert[1].index, axis_names[y] )) # print(" Min #{} , Max #{} along '{}'".format(minmax_vert[0].index, minmax_vert[1].index, axis_names[y] ))
# print(" A1 {:.1f} , A2 {:.1f} along ".format(minmax_val[0], minmax_val[1] )) # print(" A1 {:.1f} , A2 {:.1f} along ".format(minmax_val[0], minmax_val[1] ))
# Collect UV to Vert # Collect UV to Vert
vert_to_uv = utilities_uv.get_vert_to_uv(bm, uv_layers) vert_to_uv = {}
uv_to_vert = utilities_uv.get_uv_to_vert(bm, uv_layers) for face in faces:
for loop in face.loops:
vert = loop.vert
uv = loop[uv_layers]
if vert not in vert_to_uv:
vert_to_uv[vert] = [uv];
else:
vert_to_uv[vert].append(uv)
#uv_to_vert = utilities_uv.get_uv_to_vert(bm, uv_layers)
processed_edges = [] processed_edges = []
edges = [] n_edges = 0
avg_angle = 0
for face in faces: for face in faces:
for edge in face.edges: for edge in face.edges:
if edge not in processed_edges: if edge not in processed_edges:
processed_edges.append(edge) processed_edges.append(edge)
delta = edge.verts[0].co -edge.verts[1].co delta = edge.verts[0].co -edge.verts[1].co
max_side = max(abs(delta.x), abs(delta.y), abs(delta.z)) max_side = max(abs(delta.x), abs(delta.y), abs(delta.z))
# Check edges dominant in active axis # Check edges dominant in active axis
if( abs(delta[x]) == max_side or abs(delta[y]) == max_side): if( abs(delta[x]) == max_side or abs(delta[y]) == max_side):
# if( abs(delta[y]) == max_side): n_edges += 1
edges.append(edge) uv0 = vert_to_uv[ edge.verts[0] ][0]
uv1 = vert_to_uv[ edge.verts[1] ][0]
delta_verts = Vector((
edge.verts[1].co[x] - edge.verts[0].co[x],
edge.verts[1].co[y] - edge.verts[0].co[y]
))
if flip_x:
delta_verts.x = -edge.verts[1].co[x] + edge.verts[0].co[x]
if flip_y:
delta_verts.y = -edge.verts[1].co[y] + edge.verts[0].co[y]
delta_uvs = Vector((
uv1.uv.x - uv0.uv.x,
uv1.uv.y - uv0.uv.y
))
print("Edges {}x".format(len(edges))) a0 = math.atan2(delta_verts.y, delta_verts.x) #- math.pi/2
a1 = math.atan2(delta_uvs.y, delta_uvs.x) #- math.pi/2
a_delta = math.atan2(math.sin(a0-a1), math.cos(a0-a1))
# Consolidation (math.atan2 gives the lower angle between -Pi and Pi, this triggers errors when using the average avg_angle /= n_edges for rotation angles close to Pi)
if n_edges > 1:
if abs((avg_angle / (n_edges-1)) - a_delta) > 2.8:
if a_delta > 0:
avg_angle+=(a_delta-math.pi*2)
else:
avg_angle+=(a_delta+math.pi*2)
else:
avg_angle+=a_delta
else:
avg_angle+=a_delta
avg_angle /= n_edges
print("Edges {}x".format(n_edges))
print("Turn {:.1f}".format(avg_angle * 180/math.pi))
bpy.ops.uv.select_all(action='DESELECT')
for face in faces:
for loop in face.loops:
loop[uv_layers].select = True
avg_angle = 0 bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
for edge in edges: bpy.ops.transform.rotate(value=-avg_angle, orient_axis='Z') # minus angle; Blender uses unconventional rotation notation (positive for clockwise)
def align_island_simple(obj, bm, uv_layers, faces, x=0, y=1, flip_x=False, flip_y=False):
# Find lowest and highest verts
minmax_val = [0,0]
minmax_vert = [None, None]
axis_names = ['x', 'y', 'z']
print("Align shell {}x at {},{} flip {},{}".format(len(faces), axis_names[x], axis_names[y], flip_x, flip_y))
# Collect UV to Vert
vert_to_uv = {}
face = faces[0]
for loop in face.loops:
vert = loop.vert
uv = loop[uv_layers]
vert_to_uv[vert] = [uv]
uv.select = True
edge = faces[0].edges[0]
delta = edge.verts[0].co -edge.verts[1].co
max_side = max(abs(delta.x), abs(delta.y), abs(delta.z))
# Check edges dominant in active axis
if abs(delta[x]) == max_side or abs(delta[y]) == max_side :
uv0 = vert_to_uv[ edge.verts[0] ][0] uv0 = vert_to_uv[ edge.verts[0] ][0]
uv1 = vert_to_uv[ edge.verts[1] ][0] uv1 = vert_to_uv[ edge.verts[1] ][0]
delta_verts = Vector(( delta_verts = Vector((
edge.verts[1].co[x] - edge.verts[0].co[x], edge.verts[1].co[x] - edge.verts[0].co[x],
edge.verts[1].co[y] - edge.verts[0].co[y] edge.verts[1].co[y] - edge.verts[0].co[y]
)) ))
if flip_x: if flip_x:
delta_verts.x = -edge.verts[1].co[x] + edge.verts[0].co[x] delta_verts.x = -edge.verts[1].co[x] + edge.verts[0].co[x]
if flip_y: if flip_y:
delta_verts.y = -edge.verts[1].co[y] + edge.verts[0].co[y] delta_verts.y = -edge.verts[1].co[y] + edge.verts[0].co[y]
# delta_verts.y = edge.verts[0].co[y] - edge.verts[1].co[y]
delta_uvs = Vector(( delta_uvs = Vector((
uv1.uv.x - uv0.uv.x, uv1.uv.x - uv0.uv.x,
uv1.uv.y - uv0.uv.y uv1.uv.y - uv0.uv.y
)) ))
a0 = math.atan2(delta_verts.y, delta_verts.x) - math.pi/2
a1 = math.atan2(delta_uvs.y, delta_uvs.x) - math.pi/2
a0 = math.atan2(delta_verts.y, delta_verts.x)
a1 = math.atan2(delta_uvs.y, delta_uvs.x)
a_delta = math.atan2(math.sin(a0-a1), math.cos(a0-a1))
a_delta = math.atan2(math.sin(a0-a1), math.cos(a0-a1))
# edge.verts[0].index, edge.verts[1].index
# print(" turn {:.1f} .. {:.1f} , {:.1f}".format(a_delta*180/math.pi, a0*180/math.pi,a1*180/math.pi))
avg_angle+=a_delta
avg_angle/=len(edges) # - math.pi/2
print("Turn {:.1f}".format(avg_angle * 180/math.pi))
bpy.ops.uv.select_all(action='DESELECT') print("Turn {:.1f}".format(a_delta * 180/math.pi))
for face in faces:
for loop in face.loops:
loop[uv_layers].select = True
bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
bpy.ops.transform.rotate(value=avg_angle, orient_axis='Z')
# bpy.ops.transform.rotate(value=0.58191, axis=(-0, -0, -1), constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False, proportional_edit_falloff='SPHERE', proportional_size=0.0267348)
# processed = []
'''
bpy.ops.uv.select_all(action='DESELECT') bpy.ops.uv.select_all(action='DESELECT')
for face in faces: for face in faces:
# Collect UV to Vert
for loop in face.loops: for loop in face.loops:
loop[uv_layers].select = True loop[uv_layers].select = True
vert = loop.vert
uv = loop[uv_layers] bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
# vert_to_uv bpy.ops.transform.rotate(value=-a_delta, orient_axis='Z') # minus angle; Blender uses unconventional rotation notation (positive for clockwise)
if vert not in vert_to_uv:
vert_to_uv[vert] = [uv];
else:
vert_to_uv[vert].append(uv)
# uv_to_vert
if uv not in uv_to_vert:
uv_to_vert[ uv ] = vert;
for vert in face.verts:
if vert not in processed:
processed.append(vert)
vert_y = (vert.co)[y] #obj.matrix_world *
print("idx {} = {}".format(vert.index, vert_y))
if not minmax_vert[0] or not minmax_vert[1]:
minmax_vert[0] = vert
minmax_vert[1] = vert
minmax_val[0] = vert_y
minmax_val[1] = vert_y
continue
if vert_y < minmax_val[0]:
# Not yet defined or smaller
minmax_vert[0] = vert
minmax_val[0] = vert_y
elif vert_y > minmax_val[1]:
minmax_vert[1] = vert
minmax_val[1] = vert_y
if minmax_vert[0] and minmax_vert[1]:
axis_names = ['x', 'y', 'z']
print(" Min #{} , Max #{} along '{}'".format(minmax_vert[0].index, minmax_vert[1].index, axis_names[y] ))
# print(" A1 {:.1f} , A2 {:.1f} along ".format(minmax_val[0], minmax_val[1] ))
vert_A = minmax_vert[0]
vert_B = minmax_vert[1]
uv_A = vert_to_uv[vert_A][0]
uv_B = vert_to_uv[vert_B][0]
delta_verts = Vector((
vert_B.co[x] - vert_A.co[x],
vert_B.co[y] - vert_A.co[y]
))
delta_uvs = Vector((
uv_B.uv.x - uv_A.uv.x,
uv_B.uv.y - uv_A.uv.y,
))
# Get angles
angle_vert = math.atan2(delta_verts.y, delta_verts.x) - math.pi/2
angle_uv = math.atan2(delta_uvs.y, delta_uvs.x) - math.pi/2
angle_delta = math.atan2(math.sin(angle_vert-angle_uv), math.cos(angle_vert-angle_uv))
print(" Angles {:.2f} | {:.2f}".format(angle_vert*180/math.pi, angle_uv*180/math.pi))
print(" Angle Diff {:.2f}".format(angle_delta*180/math.pi))
bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
bpy.ops.transform.rotate(value=angle_delta, axis='Z')
# bpy.ops.transform.rotate(value=0.58191, axis=(-0, -0, -1), constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False, proportional_edit_falloff='SPHERE', proportional_size=0.0267348)
# bpy.ops.mesh.select_all(action='DESELECT')
# vert_A.select = True
# vert_B.select = True
# return
'''
bpy.utils.register_class(op) bpy.utils.register_class(op)

Loading…
Cancel
Save