Created
March 20, 2016 02:16
-
-
Save nutti/7c09e13954cb10ee89af to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
import bmesh | |
from mathutils import Vector | |
from math import fabs | |
from collections import defaultdict | |
bpy.ops.mesh.select_all(action='SELECT') | |
bpy.context.scene.tool_settings.uv_select_mode = 'ISLAND' | |
obj = bpy.context.active_object | |
bm = bmesh.from_edit_mesh(obj.data) | |
uv_layer = bm.loops.layers.uv.verify() | |
island_info = [] | |
uv_island_lists = [] | |
# get all UV islands | |
def get_island_1(bm, uv_layer): | |
uv_island_lists = [] | |
while True: | |
bpy.ops.uv.select(extend = False, location = (0,0)) | |
selected_uvs = [] | |
for f in bm.faces: | |
if f.select: | |
for l in f.loops: | |
if l[uv_layer].select: | |
selected_uvs.append({'uv': l[uv_layer].uv, 'loop_idx': l.index}) | |
l[uv_layer].select = False | |
if len(selected_uvs) == 0: | |
break | |
uv_island_lists.append(selected_uvs) | |
bpy.ops.uv.hide() | |
return uv_island_lists | |
face_to_verts = defaultdict(set) | |
vert_to_faces = defaultdict(set) | |
current_island = [] | |
for f in bm.faces: | |
for l in f.loops: | |
id = l[uv_layer].uv.to_tuple(5), l.vert.index | |
face_to_verts[f.index].add(id) | |
vert_to_faces[id].add(f.index) | |
def get_island_2(bm, uv_layer): | |
global face_to_verts | |
global vert_to_faces | |
global current_island | |
def parse_island(bm, face_idx, faces_left): | |
global face_to_verts | |
global vert_to_faces | |
global current_island | |
if face_idx in faces_left: | |
faces_left.remove(face_idx) | |
current_face = {'face_idx': face_idx, 'loops': []} | |
for l in bm.faces[face_idx].loops: | |
current_face['loops'].append({'uv': l[uv_layer].uv, 'loop_idx': l.index}) | |
current_island.append(current_face) | |
for v in face_to_verts[face_idx]: | |
connected_faces = vert_to_faces[v] | |
if connected_faces: | |
for cf in connected_faces: | |
parse_island(bm, cf, faces_left) | |
uv_island_lists = [] | |
faces_left = set(face_to_verts.keys()) | |
while len(faces_left) > 0: | |
current_island = [] | |
face_idx = list(faces_left)[0] | |
parse_island(bm, face_idx, faces_left) | |
#print(len(current_island)) | |
uv_island_lists.append(current_island) | |
return uv_island_lists | |
uv_island_lists = get_island_2(bm, uv_layer) | |
#print(len(uv_island_lists)) | |
# get information about each island | |
for island in uv_island_lists: | |
info = {} | |
max = Vector((-10000000.0, -10000000.0)) | |
min = Vector((10000000.0, 10000000.0)) | |
ave = Vector((0.0, 0.0)) | |
num = 0 | |
for face in island: | |
for l in face['loops']: | |
uv = l['uv'] | |
if uv.x > max.x: | |
max.x = uv.x | |
if uv.y > max.y: | |
max.y = uv.y | |
if uv.x < min.x: | |
min.x = uv.x | |
if uv.y < min.y: | |
min.y = uv.y | |
ave = ave + uv | |
num = num + 1 | |
ave = ave / num | |
info['center'] = ave | |
info['size'] = max - min | |
info['num_uv'] = num | |
info['group'] = -1 | |
info['faces'] = island | |
island_info.append(info) | |
# check if there is same island | |
num_group = 0 | |
while True: | |
for isl in island_info: | |
if isl['group'] == -1: | |
break | |
else: | |
break | |
isl['group'] = num_group | |
for isl_2 in island_info: | |
if isl_2['group'] == -1: | |
center_matched = (fabs(isl_2['center'].x - isl['center'].x) < 0.001) and (fabs(isl_2['center'].y - isl['center'].y) < 0.001) | |
size_matched = (fabs(isl_2['size'].x - isl['size'].x) < 0.001) and (fabs(isl_2['size'].y - isl['size'].y) < 0.001) | |
num_uv_matched = (isl_2['num_uv'] == isl['num_uv']) | |
if center_matched and size_matched and num_uv_matched: | |
isl_2['group'] = num_group | |
# find two same UV pair for transfering UV | |
face_pair_1 = isl['faces'][0:2] | |
face_pair_2 = [] | |
face_sorted_1 = isl['faces'] | |
face_sorted_2 = [] | |
for f1 in face_sorted_1: | |
for f2 in isl_2['faces']: | |
if len(f1['loops']) != len(f2['loops']): | |
continue | |
matched = True | |
for l1, l2 in zip(f1['loops'], f2['loops']): | |
if (fabs(l1['uv'].x - l2['uv'].x) > 0.001) or (fabs(l1['uv'].y - l2['uv'].y) > 0.001): | |
matched = False | |
if not matched: | |
continue | |
face_sorted_2.append(f2) | |
break | |
else: | |
print('error') | |
isl['sorted'] = face_sorted_1 | |
isl_2['sorted'] = face_sorted_2 | |
num_group = num_group + 1 | |
loop_lists = [l for f in bm.faces for l in f.loops] | |
bpy.ops.mesh.select_all(action='DESELECT') | |
# pack UV | |
for gidx in range(num_group): | |
group = list(filter(lambda i:i['group']==gidx, island_info)) | |
for f in group[0]['faces']: | |
bm.faces[f['face_idx']].select = True | |
bmesh.update_edit_mesh(obj.data) | |
bpy.ops.uv.select_all(action='SELECT') | |
bpy.ops.uv.pack_islands(margin=0.272269) | |
# copy/paste UV among same island | |
for gidx in range(num_group): | |
group = list(filter(lambda i:i['group']==gidx, island_info)) | |
if len(group) <= 1: | |
continue | |
for g in group[1:]: | |
for (src_face, dest_face) in zip(group[0]['sorted'], g['sorted']): | |
for (src_loop, dest_loop) in zip(src_face['loops'], dest_face['loops']): | |
loop_lists[dest_loop['loop_idx']][uv_layer].uv = loop_lists[src_loop['loop_idx']][uv_layer].uv | |
bmesh.update_edit_mesh(obj.data) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment