import bpy import bmesh import operator from mathutils import Vector from collections import defaultdict from math import pi import math from . import utilities_uv from . import utilities_texel from . import utilities_meshtex def get_mode(): if not utilities_meshtex.find_uv_mesh([bpy.context.active_object]): # Create UV mesh from face selection if bpy.context.active_object and bpy.context.active_object.mode == 'EDIT': return 'FACES' # Create UV mesh from whole object if bpy.context.active_object and bpy.context.active_object.type == 'MESH': if "SurfaceDeform" not in bpy.context.active_object.modifiers: return 'OBJECT' return 'UNDEFINED' class op(bpy.types.Operator): bl_idname = "uv.textools_meshtex_create" bl_label = "UV Mesh" bl_description = "Create a new UV Mesh from your selected object" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): if get_mode() == 'UNDEFINED': return False return True def execute(self, context): create_uv_mesh(self, bpy.context.active_object) return {'FINISHED'} def create_uv_mesh(self, obj): mode = bpy.context.active_object.mode # Select bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') obj.select_set( state = True, view_layer = None) bpy.context.view_layer.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_mode(type="FACE") bpy.context.scene.tool_settings.use_uv_select_sync = False # Select all if OBJECT mode if mode == 'OBJECT': bpy.ops.mesh.select_all(action='SELECT') # bpy.ops.uv.select_all(action='SELECT') # Create UV Map if not obj.data.uv_layers: if mode == 'OBJECT': # Smart UV project bpy.ops.uv.smart_project( angle_limit=65, island_margin=0.5, user_area_weight=0, use_aspect=True, stretch_to_bounds=True ) elif mode == 'EDIT': # Iron Faces bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0) bpy.ops.uv.textools_unwrap_faces_iron() bm = bmesh.from_edit_mesh(obj.data) uv_layers = bm.loops.layers.uv.verify() #Collect UV islands bpy.ops.uv.select_all(action='SELECT') islands = utilities_uv.getSelectionIslands(bm, uv_layers) # Collect clusters uvs = {} clusters = [] uv_to_clusters = {} vert_to_clusters = {} face_area_view = 0 face_area_uv = 0 for face in bm.faces: if face.select: # Calculate triangle area for UV and View # Triangle Verts tri_uv = [loop[uv_layers].uv for loop in face.loops ] tri_vt = [vert.co for vert in face.verts] #Triangle Areas face_area_view += math.sqrt(utilities_texel.get_area_triangle( tri_vt[0], tri_vt[1], tri_vt[2] )) face_area_uv += math.sqrt(utilities_texel.get_area_triangle( tri_uv[0], tri_uv[1], tri_uv[2] )) for i in range(len(face.loops)): v = face.loops[i] uv = Get_UVSet(uvs, bm, uv_layers, face.index, i) # # clusters isMerged = False for cluster in clusters: d = (uv.pos() - cluster.uvs[0].pos()).length if d <= 0.0000001: #Merge cluster.append(uv) uv_to_clusters[uv] = cluster if v not in vert_to_clusters: vert_to_clusters[v] = cluster isMerged = True; break; if not isMerged: #New Group clusters.append( UVCluster(v, [uv]) ) uv_to_clusters[uv] = clusters[-1] if v not in vert_to_clusters: vert_to_clusters[v] = clusters[-1] scale = face_area_view / face_area_uv print("Scale {}x {} | {}".format(scale, face_area_view, face_area_uv)) print("Islands {}x".format(len(islands))) print("UV Vert Clusters {}x".format(len(clusters))) m_vert_cluster = [] m_verts_org = [] m_verts_A = [] m_verts_B = [] m_faces = [] for island in islands: for face in island: f = [] for i in range(len(face.loops)): v = face.loops[i].vert uv = Get_UVSet(uvs, bm, uv_layers, face.index, i) c = uv_to_clusters[ uv ] index = 0 if c in m_vert_cluster: index = m_vert_cluster.index(c) else: index = len(m_vert_cluster) m_vert_cluster.append(c) m_verts_org.append(v) m_verts_A.append( Vector((uv.pos().x*scale - scale/2, uv.pos().y*scale -scale/2, 0)) ) m_verts_B.append( obj.matrix_world @ v.co - bpy.context.scene.cursor.location ) f.append(index) m_faces.append(f) # Add UV bounds as edges verts = [ Vector((-scale/2, -scale/2, 0)), Vector(( scale/2, -scale/2, 0)), Vector(( scale/2, scale/2, 0)), Vector((-scale/2, scale/2, 0)), ] m_verts_A = m_verts_A+verts; m_verts_B = m_verts_B+verts; bpy.ops.object.mode_set(mode='OBJECT') # Create Mesh mesh = bpy.data.meshes.new("mesh_texture") mesh.from_pydata(m_verts_A, [], m_faces) mesh.update() mesh_obj = bpy.data.objects.new("UV_mesh {0}".format(obj.name), mesh) mesh_obj.location = bpy.context.scene.cursor.location bpy.context.collection.objects.link(mesh_obj) # Add shape keys mesh_obj.shape_key_add(name="uv", from_mix=True) mesh_obj.shape_key_add(name="model", from_mix=True) mesh_obj.active_shape_key_index = 1 # Select bpy.context.view_layer.objects.active = mesh_obj mesh_obj.select_set( state = True, view_layer = None) bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(mesh_obj.data) if hasattr(bm.faces, "ensure_lookup_table"): bm.faces.ensure_lookup_table() bm.verts.ensure_lookup_table() bm.edges.new((bm.verts[-4], bm.verts[-3])) bm.edges.new((bm.verts[-3], bm.verts[-2])) bm.edges.new((bm.verts[-2], bm.verts[-1])) bm.edges.new((bm.verts[-1], bm.verts[-4])) for i in range(len(m_verts_B)): bm.verts[i].co = m_verts_B[i] # Split concave faces to resolve issues with Shape deform bpy.context.object.active_shape_key_index = 0 bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.vert_connect_concave() bpy.ops.object.mode_set(mode='OBJECT') # Display as edges only mesh_obj.show_wire = True mesh_obj.show_all_edges = True # mesh_obj.data.display_type = 'WIRE' #Esta linea deberia llevarte a la opcion wireframe bpy.ops.object.select_all(action='DESELECT') mesh_obj.select_set( state = True, view_layer = None) bpy.context.view_layer.objects.active = mesh_obj def Get_UVSet(uvs, bm, layer, index_face, index_loop): index = get_uv_index(index_face, index_loop) if index not in uvs: uvs[index] = UVSet(bm, layer, index_face, index_loop) return uvs[index] class UVSet: bm = None layer = None index_face = 0 index_loop = 0 def __init__(self, bm, layer, index_face, index_loop): self.bm = bm self.layer = layer self.index_face = index_face self.index_loop = index_loop def uv(self): face = self.bm.faces[self.index_face] return face.loops[self.index_loop][self.layer] def pos(self): return self.uv().uv def vertex(self): return face.loops[self.index_loop].vertex def get_uv_index(index_face, index_loop): return (index_face*1000000)+index_loop class UVCluster: uvs = [] vertex = None def __init__(self, vertex, uvs): self.vertex = vertex self.uvs = uvs def append(self, uv): self.uvs.append(uv) bpy.utils.register_class(op)