diff --git a/README.md b/README.md index b8a863d..f20a217 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TexTools for Blender # -TexTools is a Free addon for Blender 3D with a set of professional UV and Texture toolsBack in 2009 I released the [Original TexTools](http://renderhjs.net/textools/) for 3dsMax. Current features include: Easy Texture Baking, UV Align and Selection tools and Texel Density tools. +TexTools is a Free addon for Blender 3D with a set of professional UV and Texture tools. Back in 2009 I released the [Original TexTools](http://renderhjs.net/textools/) for 3dsMax. Current features include: Easy Texture Baking, UV Align and Selection tools and Texel Density tools. ## Download & Documentation ## Visit the [Official Website & Documentation](http://renderhjs.net/textools/blender/) for in depth overview of all the tools. Alternatively visit this [release log](http://renderhjs.net/textools/blender/log.html) diff --git a/__init__.py b/__init__.py index f876d58..2df7f97 100644 --- a/__init__.py +++ b/__init__.py @@ -240,7 +240,7 @@ class UV_OT_op_debug(bpy.types.Operator): class UV_OT_op_disable_uv_sync(bpy.types.Operator): - bl_idname = "uv.op_disable_sync" + bl_idname = "uv.op_disable_uv_sync" bl_label = "Disable Sync" bl_description = "Disable UV sync mode" @@ -1458,11 +1458,6 @@ def register(): - -def unregister(): - #GUI Utilities - # utilities_ui.unregister() - from bpy.utils import unregister_class for cls in reversed(classes): unregister_class(cls) @@ -1470,7 +1465,6 @@ def unregister(): #Unregister Icons utilities_ui.icon_unregister() - #Unregister Settings del bpy.types.Scene.texToolsSettings @@ -1479,6 +1473,9 @@ def unregister(): km.keymap_items.remove(kmi) keymaps.clear() + #GUI Utilities + utilities_ui.unregister() + bpy.types.IMAGE_MT_uvs.remove(menu_IMAGE_uvs) bpy.types.IMAGE_MT_select.remove(menu_IMAGE_select) bpy.types.IMAGE_MT_image.remove(menu_IMAGE_MT_image) @@ -1487,7 +1484,6 @@ def unregister(): bpy.types.VIEW3D_MT_uv_map.remove(menu_VIEW3D_MT_uv_map) bpy.types.VIEW3D_MT_object_context_menu.remove(menu_VIEW3D_MT_object_context_menu) - if __name__ == "__main__": register() diff --git a/op_bake_organize_names.py b/op_bake_organize_names.py index 0b5719c..b26ced0 100644 --- a/op_bake_organize_names.py +++ b/op_bake_organize_names.py @@ -97,7 +97,7 @@ def sort_objects(self): for obj_A in pairs_low_high: obj_B = pairs_low_high[obj_A] try: - obj_B.name = utilities_bake.get_bake_name(obj_A)+" high" + obj_B.name = utilities_bake.get_set_name(obj_A)+" high" obj_A.select_set( state = True, view_layer = None) obj_B.select_set( state = True, view_layer = None) diff --git a/op_island_align_edge.py b/op_island_align_edge.py index 8780eb2..031a203 100644 --- a/op_island_align_edge.py +++ b/op_island_align_edge.py @@ -126,18 +126,20 @@ def align_island(uv_vert0, uv_vert1, faces): loop[uv_layers].select = True diff = uv_vert1 - uv_vert0 - angle = math.atan2(diff.y, diff.x) % (math.pi/2) + current_angle = math.atan2(diff.x, diff.y) + angle_to_rotate = round(current_angle / (math.pi/2)) * (math.pi/2) - current_angle + + # For some reason bpy.ops.transform.rotate rotates in the opposite + # direction in Blender 2.83 than in other versions. + if float(bpy.app.version_string[0:4]) == 2.83: + angle_to_rotate = -angle_to_rotate bpy.ops.uv.select_linked() bpy.context.tool_settings.transform_pivot_point = 'CURSOR' bpy.ops.uv.cursor_set(location=uv_vert0 + diff/2) - if angle >= (math.pi/4): - angle = angle - (math.pi/2) - - bpy.ops.transform.rotate(value=angle, orient_axis='Z', constraint_axis=( - False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False) + bpy.ops.transform.rotate(value=angle_to_rotate, orient_axis='Z', constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False) bpy.utils.register_class(op) diff --git a/op_island_align_world.py b/op_island_align_world.py index 92f131e..750dd86 100644 --- a/op_island_align_world.py +++ b/op_island_align_world.py @@ -6,17 +6,23 @@ import operator from mathutils import Vector from collections import defaultdict -from itertools import chain # 'flattens' collection of iterables +from itertools import chain # 'flattens' collection of iterables from . import utilities_uv + + class op(bpy.types.Operator): bl_idname = "uv.textools_island_align_world" bl_label = "Align World" bl_description = "Align selected UV islands to world / gravity directions" 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( # name = "Global Axis", # description = "Global or local object axis alignment", @@ -32,245 +38,243 @@ class op(bpy.types.Operator): if not bpy.context.active_object: return False - # Only in Edit mode + #Only in Edit mode if bpy.context.active_object.mode != 'EDIT': return False - # Requires UV map + #Requires UV map if not bpy.context.object.data.uv_layers: return False if bpy.context.scene.tool_settings.use_uv_select_sync: return False - # Only in UV editor mode + #Only in UV editor mode if bpy.context.area.type != 'IMAGE_EDITOR': return False return True def execute(self, context): - main(self) + main(self, context) 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") - # Store selection + #Store selection utilities_uv.selection_store() bm = bmesh.from_edit_mesh(bpy.context.active_object.data) uv_layers = bm.loops.layers.uv.verify() - # Only in Face or Island mode + #Only in Face or Island mode if bpy.context.scene.tool_settings.uv_select_mode is not 'FACE' or 'ISLAND': bpy.context.scene.tool_settings.uv_select_mode = 'FACE' - obj = bpy.context.object - bm = bmesh.from_edit_mesh(bpy.context.active_object.data) - uv_layers = bm.loops.layers.uv.verify() - - islands = utilities_uv.getSelectionIslands() - + obj = bpy.context.object + bm = bmesh.from_edit_mesh(bpy.context.active_object.data); + uv_layers = bm.loops.layers.uv.verify(); + + 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: - # Get average viewport normal of UV island - avg_normal = Vector((0, 0, 0)) - for face in faces: - avg_normal += face.normal - avg_normal /= len(faces) - - # avg_normal = (obj.matrix_world*avg_normal).normalized() + avg_normal = Vector((0,0,0)) + if self.bool_face: + avg_normal = faces[0].normal + else: + # Get average viewport normal of UV island + for face in faces: + avg_normal+=face.normal + avg_normal/=len(faces) # Which Side x = 0 y = 1 z = 2 max_size = max(abs(avg_normal.x), abs(avg_normal.y), abs(avg_normal.z)) - - # Use multiple steps - for i in range(3): + + for i in range(self.steps): # Use multiple steps if(abs(avg_normal.x) == max_size): 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): 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): print("z normal") - 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)) - - # Restore selection + if self.bool_simple: + align_island_simple(obj, bm, uv_layers, faces, x, y, False, avg_normal.z < 0) + 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)) + + #Restore selection utilities_uv.selection_restore() def align_island(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_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)) - - # 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("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(" A1 {:.1f} , A2 {:.1f} along ".format(minmax_val[0], minmax_val[1] )) + # Collect UV to Vert - vert_to_uv = utilities_uv.get_vert_to_uv(bm, uv_layers) - uv_to_vert = utilities_uv.get_uv_to_vert(bm, uv_layers) - + vert_to_uv = {} + 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 = [] - edges = [] + n_edges = 0 + avg_angle = 0 for face in faces: for edge in face.edges: if edge not in processed_edges: 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)) - # Check edges dominant in active axis - if(abs(delta[x]) == max_side or abs(delta[y]) == max_side): - # if( abs(delta[y]) == max_side): - edges.append(edge) + if( abs(delta[x]) == max_side or abs(delta[y]) == max_side): + n_edges += 1 + 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 + )) + + 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 + + # For some reason, bpy.ops.transform.rotate rotates in the opposite direction in Blender 2.83 compared to other versions. + if float(bpy.app.version_string[0:4]) == 2.83: + avg_angle = -avg_angle + + 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 + + bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT' + bpy.ops.transform.rotate(value=-avg_angle, orient_axis='Z', constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False) - print("Edges {}x".format(len(edges))) - avg_angle = 0 - for edge in edges: - uv0 = vert_to_uv[edge.verts[0]][0] - uv1 = vert_to_uv[edge.verts[1]][0] +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)) + a_delta = 0 + + # 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] + 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_verts.y = edge.verts[0].co[y] - edge.verts[1].co[y] - + delta_uvs = Vector(( uv1.uv.x - uv0.uv.x, 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)) - # 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)) + # For some reason, bpy.ops.transform.rotate rotates in the opposite direction in Blender 2.83 compared to other versions. + if float(bpy.app.version_string[0:4]) == 2.83: + a_delta = -a_delta + + print("Turn {:.1f}".format(a_delta * 180/math.pi)) bpy.ops.uv.select_all(action='DESELECT') 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') - for face in faces: - - # Collect UV to Vert - for loop in face.loops: - loop[uv_layers].select = True - vert = loop.vert - uv = loop[uv_layers] - # vert_to_uv - 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.ops.transform.rotate(value=-a_delta, orient_axis='Z', constraint_axis=(False, False, False), orient_type='GLOBAL', mirror=False, use_proportional_edit=False) bpy.utils.register_class(op) diff --git a/op_rectify.py b/op_rectify.py index b674e19..cfb33a1 100644 --- a/op_rectify.py +++ b/op_rectify.py @@ -4,6 +4,7 @@ import operator from mathutils import Vector from collections import defaultdict from math import pi +import sys import time from math import radians, hypot @@ -37,6 +38,11 @@ class op(bpy.types.Operator): rectify(self, context) return {'FINISHED'} +def time_clock(): + if sys.version_info >= (3, 3): + return time.process_time() + else: + return time.clock() precision = 3 @@ -58,7 +64,7 @@ def rectify(self, context): def main(square=False, snapToClosest=False): - startTime = time.clock() + startTime = time_clock() obj = bpy.context.active_object me = obj.data bm = bmesh.from_edit_mesh(me) @@ -303,7 +309,7 @@ def SuccessFinished(me, startTime): # use for backtrack of steps # bpy.ops.ed.undo_push() bmesh.update_edit_mesh(me) - #elapsed = round(time.clock()-startTime, 2) + #elapsed = round(time_clock()-startTime, 2) #if (elapsed >= 0.05): operator.report({'INFO'}, "UvSquares finished, elapsed:", elapsed, "s.") return diff --git a/op_select_islands_outline.py b/op_select_islands_outline.py index 1a440d9..ad43b83 100644 --- a/op_select_islands_outline.py +++ b/op_select_islands_outline.py @@ -10,7 +10,7 @@ from . import utilities_ui class op(bpy.types.Operator): bl_idname = "uv.textools_select_islands_outline" - bl_label = "Select Overlap" + bl_label = "Select Island outline" bl_description = "Select island edge bounds" bl_options = {'REGISTER', 'UNDO'} @@ -24,7 +24,11 @@ class op(bpy.types.Operator): #Requires UV map if not bpy.context.object.data.uv_layers: - return False + return False + + # #requires UV_sync + # if not bpy.context.scene.tool_settings.use_uv_select_sync: + # return False return True @@ -40,12 +44,23 @@ def select_outline(context): if bpy.context.active_object.mode != 'EDIT': bpy.ops.object.mode_set(mode='EDIT') - - bpy.context.scene.tool_settings.use_uv_select_sync = False - bm = bmesh.from_edit_mesh(bpy.context.active_object.data); uv_layers = bm.loops.layers.uv.verify(); + pre_sync = bpy.context.scene.tool_settings.use_uv_select_sync + if bpy.context.scene.tool_settings.use_uv_select_sync: + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') + bpy.ops.uv.select_linked() + bpy.context.scene.tool_settings.use_uv_select_sync = False + bpy.ops.uv.select_all(action='SELECT') + else: + current_edit = tuple(bpy.context.tool_settings.mesh_select_mode) + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') + current_select = [f for f in bm.faces if f.select] + + islands = utilities_uv.getSelectionIslands() + faces_islands = [face for island in islands for face in island] + edges_islands = [edge for island in islands for face in island for edge in face.edges] bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') bpy.ops.mesh.select_all(action='DESELECT') @@ -60,19 +75,40 @@ def select_outline(context): # Create seams from islands bpy.ops.uv.seams_from_islands(contextViewUV) - edges_islands = [edge for edge in bm.edges if edge.seam] + edges_seams_from_islands = [edge for edge in bm.edges if edge.seam] # Clear seams - for edge in edges_islands: + for edge in edges_seams_from_islands: edge.seam = False - # Select island edges - bpy.ops.mesh.select_all(action='DESELECT') - for edge in edges_islands: - edge.select = True + if pre_sync: + # Select seams from islands edges and edge boundaries + for edge in edges_islands: + if edge.is_boundary or edge in edges_seams_from_islands: + edge.select = True + else: + for face in current_select: + face.select = True + bpy.context.tool_settings.mesh_select_mode = current_edit + bpy.ops.uv.select_all(action='DESELECT') + edges = [] + for edge in edges_islands: + if edge.is_boundary or edge in edges_seams_from_islands: + edges.extend([e for e in edge.verts[0].link_loops]) + edges.extend([e for e in edge.verts[1].link_loops]) + #edges.append(edge) + + bpy.context.scene.tool_settings.uv_select_mode = 'EDGE' + for face in faces_islands: + for loop in face.loops: + if loop in edges: + loop[uv_layers].select = True + # Restore seam selection for edge in edges_seam: edge.seam = True + bpy.context.scene.tool_settings.use_uv_select_sync = pre_sync + bpy.utils.register_class(op) \ No newline at end of file diff --git a/utilities_ui.py b/utilities_ui.py index 50e40c2..634cb6e 100644 --- a/utilities_ui.py +++ b/utilities_ui.py @@ -110,8 +110,8 @@ class op_popup(bpy.types.Operator): def invoke(self, context, event): wm = context.window_manager - return wm.invoke_popup(self, width=200, height=200) - + return wm.invoke_popup(self, width=200) + def draw(self, context): self.layout.label(text=self.message) @@ -155,15 +155,17 @@ def unregister(): from bpy.types import WindowManager for preview_collection in preview_collections.values(): bpy.utils.previews.remove(preview_collection) - preview_collections.clear() + preview_collection.clear() + # Unregister icons # global preview_icons - bpy.utils.previews.remove(preview_icons) - - del bpy.types.Scene.TT_bake_mode + # bpy.utils.previews.remove(preview_icons) + preview_icons.clear() + del bpy.types.Scene.TT_bake_mode + if __name__ == "__main__": register() bpy.utils.register_class(op_popup)