Skip to content

Instantly share code, notes, and snippets.

@nutti
Created March 20, 2016 02:16
Show Gist options
  • Save nutti/7c09e13954cb10ee89af to your computer and use it in GitHub Desktop.
Save nutti/7c09e13954cb10ee89af to your computer and use it in GitHub Desktop.
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