def invoke(self, context, event): bpy.ops.object.duplicate_move() bpy.context.object.name = bpy.context.object.name.replace("_HP.001", "_LP") bpy.ops.object.modifier_add(type='DECIMATE') bpy.context.object.modifiers["Decimate"].ratio = 0.006 bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Decimate") bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = (False, False, True) obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) for face in bm.faces: if face.select == False: face.select = True elif face.select == True: face.select = True continue bpy.ops.uv.smart_project(island_margin=0.005) bpy.ops.uv.seams_from_islands() bpy.context.tool_settings.mesh_select_mode = (False, True, False) bpy.ops.mesh.select_all() obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) for edge in bm.edges: if edge.seam == 1: edge.select = True continue bpy.ops.mesh.mark_sharp() bpy.ops.mesh.mark_seam(clear=True) bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_add(type='EDGE_SPLIT') bpy.context.object.modifiers["EdgeSplit"].use_edge_angle = False return {"FINISHED"}
def defReconst(self, OFFSET): bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.context.tool_settings.mesh_select_mode = (True, True, True) ob = bpy.context.active_object bm = bmesh.from_edit_mesh(ob.data) bm.select_flush(False) for vertice in bm.verts[:]: if abs(vertice.co[0]) < OFFSET: vertice.co[0] = 0 for vertice in bm.verts[:]: if vertice.co[0] < 0: bm.verts.remove(vertice) bmesh.update_edit_mesh(ob.data) mod = ob.modifiers.new("Mirror","MIRROR") uv = ob.data.uv_textures.new(name="SYMMETRICAL") for v in bm.faces: v.select = 1 bmesh.update_edit_mesh(ob.data) ob.data.uv_textures.active = ob.data.uv_textures['SYMMETRICAL'] bpy.ops.uv.unwrap(method='ANGLE_BASED', fill_holes=True, correct_aspect=False, use_subsurf_data=0) bpy.ops.object.mode_set(mode="OBJECT", toggle= False) bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Mirror") bpy.ops.object.mode_set(mode="EDIT", toggle= False) bm = bmesh.from_edit_mesh(ob.data) bm.select_flush(0) uv = ob.data.uv_textures.new(name="ASYMMETRICAL") ob.data.uv_textures.active = ob.data.uv_textures['ASYMMETRICAL'] bpy.ops.uv.unwrap(method='ANGLE_BASED', fill_holes=True, correct_aspect=False, use_subsurf_data=0)
def invoke(self, context, event): bpy.ops.object.editmode_toggle() bpy.context.tool_settings.mesh_select_mode = (False, False, True) obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) for face in bm.faces: if face.select == False: face.select = True elif face.select == True: face.select = True continue bpy.ops.uv.seams_from_islands() bpy.context.tool_settings.mesh_select_mode = (False, True, False) bpy.ops.mesh.select_all() obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) for edge in bm.edges: if edge.seam == 1: edge.select = True continue bpy.ops.mesh.mark_sharp() bpy.ops.mesh.mark_seam(clear=True) bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_add(type='EDGE_SPLIT') bpy.context.object.modifiers["EdgeSplit"].use_edge_angle = False return {"FINISHED"}
def defReconst(self, OFFSET): bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.context.tool_settings.mesh_select_mode = (True, False, False) OBJETO = bpy.context.active_object OBDATA = bmesh.from_edit_mesh(OBJETO.data) OBDATA.select_flush(False) for vertice in OBDATA.verts[:]: if abs(vertice.co[0]) < OFFSET: vertice.co[0] = 0 bpy.ops.mesh.select_all(action="DESELECT") for vertices in OBDATA.verts[:]: if vertices.co[0] < 0: vertices.select = 1 bpy.ops.mesh.delete() bpy.ops.object.modifier_add(type='MIRROR') bpy.ops.mesh.select_all(action="SELECT") bpy.ops.mesh.uv_texture_add() LENUVLISTSIM = len(bpy.data.objects[OBJETO.name].data.uv_textures) LENUVLISTSIM = LENUVLISTSIM - 1 OBJETO.data.uv_textures[LENUVLISTSIM:][0].name = "SYMMETRICAL" bpy.ops.uv.unwrap(method='ANGLE_BASED', fill_holes=True, correct_aspect=False, use_subsurf_data=0) bpy.ops.object.mode_set(mode="OBJECT", toggle= False) bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Mirror") bpy.ops.object.mode_set(mode="EDIT", toggle= False) OBDATA = bmesh.from_edit_mesh(OBJETO.data) OBDATA.select_flush(0) bpy.ops.mesh.uv_texture_add() LENUVLISTASIM = len(OBJETO.data.uv_textures) LENUVLISTASIM = LENUVLISTASIM - 1 OBJETO.data.uv_textures[LENUVLISTASIM:][0].name = "ASYMMETRICAL" OBJETO.data.uv_textures.active = OBJETO.data.uv_textures["ASYMMETRICAL"] bpy.ops.uv.unwrap(method='ANGLE_BASED', fill_holes=True, correct_aspect=False, use_subsurf_data=0)
def update_references(self): """ This method tries to update references at bmesh, when old bmesh was removed """ if self.bmesh is None: if bpy.context.edit_object is not None and \ bpy.context.edit_object.data == self.mesh: self.bmesh = bmesh.from_edit_mesh(self.mesh) self.bm_from_edit_mesh = True else: self.bmesh = bmesh.new() self.bmesh.from_mesh(self.mesh) self.bm_from_edit_mesh = False else: try: self.bmesh.verts except ReferenceError: if bpy.context.edit_object is not None and \ bpy.context.edit_object.data == self.mesh: self.bmesh = bmesh.from_edit_mesh(self.mesh) self.bm_from_edit_mesh = True else: self.bmesh = bmesh.new() self.bmesh.from_mesh(self.mesh) self.bm_from_edit_mesh = False self.clear_ID_cache()
def prepare(self, context, remove_start_faces = True): """Start for a face selected change of faces select an object of type mesh, with activated severel (all) faces """ #print("prepare called") obj = bpy.context.scene.objects.active #objmode = obj.mode bpy.ops.object.mode_set(mode='OBJECT') selectedpolygons = [el for el in obj.data.polygons if el.select] #edge_index_list = [[el.index for el in face.edges ] for face in selectedpolygons] #print("start edge_index_list", edge_index_list) #PKHG>INFO copies of the vectors are needed, otherwise Blender crashes! centers = [face.center for face in selectedpolygons] centers_copy = [Vector((el[0],el[1],el[2])) for el in centers] normals = [face.normal for face in selectedpolygons] normals_copy = [Vector((el[0],el[1],el[2])) for el in normals] vertindicesofpolgons = [[vert for vert in face.vertices] for face in selectedpolygons] vertVectorsOfSelectedFaces = [[obj.data.vertices[ind].co for ind in vertIndiceofface]\ for vertIndiceofface in vertindicesofpolgons] vertVectorsOfSelectedFaces_copy = [[Vector((el[0],el[1],el[2])) for el in listofvecs]\ for listofvecs in vertVectorsOfSelectedFaces] bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(obj.data) selected_bm_faces = [ ele for ele in bm.faces if ele.select] selected_edges_per_face_ind = [[ele.index for ele in face.edges] for face in selected_bm_faces] #print("\n\nPKHG>DBG selected_edges_per_face", selected_edges_per_face_ind) indices = [el.index for el in selectedpolygons] #print("indices", indices, bm.faces[:]) selected_faces_areas = [bm.faces[:][i] for i in indices ] tmp_area = [el.calc_area() for el in selected_faces_areas] #PKHG>INFO, selected faces are removed, only their edges are used! if remove_start_faces: bpy.ops.mesh.delete(type='ONLY_FACE') bpy.ops.object.mode_set(mode='OBJECT') obj.data.update() bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(obj.data) bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() start_ring_raw = [[bm.verts[ind].index for ind in vertIndiceofface] \ for vertIndiceofface in vertindicesofpolgons] start_ring = [] for el in start_ring_raw: #el.sort() start_ring.append(set(el)) bm.edges.ensure_lookup_table() bm_selected_edges_l_l = [[bm.edges[i] for i in bm_ind_list ] for bm_ind_list in selected_edges_per_face_ind] result = {'obj': obj, 'centers':centers_copy, 'normals': normals_copy,\ 'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm ,\ 'areas': tmp_area,'startBMRingVerts':start_ring,\ 'base_edges':bm_selected_edges_l_l} return result
def execute(self, context): # if self.target_length == 0: # return {'FINISHED'} self.count += 1 if self.count == 1: # 初始化 ob = context.edit_object # 准备 self.me = ob.data self.switch_point = False bm = bmesh.from_edit_mesh(self.me) # 选择顺序 重新判断长度是为了识别模式切换 if len(bm.select_history) > 1 and isinstance(bm.select_history[-1], bmesh.types.BMVert): self.vts_sequence = [i.index for i in [bm.select_history[j] for j in (-2,-1)]] elif len(bm.select_history) > 0 and isinstance(bm.select_history[-1], bmesh.types.BMEdge): self.vts_sequence = [i.index for i in bm.select_history[-1].verts] else: self.report({'ERROR'}, '0,1 edge OR 2 points; 1,don\'t support Face mode; 2,Changing select mode will Lost select-history') return {'CANCELLED'} # 当前长度 if abs(self.target_length) < 0.000000000001: if self.switch_point: tmp_vts_sequence = [self.vts_sequence[-1], self.vts_sequence[-2]] else: tmp_vts_sequence = self.vts_sequence vector = bm.verts[tmp_vts_sequence[-2]].co - bm.verts[tmp_vts_sequence[-1]].co self.target_length = vector.length self.execute(context) else: bm = bmesh.from_edit_mesh(self.me) if self.switch_point: tmp_vts_sequence = [self.vts_sequence[-1], self.vts_sequence[-2]] else: tmp_vts_sequence = self.vts_sequence vector = bm.verts[tmp_vts_sequence[-2]].co - bm.verts[tmp_vts_sequence[-1]].co vector.length = abs(self.target_length) if self.target_length > 0: bm.verts[tmp_vts_sequence[-1]].co = bm.verts[tmp_vts_sequence[-2]].co - vector elif self.target_length < 0: bm.verts[tmp_vts_sequence[-1]].co = bm.verts[tmp_vts_sequence[-2]].co + vector # 刷新视窗数据 bmesh.update_edit_mesh(self.me, True) return {'FINISHED'}
def execute(self, context): # create connection socket_connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # socket_connection.sendto(bytes(context.active_object.name,'utf-8'),addr) mess = "number of vertices: "+str(len(context.active_object.data.vertices)) # socket_connection.sendto(bytes(mess,'utf-8'),addr) sel_vert = [] if context.active_object.mode == "EDIT": blender_mesh = bmesh.from_edit_mesh(context.active_object.data) for v in blender_mesh.verts: if v.select is True: sel_vert.append(v) else: blender_mesh = context.active_object.data for v in blender_mesh.vertices: if v.select is True: sel_vert.append(v) # extract coordinate data from all vertices all_vert = context.active_object.data.vertices vertex_coordinates = [[v.co.x, v.co.y, v.co.z] for v in all_vert] vertex_normals = [[v.normal.x, v.normal.y, v.normal.z] for v in all_vert] # extract selected edges selected_edges = [] if context.active_object.mode == "EDIT": # the syntax is a little different depending on if we are in EDIT mode or not blender_mesh = bmesh.from_edit_mesh(context.active_object.data) for v in blender_mesh.edges: if v.select is True: selected_edges.append(v) edges = [(e.verts[0].index, e.verts[1].index) for e in selected_edges] else: # if we are not in edit mode things are a bit easier blender_mesh = context.active_object.data for v in blender_mesh.edges: if v.select is True: selected_edges.append(v) edges = [(e.vertices[0], e.vertices[1]) for e in selected_edges] # extract vertex index data from selected edges mess = {'edges': edges, 'vert_loc': vertex_coordinates, 'vert_norm': vertex_normals} mess = json.dumps(mess) addr = (self.IP, self.port) socket_connection.sendto(bytes(mess, "utf-8"), addr) self.report({'INFO'}, "sent message to: "+self.IP+" port: "+str(self.port)) # this lets blender know the operator finished successfully. return {'FINISHED'}
def execute(self, context): obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) if common.check_version(2, 73, 0) >= 0: bm.faces.ensure_lookup_table() uv_layer = bm.loops.layers.uv.verify() if context.tool_settings.use_uv_select_sync: sel_faces = [f for f in bm.faces] else: sel_faces = [f for f in bm.faces if f.select] overlapped_info = common.get_overlapped_uv_info(bm, sel_faces, uv_layer, 'FACE') for info in overlapped_info: if context.tool_settings.use_uv_select_sync: info["subject_face"].select = True else: for l in info["subject_face"].loops: l[uv_layer].select = True bmesh.update_edit_mesh(obj.data) return {'FINISHED'}
def create_ground(pos_z, length, width): mat_ground = createMaterial('ground.png') bpy.ops.mesh.primitive_cube_add(location=(0,0,pos_z)) ground = bpy.context.active_object ground_data = ground.data bpy.ops.object.mode_set(mode='EDIT') mesh = bmesh.from_edit_mesh(ground_data) extrude_face(mesh, 2, length, 0, 0) mesh.faces[1].select = True mesh.faces[9].select = True extrude_face_simple(mesh, 0, width, 0) mesh.faces[1].select = True mesh.faces[9].select = True bpy.ops.mesh.subdivide() bpy.ops.mesh.subdivide() bpy.ops.mesh.subdivide() bpy.ops.mesh.select_all(action="DESELECT") setMaterial(ground, mat_ground) bpy.ops.uv.smart_project() bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.shade_smooth()
def filter_items_empty_vgroups(self, context, vgroups): # This helper function checks vgroups to find out whether they are empty, and what's their average weights. # TODO: This should be RNA helper actually (a vgroup prop like "raw_data: ((vidx, vweight), etc.)"). # Too slow for python! obj_data = context.active_object.data ret = {vg.index: [True, 0.0] for vg in vgroups} if hasattr(obj_data, "vertices"): # Mesh data if obj_data.is_editmode: import bmesh bm = bmesh.from_edit_mesh(obj_data) # only ever one deform weight layer dvert_lay = bm.verts.layers.deform.active fact = 1 / len(bm.verts) if dvert_lay: for v in bm.verts: for vg_idx, vg_weight in v[dvert_lay].items(): ret[vg_idx][0] = False ret[vg_idx][1] += vg_weight * fact else: fact = 1 / len(obj_data.vertices) for v in obj_data.vertices: for vg in v.groups: ret[vg.group][0] = False ret[vg.group][1] += vg.weight * fact elif hasattr(obj_data, "points"): # Lattice data # XXX no access to lattice editdata? fact = 1 / len(obj_data.points) for v in obj_data.points: for vg in v.groups: ret[vg.group][0] = False ret[vg.group][1] += vg.weight * fact return ret
def draw(self, context): ob = bpy.context.object if ob is None: return if ob.type != 'MESH': raise TypeError("Active object is not a Mesh") me = ob.data if me.is_editmode: # Gain direct access to the mesh bm = bmesh.from_edit_mesh(me) else: # Create a bmesh from mesh # (won't affect mesh, unless explicitly written back) bm = bmesh.new() bm.from_mesh(me) # Get active face face = bm.faces.active if face is None: return arxFaceType = bm.faces.layers.int.get('arx_facetype') arxTransVal = bm.faces.layers.float.get('arx_transval') faceType = PolyTypeFlag() faceType.asUInt = face[arxFaceType] transval = face[arxTransVal] obj = bpy.context.active_object layout = self.layout layout.label(text="transval: " + str(transval)) layout.label(text="POLY_NO_SHADOW: " + str(faceType.POLY_NO_SHADOW)) layout.label(text="POLY_DOUBLESIDED: " + str(faceType.POLY_DOUBLESIDED)) layout.label(text="POLY_TRANS: " + str(faceType.POLY_TRANS)) layout.label(text="POLY_WATER: " + str(faceType.POLY_WATER)) layout.label(text="POLY_GLOW: " + str(faceType.POLY_GLOW)) layout.label(text="POLY_IGNORE: " + str(faceType.POLY_IGNORE)) layout.label(text="POLY_QUAD: " + str(faceType.POLY_QUAD)) layout.label(text="POLY_METAL: " + str(faceType.POLY_METAL)) layout.label(text="POLY_HIDE: " + str(faceType.POLY_HIDE)) layout.label(text="POLY_STONE: " + str(faceType.POLY_STONE)) layout.label(text="POLY_WOOD: " + str(faceType.POLY_WOOD)) layout.label(text="POLY_GRAVEL: " + str(faceType.POLY_GRAVEL)) layout.label(text="POLY_EARTH: " + str(faceType.POLY_EARTH)) layout.label(text="POLY_NOCOL: " + str(faceType.POLY_NOCOL)) layout.label(text="POLY_LAVA: " + str(faceType.POLY_LAVA)) layout.label(text="POLY_CLIMB: " + str(faceType.POLY_CLIMB)) layout.label(text="POLY_FALL: " + str(faceType.POLY_FALL)) layout.label(text="POLY_NOPATH: " + str(faceType.POLY_NOPATH)) layout.label(text="POLY_NODRAW: " + str(faceType.POLY_NODRAW)) layout.label(text="POLY_PRECISE_PATH: " + str(faceType.POLY_PRECISE_PATH)) layout.label(text="POLY_LATE_MIP: " + str(faceType.POLY_LATE_MIP))
def do_polyredux(self): global bm, me # Gets the current scene, there can be many scenes in 1 blend file. sce = bpy.context.scene # Get the active object, there can only ever be 1 # and the active object is always the editmode object. mode = "EDIT" if bpy.context.mode == "OBJECT": mode = "OBJECT" bpy.ops.object.editmode_toggle() ob_act = bpy.context.active_object if not ob_act or ob_act.type != "MESH": return me = ob_act.data bm = bmesh.from_edit_mesh(me) t = time.time() # Run the mesh editing function my_mesh_util() me.update(calc_edges=True, calc_tessface=True) bm.free() # Restore editmode if it was enabled if mode == "OBJECT": bpy.ops.object.editmode_toggle() else: bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() # Timing the script is a good way to be aware on any speed hits when scripting print("My Script finished in %.2f seconds" % (time.time() - t))
def __init__(self, obj, create_tris, create_edges, create_looseverts): self.tri_verts = self.edge_verts = self.looseverts = None self.tris_co = self.edges_co = self.looseverts_co = None if obj.type == 'MESH': me = obj.data if me.is_editmode: bm = bmesh.from_edit_mesh(me) bm.verts.ensure_lookup_table() self.verts_co = get_bmesh_vert_co_array(bm) if create_tris: self.tri_verts = get_bmesh_tri_verts_array(bm) if create_edges: self.edge_verts = get_bmesh_edge_verts_array(bm) if create_looseverts: self.looseverts = get_bmesh_loosevert_array(bm) else: self.verts_co = get_mesh_vert_co_array(me) if create_tris: self.tri_verts = get_mesh_tri_verts_array(me) if create_edges: self.edge_verts = get_mesh_edge_verts_array(me) if create_looseverts: edge_verts = self.edge_verts if edge_verts is None: edge_verts = get_mesh_edge_verts_array(me) self.looseverts = get_mesh_loosevert_array(me, edge_verts) del edge_verts else: #TODO self.verts_co = np.zeros((1,3), 'f4') self.looseverts = np.zeros(1, 'i4')
def get_selected_vertex(myobject): mylist = [] # if not mesh, no vertex if myobject.type != "MESH": return mylist # -------------------- # meshes # -------------------- oldobj = bpy.context.object bpy.context.scene.objects.active = myobject flag = False if myobject.mode != 'EDIT': bpy.ops.object.mode_set(mode='EDIT') flag = True bm = bmesh.from_edit_mesh(myobject.data) tv = len(bm.verts) for v in bm.verts: if v.select: mylist.extend([v.index]) if flag is True: bpy.ops.object.editmode_toggle() # Back context object bpy.context.scene.objects.active = oldobj # if select all vertices, then use origin if tv == len(mylist): return [] return mylist
def callback_save_pre(dummy): """ファイルのセーブ前に実行。ロック座標用の頂点レイヤーを削除""" for me in bpy.data.meshes: if me.is_editmode: bm = bmesh.from_edit_mesh(me) else: skip = True if LAYER_LOCK in me.vertex_layers_int: skip = False for name in (LAYER_X, LAYER_Y, LAYER_Z, LAYER_GX, LAYER_GY, LAYER_GZ): if name in me.vertex_layers_float: skip = False if skip: continue bm = bmesh.new() bm.from_mesh(me) for name in (LAYER_X, LAYER_Y, LAYER_Z): layer = bm.verts.layers.float.get(name) if layer: bm.verts.layers.float.remove(layer) # 0.2.0で追加した分 for name in (LAYER_GX, LAYER_GY, LAYER_GZ): layer = bm.verts.layers.float.get(name) if layer: bm.verts.layers.float.remove(layer) if not me.is_editmode: bm.to_mesh(me)
def sw_clipping(obj, autoclip, clipcenter): if "Mirror" in bpy.data.objects[obj].modifiers: obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) vcount = 0 EPSILON = 1.0e-3 if clipcenter == True: EPSILON_sel = 1.0e-1 for v in bm.verts: if -EPSILON_sel <= v.co.x <= EPSILON_sel: if v.select == True: v.co.x = 0 else: if autoclip == True: bpy.ops.mesh.select_all(action='DESELECT') for v in bm.verts: if -EPSILON <= v.co.x <= EPSILON: v.select = True bm.select_history.add(v) v1 = v vcount += 1 if vcount > 1: bpy.ops.mesh.select_axis(mode='ALIGNED') bpy.ops.mesh.loop_multi_select() for v in bm.verts: if v.select == True: v.co.x = 0 break
def execute(self, context): global activePath pathEntry = context.scene.cm_paths.coll[activePath] bm = bmesh.from_edit_mesh(context.active_object.data) fringe = {v for v in bm.verts if v.select} seen = {v for v in bm.verts if v.select} while len(fringe) > 0: nextFrige = set() for v in fringe: for e in v.link_edges: other = e.other_vert(v) if other not in seen: indexStr = str(e.index) if v.index == e.verts[0].index: if indexStr in pathEntry.revDirec: toRm = pathEntry.revDirec.find(indexStr) pathEntry.revDirec.remove(toRm) else: if indexStr not in pathEntry.revDirec: revEdge = pathEntry.revDirec.add() revEdge.name = indexStr nextFrige.add(other) seen.add(v) fringe = nextFrige # Hack to force redraw context.scene.objects.active = context.scene.objects.active return {'FINISHED'}
def get_bmesh(self): bpy.data.objects[self.seed_geom].select = True #bpy.ops.object.select_pattern(pattern=self.seed_geom) self.obj = bpy.context.active_object bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(self.obj.data) return bm
def main(self, context, chboxhide, chboxshow): obj = bpy.context.object me = obj.data bm = bmesh.from_edit_mesh(me) try: v1 = [v for v in bm.verts if (v.select == True and v.hide == False)] e1 = [e for e in bm.edges if (e.select == True and e.hide == False)] f1 = [f for f in bm.faces if (f.select == True and f.hide == False)] if len(v1) > 0 or len(e1) > 0 or f1 > 0: if chboxhide: bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.hide(unselected=False) bpy.ops.mesh.select_all(action='SELECT') elif chboxshow: bpy.ops.mesh.reveal() except: if chboxshow: bpy.ops.mesh.reveal() bmesh.update_edit_mesh(me, True)
def create_streets(offset_val): #grab selection, etc. mode("EDIT") mode("FACE") obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) for i in bm.faces: i.select = True #bevel out streets bpy.ops.mesh.bevel( offset_type = "WIDTH", offset = offset_val, clamp_overlap = True ) for i in bm.faces: if i.select: i.material_index = 1 bpy.ops.object.material_slot_assign else: i.material_index = 0 bpy.ops.object.material_slot_assign bpy.ops.object.material_slot_assign mode("EDIT") bmesh.update_edit_mesh(me)
def view_3d_context_visuals(): obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) toggle_index("FACE") for i in bm.faces: i.select = True
def execute(self, context): ob = context.active_object me = ob.data bm = bmesh.from_edit_mesh(me) #print(self.available_vgroups) # Save current selection selected_verts = [] for v in bm.verts: if v.select is True: selected_verts.append(v.index) if v.index != self.vertex: v.select = False weight = context.tool_settings.vertex_group_weight context.tool_settings.vertex_group_weight = 1.0 if self.available_vgroups == "-1": bpy.ops.object.vertex_group_assign(new=True) #XXX Assumes self.vertex is the active vertex else: bpy.ops.object.vertex_group_set_active(group = self.available_vgroups) bpy.ops.object.vertex_group_assign() #XXX Assumes self.vertex is the active vertex context.tool_settings.vertex_group_weight = weight # Re-select vertices for v in bm.verts: if v.index in selected_verts: v.select = True #XXX Hacky, but there's no other way to update the UI panels bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() return {'FINISHED'}
def __find_uv(self, context): bm = bmesh.from_edit_mesh(context.object.data) topology_dict = [] first = True diff = 0 uvs = [] active_uv = bm.loops.layers.uv.active for fidx, f in enumerate(bm.faces): for vidx, v in enumerate(f.verts): if v.select: uvs.append(f.loops[vidx][active_uv].uv.copy()) topology_dict.append([fidx, vidx]) if first: v1 = v.link_loops[0].vert.co sv1 = view3d_utils.location_3d_to_region_2d( context.region, context.space_data.region_3d, v1) v2 = v.link_loops[0].link_loop_next.vert.co sv2 = view3d_utils.location_3d_to_region_2d( context.region, context.space_data.region_3d, v2) vres = sv2 - sv1 va = vres.angle(Vector((0.0, 1.0))) uv1 = v.link_loops[0][active_uv].uv uv2 = v.link_loops[0].link_loop_next[active_uv].uv uvres = uv2 - uv1 uva = uvres.angle(Vector((0.0,1.0))) diff = uva - va first = False return topology_dict, uvs
def execute(self, context): if context.object.mode == 'EDIT': verts = [i.index for i in bmesh.from_edit_mesh(bpy.context.active_object.data).verts if i.select] if len(verts) > 0: context.object["boundary_condition"] = verts return {'FINISHED'}
def modal(self, context, event): ob = context.object obj_data = bmesh.from_edit_mesh(ob.data) div = 10000 self.offsetuv += Vector(((event.mouse_region_x - self.first_mouse.x) / div, (event.mouse_region_y - self.first_mouse.y) / div)) o = self.offsetuv oo = self.old_offsetuv for i, j in self.l: d = obj_data.faces[i].loops[j][obj_data.loops.layers.uv.active] vec = Vector((o.x - o.y, o.x + o.y)) d.uv = d.uv - Vector((oo.x, oo.y)) + vec self.old_offsetuv = vec self.first_mouse = Vector((event.mouse_region_x, event.mouse_region_y)) ob.data.update() if context.user_preferences.inputs.select_mouse == 'LEFT': mb = 'LEFTMOUSE' else: mb = 'RIGHTMOUSE' if event.type == mb and event.value == 'RELEASE': return {'FINISHED'} if event.type == 'ESC' and event.value == 'RELEASE': return {'CANCELLED'} return {'RUNNING_MODAL'}
def execute(self, context): ob = context.active_object me = ob.data bm = bmesh.from_edit_mesh(me) # Save current selection selected_verts = [] for v in bm.verts: if v.select is True: selected_verts.append(v.index) if v.index != self.vert_and_group[0]: v.select = False ob.vertex_groups.active_index = self.vert_and_group[1] bpy.ops.object.vertex_group_remove_from() # Re-select vertices for v in bm.verts: if v.index in selected_verts: v.select = True #XXX Hacky, but there's no other way to update the UI panels bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() return {'FINISHED'}
def find_uv(context): obj_data = bmesh.from_edit_mesh(context.object.data) l = [] first = 0 diff = 0 for f, face in enumerate(obj_data.faces): for v, vertex in enumerate(face.verts): if vertex.select: l.append([f, v]) if first == 0: v1 = vertex.link_loops[0].vert.co sv1 = loc3d2d(context.region, context.space_data.region_3d, v1) v2 = vertex.link_loops[0].link_loop_next.vert.co sv2 = loc3d2d(context.region, context.space_data.region_3d, v2) vres = sv2 - sv1 va = vres.angle(Vector((0.0, 1.0))) uv1 = vertex.link_loops[0][obj_data.loops.layers.uv.active].uv uv2 = vertex.link_loops[0].link_loop_next[obj_data.loops.layers.uv.active].uv uvres = uv2 - uv1 uva = uvres.angle(Vector((0.0, 1.0))) diff = uva - va first += 1 return l, diff
def offset_profile(self, ob_edit, info_profile): me = ob_edit.data bm = bmesh.from_edit_mesh(me) if self.caches_valid and self._cache_offset_infos: offset_infos, edges_orig = self.get_caches(bm) else: offset_infos, edges_orig = self.get_offset_infos(bm, ob_edit) if offset_infos is False: return {'CANCELLED'} self.save_caches(offset_infos, edges_orig) ref_verts = [v for v, _, _ in offset_infos] edges = edges_orig for width, depth, _ in info_profile: exverts, exedges, _ = self.extrude_and_pairing(bm, edges, ref_verts) self.move_verts(bm, me, width * self.magni_w, depth * self.magni_d, offset_infos, exverts, update=False) ref_verts = exverts edges = exedges bm.normal_update() bmesh.update_edit_mesh(me) self.caches_valid = False return {'FINISHED'}
def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False): """ Returns a transformed, triangulated copy of the mesh """ assert(obj.type == 'MESH') if apply_modifiers and obj.modifiers: import bpy me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False) bm = bmesh.new() bm.from_mesh(me) bpy.data.meshes.remove(me) del bpy else: me = obj.data if obj.mode == 'EDIT': bm_orig = bmesh.from_edit_mesh(me) bm = bm_orig.copy() else: bm = bmesh.new() bm.from_mesh(me) # TODO. remove all customdata layers. # would save ram if transform: bm.transform(obj.matrix_world) if triangulate: bmesh.ops.triangulate(bm, faces=bm.faces) return bm
def GeraModeloFotoSMVSDef(self, context): scn = context.scene tmpdir = tempfile.mkdtemp() tmpOBJface = tmpdir + '/scene/scene_dense_mesh_texture2.obj' # subprocess.call(['rm /tmp/DIRETORIO_FOTOS.txt'], shell=True) homeall = expanduser("~") if scn.my_tool.path == "": ERROTermFoto() bpy.context.window_manager.popup_menu(ERROruntimeFotosDef, title="Attention!", icon='INFO') else: if platform.system() == "Linux": SMVSPath = homeall + "/Programs/OrtogOnBlender/SMVS/" subprocess.call(['rm', '-rf', tmpdir + '/scene']) subprocess.call([ SMVSPath + './makescene', '-i', scn.my_tool.path, tmpdir + '/scene' ]) subprocess.call([SMVSPath + './sfmrecon', tmpdir + '/scene']) subprocess.call( [SMVSPath + './smvsrecon', '-s2', tmpdir + '/scene']) subprocess.call([ 'meshlabserver', '-i', tmpdir + '/scene/smvs-B2.ply', '-o', tmpdir + '/scene/meshlab.ply', '-s', SMVSPath + 'SMVSmeshlab.mlx', '-om' ]) subprocess.call([ SMVSPath + './texrecon', '--data_term=area', '--skip_global_seam_leveling', '--outlier_removal=gauss_damping', tmpdir + '/scene::undistorted', tmpdir + '/scene/meshlab.ply', tmpdir + '/scene/scene_dense_mesh_texture2' ]) bpy.ops.import_scene.obj(filepath=tmpOBJface, filter_glob="*.obj;*.mtl") scene_dense_mesh_texture2 = bpy.data.objects[ 'scene_dense_mesh_texture2'] bpy.ops.object.select_all(action='DESELECT') bpy.context.scene.objects.active = scene_dense_mesh_texture2 bpy.data.objects['scene_dense_mesh_texture2'].select = True bpy.ops.view3d.view_all(center=False) bpy.ops.file.pack_all() if platform.system() == "Windows": SMVSPath = 'C:/OrtogOnBlender/SMVS/' # shutil.rmtree(tmpdir+'/scene') subprocess.call([ SMVSPath + './makescene', '-i', scn.my_tool.path, tmpdir + '/scene' ]) subprocess.call([SMVSPath + './sfmrecon', tmpdir + '/scene']) subprocess.call( [SMVSPath + './smvsrecon', '-s2', tmpdir + '/scene']) subprocess.call([ SMVSPath + './fssrecon', tmpdir + '/scene/smvs-B2.ply', tmpdir + '/scene/smvs-surface.ply' ]) subprocess.call([ SMVSPath + './meshclean', '-p10', tmpdir + '/scene/smvs-surface.ply', tmpdir + '/scene/smvs-surface-clean.ply' ]) tmpPLYface = tmpdir + '/scene/smvs-surface-clean.ply' bpy.ops.import_mesh.ply(filepath=tmpPLYface, filter_glob="*.ply") smvs_surface_clean = bpy.data.objects['smvs-surface-clean'] bpy.ops.object.select_all(action='DESELECT') bpy.context.scene.objects.active = smvs_surface_clean bpy.data.objects['smvs-surface-clean'].select = True bpy.ops.view3d.view_all(center=False) bpy.ops.file.pack_all() if platform.system() == "Darwin": homemac = expanduser("~") SMVSPath = '/OrtogOnBlender/SMVSMAC/' subprocess.call(['rm', '-Rf', tmpdir + '/scene']) subprocess.call([ SMVSPath + './makescene', '-i', scn.my_tool.path, tmpdir + '/scene' ]) subprocess.call([SMVSPath + './sfmrecon', tmpdir + '/scene']) subprocess.call( [SMVSPath + './smvsrecon', '-s2', tmpdir + '/scene']) subprocess.call([ SMVSPath + './fssrecon', '-s4', tmpdir + '/scene/smvs-B2.ply', tmpdir + '/scene/smvs-surface.ply' ]) subprocess.call([ SMVSPath + './meshclean', '-p10', tmpdir + '/scene/smvs-surface.ply', tmpdir + '/scene/smvs-clean.ply' ]) subprocess.call(['rm', '-Rf', tmpdir + '/scene/tmp']) subprocess.call([ SMVSPath + './texrecon', '--data_term=area', '--skip_global_seam_leveling', '--outlier_removal=gauss_damping', tmpdir + '/scene::undistorted', tmpdir + '/scene/smvs-clean.ply', tmpdir + '/scene/scene_dense_mesh_texture2' ]) bpy.ops.import_scene.obj(filepath=tmpOBJface, filter_glob="*.obj;*.mtl") scene_dense_mesh_texture2 = bpy.data.objects[ 'scene_dense_mesh_texture2'] bpy.ops.object.select_all(action='DESELECT') bpy.context.scene.objects.active = scene_dense_mesh_texture2 bpy.data.objects['scene_dense_mesh_texture2'].select = True bpy.ops.view3d.view_all(center=False) bpy.ops.file.pack_all() print("FIX SMVS SURFACE AND MAP") photogrammetry_original = bpy.context.active_object #bpy.ops.object.duplicate() bpy.ops.object.duplicate_move() photogrammetry_original.select = True photogrammetry_copy = bpy.context.active_object print(photogrammetry_original) print(photogrammetry_copy) bpy.ops.object.modifier_add(type='DECIMATE') #bpy.context.object.modifiers["Decimate"].ratio = 0.25 bpy.context.object.modifiers["Decimate"].ratio = 0.50 bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Decimate") # Entra em modo de edição e seleciona todos os vértices ob = bpy.context.active_object bpy.ops.object.mode_set(mode='EDIT') mesh = bmesh.from_edit_mesh(ob.data) for v in mesh.verts: v.select = True # Cria UV map com espaço entre os grupos bpy.ops.uv.smart_project(island_margin=0.03) # bpy.ops.uv.smart_project(island_margin=0.3) # Faz o bake #bpy.context.scene.render.use_bake_selected_to_active = True #bpy.context.scene.render.bake_type = 'TEXTURE' #bpy.context.scene.render.bake_margin = 4 #bpy.ops.object.bake_image() #Cria imagem bpy.ops.image.new(name='UV_FACE', width=4096, height=4096, color=(0.5, 0.5, 0.5, 1), alpha=True, generated_type='BLANK', float=False, gen_context='NONE', use_stereo_3d=False) # BAKE bpy.context.scene.render.bake_margin = 2 bpy.context.scene.render.use_bake_selected_to_active = True ob.data.uv_textures['UVMap'].active = True bpy.data.scenes["Scene"].render.bake_type = "TEXTURE" bpy.ops.object.mode_set(mode='OBJECT') for d in ob.data.uv_textures['UVMap'].data: d.image = bpy.data.images['UV_FACE'] bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.object.bake_image() bpy.ops.object.mode_set(mode='OBJECT') # Oculta original photogrammetry_original.hide = True # MODIFICADORES # Smooth bpy.ops.object.modifier_add(type='SMOOTH') bpy.context.object.modifiers["Smooth"].factor = 2 bpy.context.object.modifiers["Smooth"].iterations = 3 bpy.context.object.modifiers["Smooth"].show_viewport = False # MultRes bpy.ops.object.modifier_add(type='MULTIRES') bpy.context.object.modifiers["Multires"].show_viewport = False bpy.ops.object.multires_subdivide(modifier="Multires") context = bpy.context obj = context.active_object heightTex = bpy.data.textures.new('Texture name', type='IMAGE') heightTex.image = bpy.data.images['UV_FACE'] dispMod = obj.modifiers.new("Displace", type='DISPLACE') dispMod.texture = heightTex bpy.context.object.modifiers["Displace"].texture_coords = 'UV' bpy.context.object.modifiers["Displace"].strength = 2.2 bpy.context.object.modifiers["Displace"].mid_level = 0.5 bpy.context.object.modifiers["Displace"].show_viewport = False #Comprime modificadores bpy.context.object.modifiers["Smooth"].show_expanded = False bpy.context.object.modifiers["Multires"].show_expanded = False bpy.context.object.modifiers["Displace"].show_expanded = False bpy.ops.object.shade_smooth() # bpy.ops.file.unpack_item(id_name="UV_FACE") # bpy.data.images["UV_FACE"].filepath = tmpdir+'/UV_FACE.png' # bpy.data.images["UV_FACE"].save() # bpy.ops.file.pack_all() bpy.data.images["UV_FACE"].pack(as_png=True)
def DisplaceSMVSDef(self, context): scn = context.scene print("FIX SMVS SURFACE AND MAP") photogrammetry_original = bpy.context.active_object #bpy.ops.object.duplicate() bpy.ops.object.duplicate_move() photogrammetry_original.select = True photogrammetry_copy = bpy.context.active_object print(photogrammetry_original) print(photogrammetry_copy) bpy.ops.object.modifier_add(type='DECIMATE') #bpy.context.object.modifiers["Decimate"].ratio = 0.25 bpy.context.object.modifiers["Decimate"].ratio = 0.50 bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Decimate") # Entra em modo de edição e seleciona todos os vértices ob = bpy.context.active_object bpy.ops.object.mode_set(mode='EDIT') mesh = bmesh.from_edit_mesh(ob.data) for v in mesh.verts: v.select = True # Cria UV map com espaço entre os grupos bpy.ops.uv.smart_project(island_margin=0.03) # bpy.ops.uv.smart_project(island_margin=0.3) # Faz o bake #bpy.context.scene.render.use_bake_selected_to_active = True #bpy.context.scene.render.bake_type = 'TEXTURE' #bpy.context.scene.render.bake_margin = 4 #bpy.ops.object.bake_image() #Cria imagem bpy.ops.image.new(name='UV_NEW', width=4096, height=4096, color=(0.5, 0.5, 0.5, 1), alpha=True, generated_type='BLANK', float=False, gen_context='NONE', use_stereo_3d=False) # BAKE bpy.context.scene.render.bake_margin = 2 bpy.context.scene.render.use_bake_selected_to_active = True ob.data.uv_textures['UVMap'].active = True bpy.data.scenes["Scene"].render.bake_type = "TEXTURE" bpy.ops.object.mode_set(mode='OBJECT') for d in ob.data.uv_textures['UVMap'].data: d.image = bpy.data.images['UV_NEW'] bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.object.bake_image() bpy.ops.object.mode_set(mode='OBJECT') # Oculta original photogrammetry_original.hide = True # MODIFICADORES # Smooth bpy.ops.object.modifier_add(type='SMOOTH') bpy.context.object.modifiers["Smooth"].factor = 2 bpy.context.object.modifiers["Smooth"].iterations = 3 bpy.context.object.modifiers["Smooth"].show_viewport = False # MultRes bpy.ops.object.modifier_add(type='MULTIRES') bpy.context.object.modifiers["Multires"].show_viewport = False bpy.ops.object.multires_subdivide(modifier="Multires") context = bpy.context obj = context.active_object heightTex = bpy.data.textures.new('Texture name', type='IMAGE') heightTex.image = bpy.data.images['UV_NEW'] dispMod = obj.modifiers.new("Displace", type='DISPLACE') dispMod.texture = heightTex bpy.context.object.modifiers["Displace"].texture_coords = 'UV' bpy.context.object.modifiers["Displace"].strength = 2.2 bpy.context.object.modifiers["Displace"].mid_level = 0.5 bpy.context.object.modifiers["Displace"].show_viewport = False #Comprime modificadores bpy.context.object.modifiers["Smooth"].show_expanded = False bpy.context.object.modifiers["Multires"].show_expanded = False bpy.context.object.modifiers["Displace"].show_expanded = False bpy.ops.object.shade_smooth() bpy.data.images["UV_NEW"].pack(as_png=True) bpy.ops.file.pack_all()
def execute(self, context): # enableing the auto execute bpy.context.user_preferences.system.use_scripts_auto_execute = True # saving the orignal object name object_name = bpy.context.active_object.name object_new_name = "Spin_" + object_name # separating objects If needed obj = bpy.context.active_object if bpy.context.mode == 'EDIT_MESH': bm = bmesh.from_edit_mesh(obj.data) selected_vertex = [v.index for v in bm.verts if v.select] else: selected_vertex = [v.index for v in obj.data.vertices if v.select] selected_vertex = len(selected_vertex) total_vertex = (len(obj.data.vertices)) # If we need separation if total_vertex - selected_vertex > 0: bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.separate(type='SELECTED') bpy.ops.object.mode_set(mode='OBJECT') bpy.data.objects[object_name].select = False for obj in bpy.context.scene.objects: obj.select = (obj == bpy.context.scene.objects.active) active_object = bpy.context.active_object active_object.name = object_new_name # If we don't need separation else: bpy.ops.object.mode_set(mode='OBJECT') active_object = bpy.context.active_object active_object.name = object_new_name # Apply rotation and scale bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) # set the origin of the object to the 3d cursor bpy.ops.object.origin_set(type='ORIGIN_CURSOR') # add the main empty(the one which is going to be rotated with the driver) bpy.ops.object.empty_add(type='PLAIN_AXES') # rename the main empty active_object = bpy.context.active_object active_object.name = "Object offset_main" # add the array offset object_child bpy.ops.object.empty_add(type='PLAIN_AXES') # change the name of the array offset object_child active_object = bpy.context.active_object active_object.name = "Object offset_child" # add the array offset object_parent for area in bpy.context.screen.areas: if area.type == 'VIEW_3D': for region in area.regions: if region.type == 'WINDOW': ctx = bpy.context.copy() ctx['area'] = area ctx['region'] = region bpy.ops.object.empty_add(ctx, type='PLAIN_AXES', view_align=True) # change the name of the array offset_parent active_object = bpy.context.active_object active_object.name = "Object offset_parent" # add the copy rotation constraint bpy.ops.object.constraint_add(type='COPY_ROTATION') bpy.context.object.constraints[ "Copy Rotation"].target = bpy.data.objects["Object offset_main"] bpy.context.object.constraints["Copy Rotation"].use_x = False bpy.context.object.constraints["Copy Rotation"].use_y = False bpy.context.object.constraints["Copy Rotation"].use_z = True bpy.context.object.constraints["Copy Rotation"].owner_space = 'LOCAL' # make the parent relation child_object = bpy.data.objects["Object offset_child"] parent_object = bpy.data.objects["Object offset_parent"] bpy.ops.object.select_all(action='DESELECT') child_object.select = True parent_object.select = True bpy.context.scene.objects.active = parent_object bpy.ops.object.parent_set() # select the spin object bpy.context.scene.objects.active = bpy.data.objects[object_new_name] for obj in bpy.context.scene.objects: obj.select = (obj == bpy.context.scene.objects.active) # add the array modifier bpy.ops.object.modifier_add(type='ARRAY') bpy.context.object.modifiers["Array"].use_relative_offset = False bpy.context.object.modifiers["Array"].use_object_offset = True bpy.context.object.modifiers["Array"].offset_object = bpy.data.objects[ "Object offset_child"] # add the array count custom property active_object = bpy.context.active_object active_object["Array count"] = 6 active_object["_RNA_UI"] = {"Array count": {"min": 2}} # add the driver to the array count myDriver = bpy.context.object.driver_add('modifiers["Array"].count') myDriver.driver.expression = "Array_count" newVar = myDriver.driver.variables.new() newVar.name = "Array_count" newVar.type = 'SINGLE_PROP' newVar.targets[0].id = bpy.data.objects[object_new_name] newVar.targets[0].data_path = '["Array count"]' # select the main empty bpy.context.scene.objects.active = bpy.data.objects[ "Object offset_main"] for obj in bpy.context.scene.objects: obj.select = (obj == bpy.context.scene.objects.active) # add the driver to the main empty myDriver = bpy.context.object.driver_add('rotation_euler', 2) myDriver.driver.expression = "360/Array * pi/180" newVar = myDriver.driver.variables.new() newVar.name = "Array" newVar.type = 'SINGLE_PROP' newVar.targets[0].id = bpy.data.objects[object_new_name] newVar.targets[0].data_path = 'modifiers["Array"].count' # select the spin object bpy.context.scene.objects.active = bpy.data.objects[object_new_name] for obj in bpy.context.scene.objects: obj.select = (obj == bpy.context.scene.objects.active) # cleaning the scene bpy.data.objects["Object offset_main"].hide = True bpy.data.objects["Object offset_child"].hide = True return {'FINISHED'}
def toggle_subd(self, context, obj, subds, toggle_type='TOGGLE'): self.mode = 'SUBD' if obj.mode == 'EDIT': bm = bmesh.from_edit_mesh(obj.data) bm.normal_update() bm.faces.ensure_lookup_table() else: bm = bmesh.new() bm.from_mesh(obj.data) bm.normal_update() bm.faces.ensure_lookup_table() overlay = context.space_data.overlay for subd in subds: if not subd.show_on_cage: subd.show_on_cage = True # ENABLE if not (subds[0].show_in_editmode and subds[0].show_viewport): if toggle_type in ['TOGGLE', 'ENABLE']: # enable face smoothing if necessary if not bm.faces[0].smooth: for f in bm.faces: f.smooth = True if obj.mode == 'EDIT': bmesh.update_edit_mesh(obj.data) else: bm.to_mesh(obj.data) bm.free() obj.M3.has_smoothed = True for subd in subds: subd.show_in_editmode = True subd.show_viewport = True # disable overlays, prevent doing it multiple times when batch smoothing if self.toggle_subd_overlays and toggle_type == 'TOGGLE': overlay.show_overlays = False return 'ENABLE' # DISABLE else: if toggle_type in ['TOGGLE', 'DISABLE']: # disable face smoothing if it was enabled before if obj.M3.has_smoothed: for f in bm.faces: f.smooth = False if obj.mode == 'EDIT': bmesh.update_edit_mesh(obj.data) else: bm.to_mesh(obj.data) bm.free() obj.M3.has_smoothed = False for subd in subds: subd.show_in_editmode = False subd.show_viewport = False # re-enable overlays, prevent doing it multiple times when batch smoothing if toggle_type == 'TOGGLE': overlay.show_overlays = True return 'DISABLE' print(f" INFO: SubD Smoothing is {'enabled' if toggle_type == 'ENABLE' else 'disabled'} already for {obj.name}") return toggle_type
def execute(self, context): ob = bpy.context.active_object me = ob.data bm = bmesh.from_edit_mesh(me) # Get the selected curve object and the required spline cuob = context.scene.objects[int(self.curveob)] cu = cuob.data self.splineidx = min(self.splineidx, len(cu.splines) - 1) p = cu.splines[self.splineidx].bezier_points # Get the property values res = self.resolution scale = self.scale rotation = self.rotation dscale = (1 - scale) / res drot = rotation / res # Get the matrices to convert between spaces cmat = ob.matrix_world.inverted() * cuob.matrix_world ctanmat = cmat.to_3x3().inverted().transposed() # The list of parameter values to evaluate the bezier curve at tvals = [t / res for t in range(res + 1)] # Get the first selected face, if none, cancel for f in bm.faces: if f.select: break else: return {'CANCELLED'} # Get the position vecs on the curve and tangent values bezval = [eval_bez(cmat, p, t) for t in tvals] beztan = [eval_bez_tan(ctanmat, p, t) for t in tvals] bezquat = [0] * len(tvals) # Using curve only bezquat[0] = beztan[0].to_track_quat('Z', 'Y') fquat = bezquat[0].inverted() # Calculate the min twist orientations for i in range(1, res + 1): ang = beztan[i - 1].angle(beztan[i], 0.0) if ang > 0.0: axis = beztan[i - 1].cross(beztan[i]) q = Quaternion(axis, ang) bezquat[i] = q * bezquat[i - 1] else: bezquat[i] = bezquat[i - 1].copy() # Get the faces to be modified fprev = f # no = f.normal.copy() faces = [f.copy() for i in range(res)] # Offset if we need to snap to the face offset = Vector() if not self.snapto else (f.calc_center_median() - bezval[0]) # For each of the faces created, set their vert positions and create side faces for i, data in enumerate(zip(faces, bezval[1:], bezquat[1:])): fn, pos, quat = data cen = fn.calc_center_median() rotquat = Quaternion((0, 0, 1), i * drot) for v in fn.verts: v.co = quat * rotquat * fquat * (v.co - cen) * ( 1 - (i + 1) * dscale) + pos + offset for ll, ul in zip(fprev.loops, fn.loops): ff = bm.faces.new((ll.vert, ll.link_loop_next.vert, ul.link_loop_next.vert, ul.vert)) ff.normal_update() bm.faces.remove(fprev) fprev = fn me.calc_tessface() me.calc_normals() me.update() return {'FINISHED'}
def main( context, island_margin, projection_limit, user_area_weight, use_aspect, stretch_to_bounds, ): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY global USER_STRETCH_ASPECT global USER_ISLAND_MARGIN from math import cos import time global dict_matrix dict_matrix = {} # Constants: # Takes a list of faces that make up a UV island and rotate # until they optimally fit inside a square. global ROTMAT_2D_POS_90D global ROTMAT_2D_POS_45D global RotMatStepRotation main_consts() # Create the variables. USER_PROJECTION_LIMIT = projection_limit USER_ONLY_SELECTED_FACES = True USER_SHARE_SPACE = 1 # Only for hole filling. USER_STRETCH_ASPECT = stretch_to_bounds USER_ISLAND_MARGIN = island_margin # Only for hole filling. USER_FILL_HOLES = 0 USER_FILL_HOLES_QUALITY = 50 # Only for hole filling. USER_VIEW_INIT = 0 # Only for hole filling. is_editmode = (context.active_object.mode == 'EDIT') if is_editmode: obList = [ ob for ob in [context.active_object] if ob and ob.type == 'MESH' ] else: obList = [ ob for ob in context.selected_editable_objects if ob and ob.type == 'MESH' ] USER_ONLY_SELECTED_FACES = False if not obList: raise Exception("error, no selected mesh objects") # Reuse variable if len(obList) == 1: ob = "Unwrap %i Selected Mesh" else: ob = "Unwrap %i Selected Meshes" # HACK, loop until mouse is lifted. ''' while Window.GetMouseButtons() != 0: time.sleep(10) ''' # ~ XXX if not Draw.PupBlock(ob % len(obList), pup_block): # ~ XXX return # ~ XXX del ob # Convert from being button types USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) USER_PROJECTION_LIMIT_HALF_CONVERTED = cos( (USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD) # Toggle Edit mode is_editmode = (context.active_object.mode == 'EDIT') if is_editmode: bpy.ops.object.mode_set(mode='OBJECT') # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode. if USER_SHARE_SPACE: # Sort by data name so we get consistent results obList.sort(key=lambda ob: ob.data.name) collected_islandList = [] # XXX Window.WaitCursor(1) time1 = time.time() # Tag as False so we don't operate on the same mesh twice. # XXX bpy.data.meshes.tag = False for me in bpy.data.meshes: me.tag = False for ob in obList: me = ob.data if me.tag or me.library: continue # Tag as used me.tag = True if not me.uv_layers: # Mesh has no UV Coords, don't bother. me.uv_layers.new() uv_layer = me.uv_layers.active.data me_verts = list(me.vertices) if USER_ONLY_SELECTED_FACES: meshFaces = [ thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select ] else: meshFaces = [ thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) ] # XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces))) # ======= # Generate a projection list from face normals, this is meant to be smart :) # make a list of face props that are in sync with meshFaces # Make a Face List that is sorted by area. # meshFaces = [] # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. meshFaces.sort(key=lambda a: -a.area) # remove all zero area faces while meshFaces and meshFaces[-1].area <= SMALL_NUM: # Set their UV's to 0,0 for uv in meshFaces[-1].uv: uv.zero() meshFaces.pop() if not meshFaces: continue # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. # Generate Projection Vecs # 0d is 1.0 # 180 IS -0.59846 # Initialize projectVecs if USER_VIEW_INIT: # Generate Projection projectVecs = [ Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3() ] # We add to this along the way else: projectVecs = [] newProjectVec = meshFaces[0].no newProjectMeshFaces = [] # Popping stuffs it up. # Pretend that the most unique angle is ages away to start the loop off mostUniqueAngle = -1.0 # This is popped tempMeshFaces = meshFaces[:] # This while only gathers projection vecs, faces are assigned later on. while 1: # If theres none there then start with the largest face # add all the faces that are close. for fIdx in range(len(tempMeshFaces) - 1, -1, -1): # Use half the angle limit so we don't overweight faces towards this # normal and hog all the faces. if newProjectVec.dot(tempMeshFaces[fIdx].no ) > USER_PROJECTION_LIMIT_HALF_CONVERTED: newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) # Add the average of all these faces normals as a projectionVec averageVec = Vector((0.0, 0.0, 0.0)) if user_area_weight == 0.0: for fprop in newProjectMeshFaces: averageVec += fprop.no elif user_area_weight == 1.0: for fprop in newProjectMeshFaces: averageVec += fprop.no * fprop.area else: for fprop in newProjectMeshFaces: averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight)) if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN projectVecs.append(averageVec.normalized()) # Get the next vec! # Pick the face thats most different to all existing angles :) mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. mostUniqueIndex = 0 # dummy for fIdx in range(len(tempMeshFaces) - 1, -1, -1): angleDifference = -1.0 # 180d difference. # Get the closest vec angle we are to. for p in projectVecs: temp_angle_diff = p.dot(tempMeshFaces[fIdx].no) if angleDifference < temp_angle_diff: angleDifference = temp_angle_diff if angleDifference < mostUniqueAngle: # We have a new most different angle mostUniqueIndex = fIdx mostUniqueAngle = angleDifference if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) # Now weight the vector to all its faces, will give a more direct projection # if the face its self was not representative of the normal from surrounding faces. newProjectVec = tempMeshFaces[mostUniqueIndex].no newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] else: if len(projectVecs) >= 1: # Must have at least 2 projections break # If there are only zero area faces then its possible # there are no projectionVecs if not len(projectVecs): Draw.PupMenu( 'error, no projection vecs where generated, 0 area faces can cause this.' ) return faceProjectionGroupList = [[] for i in range(len(projectVecs))] # MAP and Arrange # We know there are 3 or 4 faces here for fIdx in range(len(meshFaces) - 1, -1, -1): fvec = meshFaces[fIdx].no i = len(projectVecs) # Initialize first bestAng = fvec.dot(projectVecs[0]) bestAngIdx = 0 # Cycle through the remaining, first already done while i - 1: i -= 1 newAng = fvec.dot(projectVecs[i]) if newAng > bestAng: # Reverse logic for dotvecs bestAng = newAng bestAngIdx = i # Store the area for later use. faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) # Cull faceProjectionGroupList, # Now faceProjectionGroupList is full of faces that face match the project Vecs list for i in range(len(projectVecs)): # Account for projectVecs having no faces. if not faceProjectionGroupList[i]: continue # Make a projection matrix from a unit length vector. MatQuat = VectoQuat(projectVecs[i]) # Get the faces UV's from the projected vertex. for f in faceProjectionGroupList[i]: f_uv = f.uv for j, v in enumerate(f.v): # XXX - note, between mathutils in 2.4 and 2.5 the order changed. f_uv[j][:] = (MatQuat * v.co).xy if USER_SHARE_SPACE: # Should we collect and pack later? islandList = getUvIslands(faceProjectionGroupList, me) collected_islandList.extend(islandList) else: # Should we pack the islands for this 1 object? islandList = getUvIslands(faceProjectionGroupList, me) packIslands(islandList) # update the mesh here if we need to. # We want to pack all in 1 go, so pack now if USER_SHARE_SPACE: # XXX Window.DrawProgressBar(0.9, "Box Packing for all objects...") packIslands(collected_islandList) print("Smart Projection time: %.2f" % (time.time() - time1)) # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec" % (time.time() - time1)) # aspect correction is only done in edit mode - and only smart unwrap supports currently if is_editmode: bpy.ops.object.mode_set(mode='EDIT') if use_aspect: import bmesh aspect = context.scene.uvedit_aspect(context.active_object) if aspect[0] > aspect[1]: aspect[0] = aspect[1] / aspect[0] aspect[1] = 1.0 else: aspect[1] = aspect[0] / aspect[1] aspect[0] = 1.0 bm = bmesh.from_edit_mesh(me) uv_act = bm.loops.layers.uv.active faces = [f for f in bm.faces if f.select] for f in faces: for l in f.loops: l[uv_act].uv[0] *= aspect[0] l[uv_act].uv[1] *= aspect[1] dict_matrix.clear()
def toggle_korean_bevel(self, context, obj, toggle_type='TOGGLE'): self.mode = 'KOREAN' overlay = context.space_data.overlay # enabled auto_smooth if it isn't already if not obj.data.use_auto_smooth: obj.data.use_auto_smooth = True # get the currentl auto smooth angle angle = obj.data.auto_smooth_angle if obj.mode == 'EDIT': bm = bmesh.from_edit_mesh(obj.data) bm.normal_update() bm.faces.ensure_lookup_table() else: bm = bmesh.new() bm.from_mesh(obj.data) bm.normal_update() bm.faces.ensure_lookup_table() # ENABLE if degrees(angle) < 180: if toggle_type in ['TOGGLE', 'ENABLE']: obj.M3.smooth_angle = angle # change the auto-smooth angle obj.data.auto_smooth_angle = radians(180) # enable face smoothing if necessary if not bm.faces[0].smooth: for f in bm.faces: f.smooth = True if obj.mode == 'EDIT': bmesh.update_edit_mesh(obj.data) else: bm.to_mesh(obj.data) bm.free() obj.M3.has_smoothed = True # disable overlays if self.toggle_korean_bevel_overlays and toggle_type == 'TOGGLE': overlay.show_overlays = False return 'ENABLE' # DISABLE else: if toggle_type in ['TOGGLE', 'DISABLE']: # change the auto-smooth angle obj.data.auto_smooth_angle = obj.M3.smooth_angle # disable face smoothing if it was enabled before if obj.M3.has_smoothed: for f in bm.faces: f.smooth = False if obj.mode == 'EDIT': bmesh.update_edit_mesh(obj.data) else: bm.to_mesh(obj.data) bm.free() obj.M3.has_smoothed = False # re-enable overlays if toggle_type == 'TOGGLE': overlay.show_overlays = True return 'DISABLE' print(f" INFO: Korean Bevel Smoothing is {'enabled' if toggle_type == 'ENABLE' else 'disabled'} already for {obj.name}") return toggle_type
def create_mesh(self): try: bpy.ops.object.mode_set(mode='OBJECT') except: ok = True try: bpy.ops.object.select_all(action='DESELECT') except: ok = True z = self.z_mesh z.mesh = bpy.data.meshes.new(name=z.name) z.mesh.from_pydata(z.vertices, z.edges, z.faces) z.mesh.update(calc_tessface=True) # Safety Duplicate Name Check. z.name = z.mesh.name object_data_add(context, z.mesh) bpy.ops.object.select_pattern(pattern=z.name) z.object = bpy.context.active_object z.mesh = z.object.data bpy.ops.object.mode_set(mode = 'EDIT') # UV Assignments bm = bmesh.from_edit_mesh(z.mesh) uv_layer = bm.loops.layers.uv.verify() bm.faces.layers.tex.verify() voffset = 0 for f in bm.faces: index = f.index uv_array = z.face_uvs[index] vo = 0 for l in f.loops: luv = l[uv_layer] luv.uv = uv_array[vo] vo += 1 bmesh.update_edit_mesh(z.mesh) if z.has_armature: bpy.ops.object.mode_set(mode = 'OBJECT') if self.lock_model_on_armature_detection: z.object.lock_location = z.object.lock_rotation = z.object.lock_scale = [True, True, True] print(z.skeleton.object) old_active = bpy.context.active_object self.scene.objects.active = z.skeleton.object z.object.select = True bpy.ops.object.parent_set(type='ARMATURE') self.scene.objects.active = old_active z.object.select = False bpy.ops.object.mode_set(mode = 'OBJECT') # Weight Assignments for bone in z.skeleton.armature.bones: bpy.ops.object.vertex_group_add() vertex_group = z.object.vertex_groups.active vertex_group.name = bone.name bone_import_index = int(z.skeleton.object[bone.name]) offset_vert = 0 for vertex in z.mesh.vertices: vertex_weight_ids = z.weight_indexes[offset_vert] vertex_weights = z.weight_values[offset_vert] offset = 0 for vert_weight_id in vertex_weight_ids: if vert_weight_id == bone_import_index: verts = [] verts.append(vertex.index) vertex_group.add(verts, vertex_weights[offset], 'REPLACE') offset += 1 offset_vert += 1 if self.optimize_model: bpy.ops.object.mode_set(mode = 'EDIT') bpy.ops.mesh.remove_doubles() bpy.ops.mesh.tris_convert_to_quads() bpy.ops.object.mode_set(mode = 'OBJECT')
def main(square=False, snapToClosest=False): startTime = time.clock() obj = bpy.context.active_object me = obj.data bm = bmesh.from_edit_mesh(me) uv_layers = bm.loops.layers.uv.verify() # bm.faces.layers.tex.verify() # currently blender needs both layers. face_act = bm.faces.active targetFace = face_act #if len(bm.faces) > allowedFaces: # operator.report({'ERROR'}, "selected more than " +str(allowedFaces) +" allowed faces.") # return edgeVerts, filteredVerts, selFaces, nonQuadFaces, vertsDict, noEdge = ListsOfVerts( uv_layers, bm) if len(filteredVerts) is 0: return if len(filteredVerts) is 1: SnapCursorToClosestSelected(filteredVerts) return cursorClosestTo = CursorClosestTo(filteredVerts) #line is selected if len(selFaces) is 0: if snapToClosest is True: SnapCursorToClosestSelected(filteredVerts) return VertsDictForLine(uv_layers, bm, filteredVerts, vertsDict) if AreVectsLinedOnAxis(filteredVerts) is False: ScaleTo0OnAxisAndCursor(filteredVerts, vertsDict, cursorClosestTo) return SuccessFinished(me, startTime) MakeEqualDistanceBetweenVertsInLine(filteredVerts, vertsDict, cursorClosestTo) return SuccessFinished(me, startTime) #else: #active face checks if targetFace is None or targetFace.select is False or len( targetFace.verts) is not 4: targetFace = selFaces[0] else: for l in targetFace.loops: if l[uv_layers].select is False: targetFace = selFaces[0] break ShapeFace(uv_layers, operator, targetFace, vertsDict, square) for nf in nonQuadFaces: for l in nf.loops: luv = l[uv_layers] luv.select = False if square: FollowActiveUV(operator, me, targetFace, selFaces, 'EVEN') else: FollowActiveUV(operator, me, targetFace, selFaces) if noEdge is False: #edge has ripped so we connect it back for ev in edgeVerts: key = (round(ev.uv.x, precision), round(ev.uv.y, precision)) if key in vertsDict: ev.uv = vertsDict[key][0].uv ev.select = True return SuccessFinished(me, startTime)
def FollowActiveUV(operator, me, f_act, faces, EXTEND_MODE='LENGTH_AVERAGE'): bm = bmesh.from_edit_mesh(me) uv_act = bm.loops.layers.uv.active # our own local walker def walk_face_init(faces, f_act): # first tag all faces True (so we dont uvmap them) for f in bm.faces: f.tag = True # then tag faces arg False for f in faces: f.tag = False # tag the active face True since we begin there f_act.tag = True def walk_face(f): # all faces in this list must be tagged f.tag = True faces_a = [f] faces_b = [] while faces_a: for f in faces_a: for l in f.loops: l_edge = l.edge if (l_edge.is_manifold is True) and (l_edge.seam is False): l_other = l.link_loop_radial_next f_other = l_other.face if not f_other.tag: yield (f, l, f_other) f_other.tag = True faces_b.append(f_other) # swap faces_a, faces_b = faces_b, faces_a faces_b.clear() def walk_edgeloop(l): """ Could make this a generic function """ e_first = l.edge e = None while True: e = l.edge yield e # don't step past non-manifold edges if e.is_manifold: # welk around the quad and then onto the next face l = l.link_loop_radial_next if len(l.face.verts) == 4: l = l.link_loop_next.link_loop_next if l.edge is e_first: break else: break else: break def extrapolate_uv(fac, l_a_outer, l_a_inner, l_b_outer, l_b_inner): l_b_inner[:] = l_a_inner l_b_outer[:] = l_a_inner + ((l_a_inner - l_a_outer) * fac) def apply_uv(f_prev, l_prev, f_next): l_a = [None, None, None, None] l_b = [None, None, None, None] l_a[0] = l_prev l_a[1] = l_a[0].link_loop_next l_a[2] = l_a[1].link_loop_next l_a[3] = l_a[2].link_loop_next # l_b # +-----------+ # |(3) |(2) # | | # |l_next(0) |(1) # +-----------+ # ^ # l_a | # +-----------+ # |l_prev(0) |(1) # | (f) | # |(3) |(2) # +-----------+ # copy from this face to the one above. # get the other loops l_next = l_prev.link_loop_radial_next if l_next.vert != l_prev.vert: l_b[1] = l_next l_b[0] = l_b[1].link_loop_next l_b[3] = l_b[0].link_loop_next l_b[2] = l_b[3].link_loop_next else: l_b[0] = l_next l_b[1] = l_b[0].link_loop_next l_b[2] = l_b[1].link_loop_next l_b[3] = l_b[2].link_loop_next l_a_uv = [l[uv_act].uv for l in l_a] l_b_uv = [l[uv_act].uv for l in l_b] if EXTEND_MODE == 'LENGTH_AVERAGE': fac = edge_lengths[l_b[2].edge.index][0] / edge_lengths[ l_a[1].edge.index][0] elif EXTEND_MODE == 'LENGTH': a0, b0, c0 = l_a[3].vert.co, l_a[0].vert.co, l_b[3].vert.co a1, b1, c1 = l_a[2].vert.co, l_a[1].vert.co, l_b[2].vert.co d1 = (a0 - b0).length + (a1 - b1).length d2 = (b0 - c0).length + (b1 - c1).length try: fac = d2 / d1 except ZeroDivisionError: fac = 1.0 else: fac = 1.0 extrapolate_uv(fac, l_a_uv[3], l_a_uv[0], l_b_uv[3], l_b_uv[0]) extrapolate_uv(fac, l_a_uv[2], l_a_uv[1], l_b_uv[2], l_b_uv[1]) # ------------------------------------------- # Calculate average length per loop if needed if EXTEND_MODE == 'LENGTH_AVERAGE': bm.edges.index_update() edge_lengths = [None] * len( bm.edges) #NoneType times the length of edges list for f in faces: # we know its a quad l_quad = f.loops[:] l_pair_a = (l_quad[0], l_quad[2]) l_pair_b = (l_quad[1], l_quad[3]) for l_pair in (l_pair_a, l_pair_b): if edge_lengths[l_pair[0].edge.index] is None: edge_length_store = [-1.0] edge_length_accum = 0.0 edge_length_total = 0 for l in l_pair: if edge_lengths[l.edge.index] is None: for e in walk_edgeloop(l): if edge_lengths[e.index] is None: edge_lengths[e.index] = edge_length_store edge_length_accum += e.calc_length() edge_length_total += 1 edge_length_store[ 0] = edge_length_accum / edge_length_total # done with average length # ------------------------ walk_face_init(faces, f_act) for f_triple in walk_face(f_act): apply_uv(*f_triple) bmesh.update_edit_mesh(me, False)
def execute(self, context): active = context.active_object bm=bmesh.from_edit_mesh(active.data) # re select element under cursor bpy.ops.view3d.select(extend=True, deselect=self.deselect, toggle=False, location=self.loc) if issubclass(type(bm.select_history.active),bmesh.types.BMEdge): active_edge=bm.select_history.active #print(active_edge) # bpy.ops.mesh.loop_multi_select(ring=False) # active.data.update() # bm=bmesh.from_edit_mesh(active.data) # new_selection=[a.index for a in bm.edges if a.select] # deselect_all() # active_edge=bm.edges[active_edge_index] # active_edge.select=True og_edge=active_edge if active_edge and len(active_edge.link_faces)==2: angle=active_edge.calc_face_angle_signed() vert=active_edge.other_vert(active_edge.verts[0]) og_vert=vert other_vert=active_edge.verts[0] used=[] used.append(active_edge.verts[0]) used.append(active_edge.verts[1]) while vert: #sorted_edge=sorted([e for e in vert.link_edges],key =lambda x:True if [f for f in x.link_faces if f in active_edge.link_faces] else False) sorted_edge=sorted([e for e in vert.link_edges],key =lambda x:get_angle(x,active_edge,vert)) l=filter(lambda x:get_angle(x,active_edge,vert)<self.edge_threshold,sorted_edge) for e in l: if e!=active_edge and len(e.link_faces)==2: if abs(e.calc_face_angle_signed()-angle)<self.face_threshold: e.select = not self.deselect active_edge=e vert=[v for v in e.verts if v!=vert and v not in used] if vert: vert=vert[0] used.append(vert) break else: vert=None vert=other_vert active_edge=og_edge while vert: sorted_edge=sorted([e for e in vert.link_edges],key =lambda x:get_angle(x,active_edge,vert)) l=filter(lambda x:get_angle(x,active_edge,vert)<self.edge_threshold,sorted_edge) for e in l: if e!=active_edge and len(e.link_faces)==2: if abs(e.calc_face_angle_signed()-angle)<self.face_threshold: e.select=not self.deselect active_edge=e vert=[v for v in e.verts if v!=vert and v not in used] if vert: vert=vert[0] used.append(vert) break else: vert=None selected_verts=[v for v in bm.verts if v.select] vert=other_vert active_edge=og_edge #print(vert) split_verts=get_split_vert(vert,active_edge) edges_to_deselect=[] if split_verts: for split_vert in split_verts: deselect=False for e in split_vert.link_edges: if e.select: (length,edges)=get_path_to_self(vert,e,split_vert) if length<99999: deselect=True else: edges_to_deselect.append((length,edges)) edges_to_deselect=sorted(edges_to_deselect,key=lambda x : x[0]) if deselect: for i,e in enumerate(edges_to_deselect): for edge in e[1]: edge.select=False vert=og_vert active_edge=og_edge #print(vert) split_verts=get_split_vert(vert,active_edge) edges_to_deselect=[] if split_verts: for split_vert in split_verts: deselect=False for e in split_vert.link_edges: if e.select: (length,edges)=get_path_to_self(vert,e,split_vert) if length<99999: deselect=True else: edges_to_deselect.append((length,edges)) edges_to_deselect=sorted(edges_to_deselect,key=lambda x : x[0]) if deselect: for i,e in enumerate(edges_to_deselect): for edge in e[1]: edge.select=False if self.deselect: bpy.ops.view3d.select(deselect=True, extend=False, location=self.loc) context.active_object.data.update() else: self.report({'WARNING'},'Edge has more than 2 adjacent faces') else: self.report({'WARNING'},'Active element must be an edge!') return {'FINISHED'}
def mesh_to_bin_and_dic(self): self.json_dic["meshes"] = [] for id, mesh in enumerate([ obj for obj in bpy.context.selected_objects if obj.type == "MESH" ]): is_skin_mesh = True if len([m for m in mesh.modifiers if m.type == "ARMATURE"]) == 0: if mesh.parent is not None: if mesh.parent.type == "ARMATURE": if mesh.parent_bone != None: is_skin_mesh = False node_dic = OrderedDict({ "name": mesh.name, "translation": self.axis_blender_to_glb( mesh.location), #原点にいてほしいけどね, vectorのままだとjsonに出来ないからこうする "rotation": [0, 0, 0, 1], #このへんは規約なので "scale": [1, 1, 1], #このへんは規約なので "mesh": id, }) if is_skin_mesh: node_dic[ "skin"] = 0 #TODO: 決め打ちってどうよ:一体のモデルなのだから2つもあっては困る(から決め打ち(やめろ(やだ)) self.json_dic["nodes"].append(node_dic) mesh_node_id = len(self.json_dic["nodes"]) - 1 if is_skin_mesh: self.json_dic["scenes"][0]["nodes"].append(mesh_node_id) else: parent_node = [ node for node in self.json_dic["nodes"] if node["name"] == mesh.parent_bone ][0] if "children" in parent_node.keys(): parent_node["children"].append(mesh_node_id) else: parent_node["children"] = [mesh_node_id] relate_pos = [ mesh.location[i] - self.armature.data.bones[mesh.parent_bone].head_local[i] for i in range(3) ] self.json_dic["nodes"][mesh_node_id][ "translation"] = self.axis_blender_to_glb(relate_pos) #region hell bpy.ops.object.mode_set(mode='OBJECT') mesh.hide_viewport = False mesh.hide_select = False bpy.context.view_layer.objects.active = mesh bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(mesh.data) #region tempolary_used mat_id_dic = { mat["name"]: i for i, mat in enumerate(self.json_dic["materials"]) } material_slot_dic = { i: mat.name for i, mat in enumerate(mesh.material_slots) } node_id_dic = { node["name"]: i for i, node in enumerate(self.json_dic["nodes"]) } def joint_id_from_node_name_solver(node_name): try: node_id = node_id_dic[node_name] joint_id = self.json_dic["skins"][0]["joints"].index( node_id) except ValueError: joint_id = -1 #存在しないボーンを指してる場合は-1を返す print("{} bone may be not exist".format(node_name)) return joint_id v_group_name_dic = { i: vg.name for i, vg in enumerate(mesh.vertex_groups) } fmin, fmax = float_info.min, float_info.max unique_vertex_id = 0 unique_vertex_id_dic = { } #loop verts id : base vertex id (uv違いを同じ頂点番号で管理されているので) unique_vertex_dic = { } # {(uv...,vertex_index):unique_vertex_id} (uvと頂点番号が同じ頂点は同じものとして省くようにする) uvlayers_dic = { i: uvlayer.name for i, uvlayer in enumerate(mesh.data.uv_layers) } def fetch_morph_vertex_normal_difference(): #TODO 実装 morph_normal_diff_dic = {} vert_base_normal_dic = OrderedDict() for kb in mesh.data.shape_keys.key_blocks: vert_base_normal_dic.update( {kb.name: kb.normals_vertex_get()}) for k, v in vert_base_normal_dic.items(): if k == "Basis": continue values = [] for vert_morph_normal, vert_base_normal in zip( zip(*[iter(v)] * 3), zip(*[iter(vert_base_normal_dic["Basis"])] * 3)): values.append([ vert_morph_normal[i] - vert_base_normal[i] for i in range(3) ]) morph_normal_diff_dic.update({k: values}) return morph_normal_diff_dic #endregion tempolary_used primitive_index_bin_dic = OrderedDict( {mat_id_dic[mat.name]: b"" for mat in mesh.material_slots}) primitive_index_vertex_count = OrderedDict( {mat_id_dic[mat.name]: 0 for mat in mesh.material_slots}) if mesh.data.shape_keys is None: shape_pos_bin_dic = {} shape_normal_bin_dic = {} shape_min_max_dic = {} morph_normal_diff_dic = {} else: shape_pos_bin_dic = OrderedDict({ shape.name: b"" for shape in mesh.data.shape_keys.key_blocks[1:] }) #0番目Basisは省く shape_normal_bin_dic = OrderedDict({ shape.name: b"" for shape in mesh.data.shape_keys.key_blocks[1:] }) shape_min_max_dic = OrderedDict({ shape.name: [[fmax, fmax, fmax], [fmin, fmin, fmin]] for shape in mesh.data.shape_keys.key_blocks[1:] }) morph_normal_diff_dic = fetch_morph_vertex_normal_difference( ) #{morphname:{vertexid:[diff_X,diff_y,diff_z]}} position_bin = b"" position_min_max = [[fmax, fmax, fmax], [fmin, fmin, fmin]] normal_bin = b"" joints_bin = b"" weights_bin = b"" texcord_bins = {id: b"" for id in uvlayers_dic.keys()} f_vec4_packer = struct.Struct("<ffff").pack f_vec3_packer = struct.Struct("<fff").pack f_pair_packer = struct.Struct("<ff").pack I_scalar_packer = struct.Struct("<I").pack H_vec4_packer = struct.Struct("<HHHH").pack def min_max(minmax, position): for i in range(3): minmax[0][i] = position[ i] if position[i] < minmax[0][i] else minmax[0][i] minmax[1][i] = position[ i] if position[i] > minmax[1][i] else minmax[1][i] return for face in bm.faces: #このへん絶対超遅い for loop in face.loops: uv_list = [] for uvlayer_name in uvlayers_dic.values(): uv_layer = bm.loops.layers.uv[uvlayer_name] uv_list += [loop[uv_layer].uv[0], loop[uv_layer].uv[1]] cached_vert_id = unique_vertex_dic.get( (*uv_list, loop.vert.index)) #keyがなければNoneを返す if cached_vert_id is not None: primitive_index_bin_dic[mat_id_dic[material_slot_dic[ face.material_index]]] += I_scalar_packer( cached_vert_id) primitive_index_vertex_count[mat_id_dic[ material_slot_dic[face.material_index]]] += 1 continue else: unique_vertex_dic[(*uv_list, loop.vert.index)] = unique_vertex_id for id, uvlayer_name in uvlayers_dic.items(): uv_layer = bm.loops.layers.uv[uvlayer_name] uv = loop[uv_layer].uv texcord_bins[id] += f_pair_packer( uv[0], -uv[1]) #blenderとglbのuvは上下逆 for shape_name in shape_pos_bin_dic.keys(): shape_layer = bm.verts.layers.shape[shape_name] morph_pos = self.axis_blender_to_glb([ loop.vert[shape_layer][i] - loop.vert.co[i] for i in range(3) ]) shape_pos_bin_dic[shape_name] += f_vec3_packer( *morph_pos) shape_normal_bin_dic[shape_name] += f_vec3_packer( *self.axis_blender_to_glb( morph_normal_diff_dic[shape_name][ loop.vert.index])) min_max(shape_min_max_dic[shape_name], morph_pos) if is_skin_mesh: magic = 0 joints = [magic, magic, magic, magic] weights = [0.0, 0.0, 0.0, 0.0] if len(mesh.data.vertices[ loop.vert.index].groups) >= 5: print( "vertex weights are less than 4 in {}".format( mesh.name)) raise Exception for v_group in mesh.data.vertices[ loop.vert.index].groups: joint_id = joint_id_from_node_name_solver( v_group_name_dic[v_group.group]) if joint_id == -1: #存在しないボーンを指してる場合は-1を返されてるので、その場合は飛ばす continue weights.pop(3) weights.insert(0, v_group.weight) joints.pop(3) joints.insert(0, joint_id) nomalize_fact = sum(weights) try: weights = [ weights[i] / nomalize_fact for i in range(4) ] except ZeroDivisionError: print("vertex has no weight in {}".format( mesh.name)) raise ZeroDivisionError if sum(weights) < 1: weights[0] += 1 - sum(weights) joints_bin += H_vec4_packer(*joints) weights_bin += f_vec4_packer(*weights) vert_location = self.axis_blender_to_glb(loop.vert.co) position_bin += f_vec3_packer(*vert_location) min_max(position_min_max, vert_location) normal_bin += f_vec3_packer( *self.axis_blender_to_glb(loop.vert.normal)) unique_vertex_id_dic[unique_vertex_id] = loop.vert.index primitive_index_bin_dic[mat_id_dic[material_slot_dic[ face.material_index]]] += I_scalar_packer( unique_vertex_id) primitive_index_vertex_count[mat_id_dic[material_slot_dic[ face.material_index]]] += 1 unique_vertex_id += 1 #DONE :index position, uv, normal, position morph,JOINT WEIGHT #TODO: morph_normal, v_color...? primitive_glbs_dic = OrderedDict({ mat_id: Glb_bin(index_bin, "SCALAR", GL_CONSTANS.UNSIGNED_INT, primitive_index_vertex_count[mat_id], None, self.glb_bin_collector) for mat_id, index_bin in primitive_index_bin_dic.items() if index_bin != b"" }) pos_glb = Glb_bin(position_bin, "VEC3", GL_CONSTANS.FLOAT, unique_vertex_id, position_min_max, self.glb_bin_collector) nor_glb = Glb_bin(normal_bin, "VEC3", GL_CONSTANS.FLOAT, unique_vertex_id, None, self.glb_bin_collector) uv_glbs = [ Glb_bin(texcood_bin, "VEC2", GL_CONSTANS.FLOAT, unique_vertex_id, None, self.glb_bin_collector) for texcood_bin in texcord_bins.values() ] if is_skin_mesh: joints_glb = Glb_bin(joints_bin, "VEC4", GL_CONSTANS.UNSIGNED_SHORT, unique_vertex_id, None, self.glb_bin_collector) weights_glb = Glb_bin(weights_bin, "VEC4", GL_CONSTANS.FLOAT, unique_vertex_id, None, self.glb_bin_collector) if len(shape_pos_bin_dic.keys()) != 0: morph_pos_glbs = [ Glb_bin(morph_pos_bin, "VEC3", GL_CONSTANS.FLOAT, unique_vertex_id, morph_minmax, self.glb_bin_collector) for morph_pos_bin, morph_minmax in zip( shape_pos_bin_dic.values(), shape_min_max_dic.values()) ] morph_normal_glbs = [ Glb_bin(morph_normal_bin, "VEC3", GL_CONSTANS.FLOAT, unique_vertex_id, None, self.glb_bin_collector) for morph_normal_bin in shape_normal_bin_dic.values() ] primitive_list = [] for primitive_id, index_glb in primitive_glbs_dic.items(): primitive = OrderedDict({"mode": 4}) primitive["material"] = primitive_id primitive["indices"] = index_glb.accessor_id primitive["attributes"] = { "POSITION": pos_glb.accessor_id, "NORMAL": nor_glb.accessor_id, } if is_skin_mesh: primitive["attributes"].update({ "JOINTS_0": joints_glb.accessor_id, "WEIGHTS_0": weights_glb.accessor_id }) primitive["attributes"].update({ "TEXCOORD_{}".format(i): uv_glb.accessor_id for i, uv_glb in enumerate(uv_glbs) }) if len(shape_pos_bin_dic.keys()) != 0: primitive["targets"] = [{ "POSITION": morph_pos_glb.accessor_id, "NORMAL": morph_normal_glb.accessor_id } for morph_pos_glb, morph_normal_glb in zip( morph_pos_glbs, morph_normal_glbs)] primitive["extras"] = { "targetNames": [ shape_name for shape_name in shape_pos_bin_dic.keys() ] } primitive_list.append(primitive) self.json_dic["meshes"].append( OrderedDict({ "name": mesh.name, "primitives": primitive_list })) #endregion hell bpy.ops.object.mode_set(mode='OBJECT') return
def modal(self, context, event): context.area.tag_redraw() preferences = context.preferences addon_prefs = preferences.addons[__package__].preferences lin_def_settings = context.scene.mi_ldeformer_settings region = context.region rv3d = context.region_data m_coords = event.mouse_region_x, event.mouse_region_y active_obj = context.active_object bm = bmesh.from_edit_mesh(active_obj.data) # update check if lin_def_settings.manual_update is True: if event.type == 'U': if event.value == 'PRESS': self.do_update = True else: self.do_update = False else: self.do_update = True # tooltip tooltip_text = None if lin_def_settings.manual_update is True and self.tool_mode not in { 'IDLE', 'MOVE_POINT' }: tooltip_text = "Press U key to udate!" else: tooltip_text = "I:Invert, Z:Z-Constraint, X:X-Constraint, S:Scale, Shift-S:ScaleForward, G:Move, R:Rotate, B:Bend, Shift-B:BendSpiral, T:Tape, Shift-T:Twist, Ctrl+Z:Undo, Ctrl+Shift+Z:Redo" context.area.header_text_set(tooltip_text) keys_pass = mi_inputs.get_input_pass(mi_inputs.pass_keys, addon_prefs.key_inputs, event) # key pressed if self.tool_mode == 'IDLE' and event.value == 'PRESS' and keys_pass is False: if event.type in {'LEFTMOUSE', 'SELECTMOUSE'}: if self.lw_tool: # pick linear widget point picked_point = l_widget.pick_lw_point( context, m_coords, self.lw_tool) if picked_point: self.deform_mouse_pos = Vector(m_coords) self.active_lw_point = picked_point self.tool_mode = 'MOVE_POINT' else: picked_point = ut_base.get_mouse_on_plane( context, self.start_work_center, None, m_coords) if picked_point: self.lw_tool = l_widget.MI_Linear_Widget() self.lw_tool.start_point = l_widget.MI_LW_Point( picked_point.copy()) self.lw_tool.middle_point = l_widget.MI_LW_Point( picked_point.copy()) self.lw_tool.end_point = l_widget.MI_LW_Point( picked_point) self.active_lw_point = self.lw_tool.end_point self.tool_mode = 'MOVE_POINT' elif event.type in {'S', 'G', 'R', 'B', 'T'}: # set tool type if event.type == 'S': if event.shift: self.tool_mode = 'SCALE_FRONT' else: self.tool_mode = 'SCALE_ALL' elif event.type == 'R': self.tool_mode = 'ROTATE_ALL' elif event.type == 'G': self.tool_mode = 'MOVE_ALL' elif event.type == 'B': if event.shift: self.tool_mode = 'BEND_SPIRAL' else: self.tool_mode = 'BEND_ALL' elif event.type == 'T': if event.shift: self.tool_mode = 'TWIST' else: self.tool_mode = 'TAPE' # get tool verts if self.tool_mode in {'SCALE_FRONT', 'TAPE'}: # do not clamp for SCALE_FRONT mode self.apply_tool_verts = l_widget.get_tool_verts( self.lw_tool, self.work_verts, bm, active_obj, False, True) else: self.apply_tool_verts = l_widget.get_tool_verts( self.lw_tool, self.work_verts, bm, active_obj, True, True) # set some settings for tools if self.tool_mode in {'SCALE_ALL', 'SCALE_FRONT', 'TAPE'}: self.deform_mouse_pos = Vector(m_coords) elif self.tool_mode == 'MOVE_ALL': mouse_pos_3d = ut_base.get_mouse_on_plane( context, self.lw_tool.start_point.position, None, m_coords) self.deform_vec_pos = mouse_pos_3d # 3d location elif self.tool_mode in { 'ROTATE_ALL', 'TWIST', 'BEND_ALL', 'BEND_SPIRAL' }: start_2d = view3d_utils.location_3d_to_region_2d( region, rv3d, self.lw_tool.start_point.position) self.deform_vec_pos = ( Vector(m_coords) - start_2d).normalized() # 2d direction self.deform_mouse_pos = 0.0 # we will use it as angle counter if self.tool_mode in {'BEND_SPIRAL', 'BEND_ALL'}: self.bend_scale_len = (Vector(m_coords) - start_2d).length #return {'RUNNING_MODAL'} elif event.type in {'Z', 'X'} and self.lw_tool: if event.type == 'Z' and event.ctrl: if event.shift: redo_history(bm, self.h_undo, self.h_redo, active_obj) else: undo_history(bm, self.h_undo, self.h_redo, active_obj) else: pre_verts = [bm.verts[v_id] for v_id in self.work_verts] if event.type == 'X': if self.lw_tool_axis: if self.lw_tool_axis == 'X': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'X_Left', 1.0) self.lw_tool_axis = 'X_Left' elif self.lw_tool_axis == 'X_Left': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'X_Right', 1.0) ## revert direction #stp = self.lw_tool.start_point.position.copy() #self.lw_tool.start_point.position = self.lw_tool.end_point.position #self.lw_tool.end_point.position = stp self.lw_tool_axis = 'X_Right' elif self.lw_tool_axis == 'X_Right': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'X', 1.0) self.lw_tool_axis = 'X' else: l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'X', 1.0) self.lw_tool_axis = 'X' else: l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'X', 1.0) self.lw_tool_axis = 'X' else: if self.lw_tool_axis: if self.lw_tool_axis == 'Z': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'Z_Top', 1.0) self.lw_tool_axis = 'Z_Top' elif self.lw_tool_axis == 'Z_Top': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'Z_Bottom', 1.0) ## revert direction #stp = self.lw_tool.start_point.position.copy() #self.lw_tool.start_point.position = self.lw_tool.end_point.position #self.lw_tool.end_point.position = stp self.lw_tool_axis = 'Z_Bottom' elif self.lw_tool_axis == 'Z_Bottom': l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'Z', 1.0) self.lw_tool_axis = 'Z' else: l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'Z', 1.0) self.lw_tool_axis = 'Z' else: l_widget.setup_lw_tool(rv3d, self.lw_tool, active_obj, pre_verts, 'Z', 1.0) self.lw_tool_axis = 'Z' elif event.type == 'I' and self.lw_tool: start_copy = self.lw_tool.start_point.position.copy() self.lw_tool.start_point.position = self.lw_tool.end_point.position self.lw_tool.end_point.position = start_copy # TOOL WORK! if self.tool_mode == 'MOVE_POINT': if event.value == 'RELEASE': self.tool_mode = 'IDLE' return {'RUNNING_MODAL'} else: # move points new_point_pos = ut_base.get_mouse_on_plane( context, self.active_lw_point.position, None, m_coords) if self.active_lw_point.position == self.lw_tool.start_point.position or self.active_lw_point.position == self.lw_tool.end_point.position: self.active_lw_point.position = new_point_pos l_widget.update_middle_point(self.lw_tool) elif self.active_lw_point.position == self.lw_tool.middle_point.position: self.lw_tool.start_point.position += new_point_pos - self.active_lw_point.position self.lw_tool.end_point.position += new_point_pos - self.active_lw_point.position self.lw_tool.middle_point.position = new_point_pos return {'RUNNING_MODAL'} elif self.tool_mode in {'SCALE_ALL', 'SCALE_FRONT', 'TAPE'}: if event.value == 'RELEASE' and event.type in { 'LEFTMOUSE', 'SELECTMOUSE' }: bm.normal_update() # add to undo history self.h_redo.clear() pre_work_verts = [bm.verts[v_id] for v_id in self.work_verts] add_history(pre_work_verts, self.h_undo) self.tool_mode = 'IDLE' elif self.do_update: # move points start_point_2d = view3d_utils.location_3d_to_region_2d( region, rv3d, self.lw_tool.start_point.position) if start_point_2d: tool_dist = (start_point_2d - self.deform_mouse_pos).length now_dist = (start_point_2d - Vector(m_coords)).length apply_value = (now_dist - tool_dist) / tool_dist if apply_value != 0.0: tool_orig = active_obj.matrix_world.inverted( ) @ self.lw_tool.start_point.position tool_end = active_obj.matrix_world.inverted( ) @ self.lw_tool.end_point.position tool_vec = tool_end - tool_orig tool_dir = (tool_end - tool_orig).normalized() for vert_data in self.apply_tool_verts: scale_vec = None scale_value = vert_data[1] if self.tool_mode == 'SCALE_ALL': scale_vec = (vert_data[2] - tool_orig) elif self.tool_mode == 'SCALE_FRONT': scale_vec = (tool_end - tool_orig) else: # TAPE scale_vec = vert_data[2] - ( tool_orig + (tool_dir * vert_data[1] * (tool_vec).length)) scale_value = min(1.0, vert_data[1]) bm.verts[vert_data[0]].co = vert_data[2] + ( scale_vec * (scale_value * apply_value)) bm.normal_update() bmesh.update_edit_mesh(active_obj.data) self.do_update = False return {'RUNNING_MODAL'} elif self.tool_mode == 'MOVE_ALL': if event.value == 'RELEASE' and event.type in { 'LEFTMOUSE', 'SELECTMOUSE' }: bm.normal_update() # add to undo history self.h_redo.clear() pre_work_verts = [bm.verts[v_id] for v_id in self.work_verts] add_history(pre_work_verts, self.h_undo) self.tool_mode = 'IDLE' elif self.do_update: mouse_pos_3d = ut_base.get_mouse_on_plane( context, self.lw_tool.start_point.position, None, m_coords) mouse_pos_3d = active_obj.matrix_world.inverted( ) @ mouse_pos_3d start_pos = active_obj.matrix_world.inverted( ) @ self.lw_tool.start_point.position orig_pos = active_obj.matrix_world.inverted( ) @ self.deform_vec_pos orig_vec = orig_pos - start_pos move_vec = (mouse_pos_3d - start_pos) - orig_vec for vert_data in self.apply_tool_verts: move_value = vert_data[1] bm.verts[vert_data[0]].co = vert_data[2] + (move_vec * move_value) bm.normal_update() bmesh.update_edit_mesh(active_obj.data) self.do_update = False return {'RUNNING_MODAL'} elif self.tool_mode in { 'ROTATE_ALL', 'TWIST', 'BEND_ALL', 'BEND_SPIRAL' }: if event.value == 'RELEASE' and event.type in { 'LEFTMOUSE', 'SELECTMOUSE' }: bm.normal_update() # add to undo history self.h_redo.clear() pre_work_verts = [bm.verts[v_id] for v_id in self.work_verts] add_history(pre_work_verts, self.h_undo) self.tool_mode = 'IDLE' elif self.do_update: m_coords = Vector( m_coords) # convert into vector for operations start_2d = view3d_utils.location_3d_to_region_2d( region, rv3d, self.lw_tool.start_point.position) new_vec_dir = (m_coords - start_2d).normalized() rot_angle = new_vec_dir.angle(self.deform_vec_pos) start_3d = self.lw_tool.start_point.position end_3d = self.lw_tool.end_point.position if rot_angle != 0.0: # check for left or right direction to rotate vec_check_1 = Vector((new_vec_dir[0], new_vec_dir[1], 0)) vec_check_2 = Vector( (new_vec_dir[0] - self.deform_vec_pos[0], new_vec_dir[1] - self.deform_vec_pos[1], 0)) checker_side_dir = vec_check_1.cross( vec_check_2).normalized()[2] if checker_side_dir > 0.0: rot_angle = -rot_angle start_pos = self.lw_tool.start_point.position rot_dir = None if self.tool_mode == 'ROTATE_FRONT' or self.tool_mode == 'TWIST': # ROTATE_FRONT code rot_dir = (end_3d - start_3d).normalized() else: rot_dir = (rv3d.view_rotation @ Vector( (0.0, 0.0, -1.0))).normalized() rot_angle += self.deform_mouse_pos # add rot angle bend_side_dir = None faloff_len = None spiral_value = 0.0 # only for BEND_SPIRAL bend_scale_value = 1.0 # only for BEND_ALL if self.tool_mode == 'BEND_ALL' or self.tool_mode == 'BEND_SPIRAL': bend_side_dir = (((end_3d - start_3d).normalized() ).cross(rot_dir)).normalized() faloff_len = end_3d - start_3d if self.tool_mode == 'BEND_SPIRAL': val_scale = None if rot_angle > 0.0: val_scale = (1.0 - ((m_coords - start_2d).length / self.bend_scale_len)) else: val_scale = (((m_coords - start_2d).length / self.bend_scale_len)) spiral_value = 1.0 - (faloff_len.length * val_scale) else: val_scale = (((m_coords - start_2d).length / self.bend_scale_len)) bend_scale_value = ((val_scale)) do_bend = False if self.tool_mode == 'BEND_ALL' or self.tool_mode == 'BEND_SPIRAL': do_bend = True for vert_data in self.apply_tool_verts: apply_value = vert_data[1] final_apply_value = rot_angle * apply_value # do rotation if final_apply_value != 0.0: rot_mat = Matrix.Rotation(final_apply_value, 3, rot_dir) vert = bm.verts[vert_data[0]] if do_bend: vert_temp = ( active_obj.matrix_world @ vert_data[2]) - ( (faloff_len) * apply_value) back_offset = ( ((faloff_len).length / (final_apply_value)) + spiral_value) * ( apply_value * bend_scale_value) vert_temp += bend_side_dir * back_offset vert.co = vert_temp else: # set original position vert.co[0] = vert_data[2][0] vert.co[1] = vert_data[2][1] vert.co[2] = vert_data[2][2] # ROTATE VERTS! if do_bend: vert.co = rot_mat @ ( (vert.co) - start_pos) + start_pos back_offset = ( (faloff_len).length / (final_apply_value)) * (apply_value * bend_scale_value) vert.co = active_obj.matrix_world.inverted( ) @ (vert.co - (bend_side_dir * back_offset)) else: vert.co = active_obj.matrix_world.inverted( ) @ (rot_mat @ ( (active_obj.matrix_world @ vert.co) - start_pos) + start_pos) self.deform_vec_pos = new_vec_dir self.deform_mouse_pos = rot_angle # set new angle rotation for next step bm.normal_update() bmesh.update_edit_mesh(active_obj.data) self.do_update = False return {'RUNNING_MODAL'} else: if event.value == 'RELEASE' and event.type in { 'LEFTMOUSE', 'SELECTMOUSE' }: self.tool_mode = 'IDLE' return {'RUNNING_MODAL'} # get keys if keys_pass is True: # allow navigation return {'PASS_THROUGH'} elif event.type in {'RIGHTMOUSE', 'ESC'}: context.space_data.show_gizmo = self.manipulator # bpy.types.SpaceView3D.draw_handler_remove(self.lin_deform_handle_3d, 'WINDOW') bpy.types.SpaceView3D.draw_handler_remove( self.lin_deform_handle_2d, 'WINDOW') context.area.header_text_set(None) return {'FINISHED'} return {'RUNNING_MODAL'}
def elem_count(context): bm = bmesh.from_edit_mesh(context.edit_object.data) return len(bm.verts), len(bm.edges), len(bm.faces)
def getPercent(obj, flip_p, per_v, data, scene): """Calculates a Percentage Distance between 2 Vectors. Calculates a point that lies a set percentage between two given points using standard Numpy Routines. Works for either 2 vertices for an object in Edit mode or 2 selected objects in Object mode. Args: obj: The Object under consideration flip_p: Setting this to True measures the percentage starting from the second vector per_v: Percentage Input Value data: pg.flip, pg.percent scene variables & Operational Mode scene: Context Scene Returns: World Vector. """ pg = scene.pdt_pg if obj.mode == "EDIT": bm = bmesh.from_edit_mesh(obj.data) verts = [v for v in bm.verts if v.select] if len(verts) == 2: actV = verts[0].co othV = verts[1].co if actV is None: pg.error = PDT_ERR_VERT_MODE bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR") return None else: pg.error = PDT_ERR_SEL_2_V_1_E + str(len(verts)) + " Vertices" bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR") return None p1 = np.array([actV.x, actV.y, actV.z]) p2 = np.array([othV.x, othV.y, othV.z]) if obj.mode == "OBJECT": objs = bpy.context.view_layer.objects.selected if len(objs) != 2: pg.error = PDT_ERR_SEL_2_OBJS + str(len(objs)) + ")" bpy.context.window_manager.popup_menu(oops, title="Error", icon="ERROR") return None p1 = np.array([ objs[-1].matrix_world.decompose()[0].x, objs[-1].matrix_world.decompose()[0].y, objs[-1].matrix_world.decompose()[0].z, ]) p2 = np.array([ objs[-2].matrix_world.decompose()[0].x, objs[-2].matrix_world.decompose()[0].y, objs[-2].matrix_world.decompose()[0].z, ]) p4 = np.array([0, 0, 0]) p3 = p2 - p1 _per_v = per_v if (flip_p and data != "MV") or data == "MV": _per_v = 100 - per_v V = (p4 + p3) * (_per_v / 100) + p1 return Vector((V[0], V[1], V[2]))
import bpy import bmesh obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) # notice in Bmesh polygons are called faces bm.faces[4].select = True # select index 4 # Show the updates in the viewport bmesh.update_edit_mesh(me, True) bpy.ops.mesh.select_linked(limit=True) bpy.ops.mesh.separate()
def get_orientation(context): obj = bpy.context.view_layer.objects.active bm = bmesh.from_edit_mesh(obj.data) uv_layer = bm.loops.layers.uv.verify() faces = list() #MAKE FACE LIST for face in bm.faces: if face.select: faces.append(face) for face in faces: xmin, xmax = face.loops[0][uv_layer].uv.x, face.loops[0][uv_layer].uv.x ymin, ymax = face.loops[0][uv_layer].uv.y, face.loops[0][uv_layer].uv.y for vert in face.loops: xmin = min(xmin, vert[uv_layer].uv.x) xmax = max(xmax, vert[uv_layer].uv.x) ymin = min(ymin, vert[uv_layer].uv.y) ymax = max(ymax, vert[uv_layer].uv.y) # corners: # 3 2 # 0 1 bound0 = Vector((xmin, ymin)) bound1 = Vector((xmax, ymin)) bound2 = Vector((xmax, ymax)) bound3 = Vector((xmin, ymax)) middle = Vector( (((xmax + xmin) / 2) - bound0.x, ((ymax + ymin) / 2) - bound0.y)) print("find corner 0:") distance = middle.length corner0 = faces[0].loops[0] for f in faces: for loop in f.loops: loop_uv = loop[uv_layer] vertuv = Vector((loop_uv.uv.x - bound0.x, loop_uv.uv.y - bound0.y)) tempdistance = vertuv.length if tempdistance <= distance: distance = tempdistance corner0 = loop print(corner0[uv_layer].uv) print("find corner 1:") distance = middle.length corner1 = faces[0].loops[0] for f in faces: for loop in f.loops: loop_uv = loop[uv_layer] vertuv = Vector((loop_uv.uv.x - bound1.x, loop_uv.uv.y - bound1.y)) tempdistance = vertuv.length if tempdistance <= distance: distance = tempdistance corner1 = loop print(corner1[uv_layer].uv) print("find corner 2:") distance = middle.length corner2 = faces[0].loops[0] for f in faces: for loop in f.loops: loop_uv = loop[uv_layer] vertuv = Vector((loop_uv.uv.x - bound2.x, loop_uv.uv.y - bound2.y)) tempdistance = vertuv.length if tempdistance <= distance: distance = tempdistance corner2 = loop print(corner2[uv_layer].uv) print("find corner 3:") distance = middle.length corner3 = faces[0].loops[0] for f in faces: for loop in f.loops: loop_uv = loop[uv_layer] vertuv = Vector((loop_uv.uv.x - bound3.x, loop_uv.uv.y - bound3.y)) tempdistance = vertuv.length if tempdistance <= distance: distance = tempdistance corner3 = loop print(corner3[uv_layer].uv) #orientations: # 3 2 0 3 1 0 2 1 # 0 1 1 2 2 3 3 0 #1st case: if corner3.vert.co.z >= corner0.vert.co.z and corner2.vert.co.z >= corner1.vert.co.z and corner3.vert.co.z >= corner1.vert.co.z and corner2.vert.co.z >= corner0.vert.co.z: print("case1") if corner0.vert.co.z >= corner1.vert.co.z and corner3.vert.co.z >= corner2.vert.co.z and corner0.vert.co.z >= corner2.vert.co.z and corner3.vert.co.z >= corner1.vert.co.z: print("case2") for face in faces: for loop in face.loops: newx = loop[uv_layer].uv.y newy = -loop[uv_layer].uv.x loop[uv_layer].uv.x = newx loop[uv_layer].uv.y = newy if corner1.vert.co.z >= corner2.vert.co.z and corner0.vert.co.z >= corner3.vert.co.z and corner1.vert.co.z >= corner3.vert.co.z and corner0.vert.co.z >= corner2.vert.co.z: print("case3") for face in faces: for loop in face.loops: newx = -loop[uv_layer].uv.x newy = -loop[uv_layer].uv.y loop[uv_layer].uv.x = newx loop[uv_layer].uv.y = newy if corner2.vert.co.z >= corner3.vert.co.z and corner1.vert.co.z >= corner0.vert.co.z and corner2.vert.co.z >= corner0.vert.co.z and corner1.vert.co.z >= corner3.vert.co.z: print("case4") for face in faces: for loop in face.loops: newx = -loop[uv_layer].uv.y newy = loop[uv_layer].uv.x loop[uv_layer].uv.x = newx loop[uv_layer].uv.y = newy return None
def command_parse(context): """Parse Command Input. Args: context: Blender bpy.context instance. Returns: pg: PDT Parameters Group - our variables values_out: The Output Values as a list of numbers obj: The Active Object obj_loc: The object's location in 3D space bm: The object's Bmesh verts: The object's selected vertices, or selected history vertices. """ scene = context.scene pg = scene.pdt_pg command = pg.command.strip() operation = command[0].upper() mode = command[1].lower() values = command[2:].split(",") mode_sel = pg.select obj = context.view_layer.objects.active ind = 0 for v in values: try: _ = float(v) good = True except ValueError: values[ind] = "0.0" ind = ind + 1 if mode == "n": # View relative mode if pg.plane == "XZ": values = [0.0, values[0], 0.0] elif pg.plane == "YZ": values = [values[0], 0.0, 0.0] elif pg.plane == "XY": values = [0.0, 0.0, values[0]] else: if "-" in values[0]: values = [0.0, 0.0, values[0][1:]] else: values = [0.0, 0.0, f"-{values[0]}"] # Apply System Rounding decimal_places = context.preferences.addons[ __package__].preferences.pdt_input_round values_out = [str(round(float(v), decimal_places)) for v in values] bm = "No Bmesh" obj_loc = Vector((0, 0, 0)) verts = [] if mode_sel == 'REL' and operation not in {"C", "P"}: pg.select = 'SEL' mode_sel = 'SEL' if mode == "a" and operation not in {"C", "P"}: # Place new Vertex, or Extrude Vertices by Absolute Coords. if mode_sel == 'REL': pg.select = 'SEL' mode_sel = 'SEL' if obj is not None: if obj.mode == "EDIT": bm = bmesh.from_edit_mesh(obj.data) obj_loc = obj.matrix_world.decompose()[0] verts = [] else: if operation != "G": pg.error = PDT_OBJ_MODE_ERROR context.window_manager.popup_menu(oops, title="Error", icon="ERROR") raise PDT_ObjectModeError else: pg.error = PDT_ERR_NO_ACT_OBJ context.window_manager.popup_menu(oops, title="Error", icon="ERROR") raise PDT_NoObjectError if mode_sel == 'SEL' and mode not in {"a"}: # All other options except Cursor or Pivot by Absolute # These options require no object, etc. bm, good = obj_check(obj, scene, operation) if good and obj.mode == 'EDIT': obj_loc = obj.matrix_world.decompose()[0] if len(bm.select_history) == 0 or operation == "G": verts = [v for v in bm.verts if v.select] if len(verts) == 0: pg.error = PDT_ERR_NO_SEL_GEOM context.window_manager.popup_menu(oops, title="Error", icon="ERROR") raise PDT_SelectionError else: verts = bm.select_history debug(f"command: {operation}{mode}{values_out}") debug(f"obj: {obj}, bm: {bm}, obj_loc: {obj_loc}") return pg, values_out, obj, obj_loc, bm, verts
def execute(self, context): area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW', 'IMAGE_EDITOR') if compat.check_version(2, 80, 0) < 0: bd_size = common.get_uvimg_editor_board_size(area) else: bd_size = [1.0, 1.0] large_value = 1e7 if self.base == 'UV': objs = common.get_uv_editable_objects(context) no_selected_face = True if objs: max_ = Vector((-large_value, -large_value)) min_ = Vector((large_value, large_value)) for obj in objs: bm = bmesh.from_edit_mesh(obj.data) if not bm.loops.layers.uv: return None uv_layer = bm.loops.layers.uv.verify() for f in bm.faces: if not f.select: continue for l in f.loops: uv = l[uv_layer].uv max_.x = max(max_.x, uv.x) max_.y = max(max_.y, uv.y) min_.x = min(min_.x, uv.x) min_.y = min(min_.y, uv.y) no_selected_face = False if no_selected_face: max_ = Vector((1.0, 1.0)) min_ = Vector((0.0, 0.0)) center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0)) # pylint: disable=R1702 elif self.base == 'UV_SEL': objs = common.get_uv_editable_objects(context) no_selected_face = True if objs: max_ = Vector((-large_value, -large_value)) min_ = Vector((large_value, large_value)) for obj in objs: bm = bmesh.from_edit_mesh(obj.data) if not bm.loops.layers.uv: return None uv_layer = bm.loops.layers.uv.verify() for f in bm.faces: if not f.select: continue for l in f.loops: if not l[uv_layer].select: continue uv = l[uv_layer].uv max_.x = max(max_.x, uv.x) max_.y = max(max_.y, uv.y) min_.x = min(min_.x, uv.x) min_.y = min(min_.y, uv.y) no_selected_face = False if no_selected_face: max_ = Vector((1.0, 1.0)) min_ = Vector((0.0, 0.0)) center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0)) elif self.base == 'TEXTURE': min_ = Vector((0.0, 0.0)) max_ = Vector((1.0, 1.0)) center = Vector((0.5, 0.5)) else: self.report({'ERROR'}, "Unknown Operation") return {'CANCELLED'} if self.position == 'CENTER': cx = center.x cy = center.y elif self.position == 'LEFT_TOP': cx = min_.x cy = max_.y elif self.position == 'LEFT_MIDDLE': cx = min_.x cy = center.y elif self.position == 'LEFT_BOTTOM': cx = min_.x cy = min_.y elif self.position == 'MIDDLE_TOP': cx = center.x cy = max_.y elif self.position == 'MIDDLE_BOTTOM': cx = center.x cy = min_.y elif self.position == 'RIGHT_TOP': cx = max_.x cy = max_.y elif self.position == 'RIGHT_MIDDLE': cx = max_.x cy = center.y elif self.position == 'RIGHT_BOTTOM': cx = max_.x cy = min_.y else: self.report({'ERROR'}, "Unknown Operation") return {'CANCELLED'} cx = cx * bd_size[0] cy = cy * bd_size[1] space.cursor_location = Vector((cx, cy)) return {'FINISHED'}
def square_fit(context): obj = bpy.context.view_layer.objects.active bm = bmesh.from_edit_mesh(obj.data) uv_layer = bm.loops.layers.uv.verify() faces = list() #MAKE FACE LIST for face in bm.faces: if face.select: faces.append(face) #TEST IF QUADS OR NOT quadmethod = True #EXPERIMENTAL! TO MUCH SKEWING TEST: distorted = False for face in faces: if len(face.loops) is not 4: quadmethod = False #print('no quad!') #SLOW HERE, find faster way to test if selection is ring shaped #Unwrap and get the edge verts bmesh.update_edit_mesh(obj.data) bpy.ops.uv.unwrap(method='CONFORMAL', margin=0.001) bpy.ops.mesh.region_to_loop() obj = bpy.context.edit_object me = obj.data bm = bmesh.from_edit_mesh(me) edge_list = list() for e in bm.edges: if e.select is True: edge_list.append(e) #print(e) #select faces again for f in faces: f.select = True #get start loop (this makes sure we loop in the right direction) startloop = None if (len(edge_list) == 0): print("weird! - means no mesh was sent?") return distorted for l in edge_list[0].link_loops: if l.face.select is True: startloop = l #create sorted verts from start loop sorted_vert_list = list() for f in faces: f.select = False for e in edge_list: e.select = True sorted_vert_list.append(startloop.vert) startloop.edge.select = False sorted_vert_list.append(startloop.link_loop_next.vert) for i in range(1, len(edge_list) - 1): #catch if a patch is donut shaped: if i >= len(sorted_vert_list): for f in faces: f.select = True bmesh.update_edit_mesh(obj.data) return False for e in sorted_vert_list[i].link_edges: if e.select is True: sorted_vert_list.append(e.other_vert(sorted_vert_list[i])) e.select = False #select faces again for f in faces: f.select = True #get UV sorted_uv_list = list() uv_layer = bm.loops.layers.uv.active for v in sorted_vert_list: for l in v.link_loops: if l.face.select is True: sorted_uv_list.append(l[uv_layer]) break #get all angles sorted_angle_list = list() for i in range(len(sorted_uv_list)): prev = (i - 1) % len(sorted_uv_list) next = (i + 1) % len(sorted_uv_list) vector1 = Vector((sorted_uv_list[prev].uv.y - sorted_uv_list[i].uv.y, sorted_uv_list[prev].uv.x - sorted_uv_list[i].uv.x)) vector2 = Vector((sorted_uv_list[next].uv.y - sorted_uv_list[i].uv.y, sorted_uv_list[next].uv.x - sorted_uv_list[i].uv.x)) #check failcase of zero length vector: if vector1.length == 0 or vector2.length == 0: bmesh.update_edit_mesh(obj.data) return False angle = -math.degrees(vector1.angle_signed(vector2)) if angle < 0: angle += 360 sorted_angle_list.append(angle) #find concaves: for i in range(len(sorted_angle_list)): #print(sorted_angle_list[i]) if sorted_angle_list[i] > 230: distorted = True bmesh.update_edit_mesh(obj.data) return False #angle test: #print("angles") #test if more than 4 90 degrees: NCount = 0 for i in range(len(sorted_angle_list)): #print(sorted_angle_list[i]) if sorted_angle_list[i] < 100: NCount += 1 if NCount > 4: distorted = True #now find top 4 angles topangles = list() for o in range(4): top = 360 topindex = -1 for i in range(len(sorted_angle_list)): if sorted_angle_list[i] < top: top = sorted_angle_list[i] topindex = i #print(sorted_angle_list[topindex]) if o is 3: if sorted_angle_list[topindex] > 120: distorted = True topangles.append(topindex) sorted_angle_list[topindex] = 999 #lol sorted_corner_list = list() for i in range(len(sorted_uv_list)): sorted_corner_list.append(False) sorted_corner_list[topangles[0]] = True sorted_corner_list[topangles[1]] = True sorted_corner_list[topangles[2]] = True sorted_corner_list[topangles[3]] = True #find bottom left corner (using distance method seems to work well) distance = 2 closest = 0 for t in topangles: l = sorted_uv_list[t].uv.length if l < distance: distance = l closest = t #rotate lists to get clostest corner at start: for i in range(closest): sorted_corner_list.append(sorted_corner_list.pop(0)) sorted_uv_list.append(sorted_uv_list.pop(0)) sorted_vert_list.append(sorted_vert_list.pop(0)) print("THESE ARE THE CORNERS") print(sorted_corner_list) #create coord list: cornerz = list() for i in range(len(sorted_vert_list)): if sorted_corner_list[i] is True: print(sorted_vert_list[i].co.z) cornerz.append(sorted_vert_list[i].co.z) print(cornerz) #avgedge1 = cornerz[0] + cornerz[1] #avgedge2 = cornerz[0] + cornerz[3] #print(avgedge1) #print(avgedge2) sorted_edge_ratios = list() #get edge lenghts edge = list() for i in range(len(sorted_vert_list)): if sorted_corner_list[i] is True: sorted_edge_ratios.append(0) if i is not 0: l = (sorted_vert_list[i - 1].co.xyz - sorted_vert_list[i].co.xyz).length edge.append(sorted_edge_ratios[i - 1] + l) if sorted_corner_list[i] is False: l = (sorted_vert_list[i - 1].co.xyz - sorted_vert_list[i].co.xyz).length sorted_edge_ratios.append(sorted_edge_ratios[i - 1] + l) if i is (len(sorted_vert_list) - 1): l = (sorted_vert_list[i].co.xyz - sorted_vert_list[0].co.xyz).length edge.append(sorted_edge_ratios[i] + l) if quadmethod: #MAP FIRST QUAD edge1 = (faces[0].loops[0].vert.co.xyz - faces[0].loops[1].vert.co.xyz).length edge2 = (faces[0].loops[1].vert.co.xyz - faces[0].loops[2].vert.co.xyz).length faces[0].loops[0][uv_layer].uv.x = 0 faces[0].loops[0][uv_layer].uv.y = 0 faces[0].loops[1][uv_layer].uv.x = edge1 faces[0].loops[1][uv_layer].uv.y = 0 faces[0].loops[2][uv_layer].uv.x = edge1 faces[0].loops[2][uv_layer].uv.y = edge2 faces[0].loops[3][uv_layer].uv.x = 0 faces[0].loops[3][uv_layer].uv.y = edge2 bm.faces.active = faces[0] #UNWRAP ADJACENT bmesh.update_edit_mesh(obj.data) bpy.ops.uv.follow_active_quads() obj = bpy.context.view_layer.objects.active bm = bmesh.from_edit_mesh(obj.data) uv_layer = bm.loops.layers.uv.verify() #return edge1 = (edge[0] + edge[2]) * .5 edge2 = (edge[1] + edge[3]) * .5 #FIT TO 0-1 range xmin, xmax = faces[0].loops[0][uv_layer].uv.x, faces[0].loops[0][ uv_layer].uv.x ymin, ymax = faces[0].loops[0][uv_layer].uv.y, faces[0].loops[0][ uv_layer].uv.y for face in faces: for vert in face.loops: xmin = min(xmin, vert[uv_layer].uv.x) xmax = max(xmax, vert[uv_layer].uv.x) ymin = min(ymin, vert[uv_layer].uv.y) ymax = max(ymax, vert[uv_layer].uv.y) #return #prevent divide by 0: if (xmax - xmin) == 0: xmin = .1 if (ymax - ymin) == 0: ymin = .1 for face in faces: for loop in face.loops: loop[uv_layer].uv.x -= xmin loop[uv_layer].uv.y -= ymin loop[uv_layer].uv.x /= (xmax - xmin) loop[uv_layer].uv.y /= (ymax - ymin) #shift extents to be positive only: xmax = xmax - xmin ymax = ymax - ymin #now fit to correct edge lengths: if (edge1 < edge2): #flip them: tedge = edge1 edge1 = edge2 edge2 = tedge if xmax >= ymax: for face in faces: for loop in face.loops: loop[uv_layer].uv.x *= edge1 loop[uv_layer].uv.y *= edge2 if xmax < ymax: for face in faces: for loop in face.loops: loop[uv_layer].uv.x *= edge2 loop[uv_layer].uv.y *= edge1 bmesh.update_edit_mesh(obj.data) if quadmethod is False: if distorted is False: #NOW LAY OUT ALL EDGE UVs i = 0 #EDGE 1 for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector((0, 0)) i += 1 while sorted_corner_list[i] is False: for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector( (sorted_edge_ratios[i] / edge[0], 0)) i += 1 #EDGE 2 for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector((1, 0)) i += 1 while sorted_corner_list[i] is False: for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector( (1, sorted_edge_ratios[i] / edge[1])) i += 1 #EDGE 3 for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector((1, 1)) i += 1 while sorted_corner_list[i] is False: for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector( (1 - (sorted_edge_ratios[i] / edge[2]), 1)) i += 1 #EDGE 4 for l in sorted_vert_list[i].link_loops: if l.face.select is True: l[uv_layer].uv = Vector((0, 1)) i += 1 for o in range(i, len(sorted_vert_list)): for l in sorted_vert_list[o].link_loops: if l.face.select is True: l[uv_layer].uv = Vector( (0, 1 - (sorted_edge_ratios[o] / edge[3]))) #set proper aspect ratio for f in bm.faces: if f.select is True: for loop in f.loops: loop_uv = loop[uv_layer] loop_uv.uv.x *= edge[0] loop_uv.uv.y *= edge[1] bmesh.update_edit_mesh(me, True) bpy.ops.uv.select_all(action='SELECT') #expand middle verts bpy.ops.uv.minimize_stretch(iterations=100) #return true if rect fit was succesful return not distorted
def init_edgegrow(self, context): self.change = True self.area = context.area self.region = context.region self.rv3d = context.space_data.region_3d self.selobj = context.active_object self.mesh = self.selobj.data self.bm = bmesh.from_edit_mesh(self.mesh) self.actedge = self.bm.select_history.active # get transf matrix self.getmatrix() # vsellist, essellist: remember selection for reselecting later self.selset = set([]) self.vsellist = [] self.esellist = [] for edge in self.bm.edges: if edge.select: self.selset.add(edge) self.esellist.append(edge) for vert in self.bm.verts: if vert.select: self.vsellist.append(vert) def addstart(vert): # recursive: adds to initial edgelist at start for e in vert.link_edges: if e in self.selset: self.selset.discard(e) v = e.other_vert(vert) self.edgelist[posn].insert(0, e) addstart(v) break def addend(vert): # recursive: adds to initial edgelist at end for e in vert.link_edges: if e in self.selset: self.selset.discard(e) v = e.other_vert(vert) self.edgelist[posn].append(e) addend(v) break self.state = [] self.oldstate = [] self.cursor = [] self.startcur = [] self.endcur = [] self.check = [] self.activedir = [] self.singledir = {} self.singledir[0] = None self.startlen = [] self.edgelist = [] posn = 0 while len(self.selset) > 0: # INITialize next edgesnake self.state.append('INIT') self.oldstate.append('INIT') self.cursor.append(None) self.startcur.append(None) self.endcur.append(None) self.check.append(0) self.activedir.append("") self.edgelist.append([]) elem = self.selset.pop() vert = elem.verts[0] self.selset.add(elem) # add to START and END of arbitrary START vert addstart(vert) addend(vert) self.startlen.append(len(self.edgelist[posn])) posn += 1 if len(self.edgelist) == 1: if len(self.edgelist[0]) == 1: # must store leftmost vert as startingvert when only one edge selected x1, y = self.getscreencoords(self.edgelist[0][0].verts[0].co) x2, y = self.getscreencoords(self.edgelist[0][0].verts[1].co) if x1 < x2: self.singledir[0] = self.edgelist[0][0].verts[0] else: self.singledir[0] = self.edgelist[0][0].verts[1] # orient first edgesnake from left(start) to right(end) x1, y = self.getscreencoords(self.edgelist[0][0].verts[0].co) x2, y = self.getscreencoords(self.edgelist[0][len(self.edgelist[0]) - 1].verts[0].co) if x1 > x2: self.edgelist[0].reverse() # # orient edge and vertlists parallel - reverse if necessary for i in range(len(self.edgelist) - 1): bpy.ops.mesh.select_all(action='DESELECT') # get first vert and edge for two adjacent snakes for v in self.edgelist[i][0].verts: if len(self.edgelist[i]) == 1: if i == 0: x1, y = self.getscreencoords(v.co) x2, y = self.getscreencoords( edgelist[i][0].other_vert(v).co) if x1 < x2: self.singledir[0] = v else: self.singledir[0] = self.edgelist[i][0].other_vert( v) vt = self.singledir[i] vt.select = True self.bm.select_history.add(vt) v1 = vt e1 = self.edgelist[i][0] break elif not (v in self.edgelist[i][1].verts): v.select = True self.bm.select_history.add(v) v1 = v e1 = self.edgelist[i][0] for v in self.edgelist[i + 1][0].verts: if len(self.edgelist[i + 1]) == 1: v.select = True self.bm.select_history.add(v) v2 = v e2 = self.edgelist[i + 1][0] break elif not (v in self.edgelist[i + 1][1].verts): v.select = True self.bm.select_history.add(v) v2 = v e2 = self.edgelist[i + 1][0] self.singledir[i + 1] = v2 self.bm.select_history.validate() # get path between startverts for checking orientation bpy.ops.mesh.shortest_path_select() for e in self.bm.edges: if e.verts[0].select and e.verts[1].select: e.select = True # correct selected path when not connected neatly to vert from left or right(cant know direction) def correctsel(e1, v1, lst): found = False while not (found): found = True for edge in e1.other_vert(v1).link_edges: if edge.select and edge != e1: if lst.index(e1) < len(lst) - 1: v1.select = False e1.select = False v1 = e1.other_vert(v1) e1 = lst[lst.index(e1) + 1] else: templ = list(e1.other_vert(v1).link_faces) for f in e1.link_faces: templ.pop(templ.index(f)) for edge in e1.other_vert(v1).link_edges: if edge in templ[ 0].edges and edge in templ[1].edges: v1.select = False e1.select = False v1 = e1.other_vert(v1) e1 = edge found = False # check situation where left/right connection is on vert thats outside slice found = False while not (found): templ = list(v1.link_faces) for f in e1.link_faces: templ.pop(templ.index(f)) found = True for edge in v1.link_edges: if edge in templ[0].edges and edge in templ[1].edges: if edge.other_vert(v1).select: v1.select = False edge.select = False v1 = edge.other_vert(v1) e1 = edge found = False return e1, v1 e1, v1 = correctsel(e1, v1, self.edgelist[i]) e2, v2 = correctsel(e2, v2, self.edgelist[i + 1]) # do all the checking to see if the checked lists must be reversed brk = False for face1 in e1.link_faces: for edge1 in face1.edges: if edge1.select: for loop1 in face1.loops: if loop1.vert == v1: if loop1.edge == e1: turn = loop1 elif loop1.link_loop_next.edge == e1: turn = loop1.link_loop_next else: turn = loop1.link_loop_prev # check if turning in one direction if turn.link_loop_next.edge.select: for face2 in e2.link_faces: for edge2 in face2.edges: if edge2.select: for loop2 in face2.loops: if loop2.vert == v2: if loop2.edge == e2: turn = loop2 elif loop2.link_loop_next.edge == e2: turn = loop2.link_loop_next else: turn = loop2.link_loop_prev if turn.link_loop_next.edge.select: self.singledir[ i + 1] = e2.other_vert( v2) self.edgelist[ i + 1].reverse() break brk = True break if brk == True: break # and the other elif loop1.link_loop_prev.edge.select: for face2 in e2.link_faces: for edge2 in face2.edges: if edge2.select: for loop2 in face2.loops: if loop2.vert == v2: if loop2.edge == e2: turn = loop2 elif loop2.link_loop_next.edge == e2: turn = loop2.link_loop_next else: turn = loop2.link_loop_prev if turn.link_loop_prev.edge.select: self.singledir[ i + 1] = e2.other_vert( v2) self.edgelist[ i + 1].reverse() break brk = True break if brk == True: break break break for posn in range(len(self.edgelist)): if self.edgelist[posn][0] == self.actedge: for posn in range(len(self.edgelist)): self.edgelist[posn].reverse() bpy.ops.mesh.select_all(action='DESELECT') for v in self.vsellist: v.select = True for e in self.esellist: e.select = True self.region.tag_redraw()
def execute(self, context): mode = context.mode if mode == 'EDIT_MESH': mode = 'EDIT' act = context.active_object if mode != 'OBJECT': sel = [act] bpy.ops.object.mode_set(mode='OBJECT') else: sel = context.selected_objects doneMeshes = [] for ob0 in sel: if ob0.type != 'MESH': continue if ob0.data.name in doneMeshes: continue ob = ob0 mesh_name = ob0.data.name # store linked objects clones = [] n_users = ob0.data.users count = 0 for o in bpy.data.objects: if o.type != 'MESH': continue if o.data.name == mesh_name: count += 1 clones.append(o) if count == n_users: break if self.apply_modifiers: bpy.ops.object.convert(target='MESH') ob.data = ob.data.copy() bpy.ops.object.select_all(action='DESELECT') ob.select_set(True) context.view_layer.objects.active = ob0 bpy.ops.object.mode_set(mode='EDIT') # prevent borders erosion bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') bpy.ops.mesh.select_non_manifold(extend=False, use_wire=False, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) bpy.ops.mesh.extrude_region_move( MESH_OT_extrude_region={"mirror": False}, TRANSFORM_OT_translate={"value": (0, 0, 0)}) bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT', action='TOGGLE') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.quads_convert_to_tris(quad_method=self.quad_method, ngon_method=self.polygon_method) bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.modifier_add(type='SUBSURF') ob.modifiers[-1].name = "dual_mesh_subsurf" while True: bpy.ops.object.modifier_move_up(modifier="dual_mesh_subsurf") if ob.modifiers[0].name == "dual_mesh_subsurf": break bpy.ops.object.modifier_apply(apply_as='DATA', modifier='dual_mesh_subsurf') bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='DESELECT') verts = ob.data.vertices bpy.ops.object.mode_set(mode='OBJECT') verts[-1].select = True bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_more(use_face_step=False) bpy.ops.mesh.select_similar(type='EDGE', compare='EQUAL', threshold=0.01) bpy.ops.mesh.select_all(action='INVERT') bpy.ops.mesh.dissolve_verts() bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_non_manifold(extend=False, use_wire=False, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) bpy.ops.mesh.select_more() # find boundaries bpy.ops.object.mode_set(mode='OBJECT') bound_v = [v.index for v in ob.data.vertices if v.select] bound_e = [e.index for e in ob.data.edges if e.select] bound_p = [p.index for p in ob.data.polygons if p.select] bpy.ops.object.mode_set(mode='EDIT') # select quad faces context.tool_settings.mesh_select_mode = (False, False, True) bpy.ops.mesh.select_face_by_sides(number=4, extend=False) # deselect boundaries bpy.ops.object.mode_set(mode='OBJECT') for i in bound_v: context.active_object.data.vertices[i].select = False for i in bound_e: context.active_object.data.edges[i].select = False for i in bound_p: context.active_object.data.polygons[i].select = False bpy.ops.object.mode_set(mode='EDIT') context.tool_settings.mesh_select_mode = (False, False, True) bpy.ops.mesh.edge_face_add() context.tool_settings.mesh_select_mode = (True, False, False) bpy.ops.mesh.select_all(action='DESELECT') # delete boundaries bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=True) bpy.ops.mesh.delete(type='VERT') # remove middle vertices bm = bmesh.from_edit_mesh(ob.data) for v in bm.verts: if len(v.link_edges) == 2 and len(v.link_faces) < 3: v.select = True # dissolve bpy.ops.mesh.dissolve_verts() bpy.ops.mesh.select_all(action='DESELECT') # remove border faces if not self.preserve_borders: bpy.ops.mesh.select_non_manifold(extend=False, use_wire=False, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) bpy.ops.mesh.select_more() bpy.ops.mesh.delete(type='FACE') # clean wires bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=False, use_multi_face=False, use_non_contiguous=False, use_verts=False) bpy.ops.mesh.delete(type='EDGE') bpy.ops.object.mode_set(mode='OBJECT') ob0.data.name = mesh_name doneMeshes.append(mesh_name) for o in clones: o.data = ob.data bm.free() for o in sel: o.select_set(True) context.view_layer.objects.active = act bpy.ops.object.mode_set(mode=mode) return {'FINISHED'}
def execute(self, context): obj_name = self.name_source_object face_type = self.face_types is_selected = check_is_selected() if not is_selected: self.report({'WARNING'}, "Operation Cancelled. No selected Faces found on the Active Object") return {'CANCELLED'} if face_type == "spiked": Spiked(spike_base_width=self.spike_base_width, base_height_inset=self.base_height_inset, top_spike=self.top_spike, top_relative=self.use_relative) elif face_type == "boxed": startinfo = prepare(self, context, self.remove_start_faces) bm = startinfo['bm'] top = self.top_spike obj = startinfo['obj'] obj_matrix_local = obj.matrix_local distance = None base_heights = None t = self.move_inside areas = startinfo['areas'] base_height = self.base_height if self.use_relative: distance = [min(t * area, 1.0) for i, area in enumerate(areas)] base_heights = [base_height * area for i, area in enumerate(areas)] else: distance = [t] * len(areas) base_heights = [base_height] * len(areas) rings = startinfo['rings'] centers = startinfo['centers'] normals = startinfo['normals'] for i in range(len(rings)): make_one_inset(self, context, bm=bm, ringvectors=rings[i], center=centers[i], normal=normals[i], t=distance[i], base_height=base_heights[i]) bpy.ops.mesh.select_mode(type="EDGE") bpy.ops.mesh.select_more() bpy.ops.mesh.select_more() bpy.ops.object.mode_set(mode='OBJECT') # PKHG>INFO base extrusion done and set to the mesh # PKHG>INFO if the extrusion is NOT done ... it'll look strange soon! if not self.strange_boxed_effect: bpy.ops.object.mode_set(mode='EDIT') obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) bmfaces = [face for face in bm.faces if face.select] res = extrude_faces(self, context, bm=bm, face_l=bmfaces) ring_edges = [face.edges[:] for face in res] bpy.ops.object.mode_set(mode='OBJECT') # PKHG>INFO now the extruded facec have to move in normal direction bpy.ops.object.mode_set(mode='EDIT') obj = bpy.context.view_layer.objects.active bm = bmesh.from_edit_mesh(obj.data) todo_faces = [face for face in bm.faces if face.select] for face in todo_faces: bmesh.ops.translate(bm, vec=face.normal * top, space=obj_matrix_local, verts=face.verts) bpy.ops.object.mode_set(mode='OBJECT') elif face_type == "stepped": Stepped(spike_base_width=self.spike_base_width, base_height_inset=self.base_height_inset, top_spike=self.second_height, top_extra_height=self.top_extra_height, use_relative_offset=self.use_relative, with_spike=self.step_with_real_spike) elif face_type == "open_inset": startinfo = prepare(self, context, self.remove_start_faces) bm = startinfo['bm'] # PKHG>INFO adjust for relative, via areas t = self.move_inside areas = startinfo['areas'] base_height = self.base_height base_heights = None distance = None if self.use_relative: distance = [min(t * area, 1.0) for i, area in enumerate(areas)] base_heights = [base_height * area for i, area in enumerate(areas)] else: distance = [t] * len(areas) base_heights = [base_height] * len(areas) rings = startinfo['rings'] centers = startinfo['centers'] normals = startinfo['normals'] for i in range(len(rings)): make_one_inset(self, context, bm=bm, ringvectors=rings[i], center=centers[i], normal=normals[i], t=distance[i], base_height=base_heights[i]) bpy.ops.object.mode_set(mode='OBJECT') elif face_type == "with_base": startinfo = prepare(self, context, self.remove_start_faces) bm = startinfo['bm'] obj = startinfo['obj'] object_matrix = obj.matrix_local # PKHG>INFO for relative (using areas) t = self.move_inside areas = startinfo['areas'] base_height = self.base_height distance = None base_heights = None if self.use_relative: distance = [min(t * area, 1.0) for i, area in enumerate(areas)] base_heights = [base_height * area for i, area in enumerate(areas)] else: distance = [t] * len(areas) base_heights = [base_height] * len(areas) next_rings = [] rings = startinfo['rings'] centers = startinfo['centers'] normals = startinfo['normals'] for i in range(len(rings)): next_rings.append(make_one_inset(self, context, bm=bm, ringvectors=rings[i], center=centers[i], normal=normals[i], t=distance[i], base_height=base_heights[i])) prepare_ring = extrude_edges(self, context, bm=bm, edge_l_l=next_rings) second_height = self.second_height width = self.width vectors = [[ele.verts[:] for ele in edge] for edge in prepare_ring] n_ring_vecs = [] for rings in vectors: v = [] for edgv in rings: v.extend(edgv) # PKHF>INFO no double verts allowed, coming from two adjacents edges! bm.verts.ensure_lookup_table() vv = list(set([ele.index for ele in v])) vvv = [bm.verts[i].co for i in vv] n_ring_vecs.append(vvv) for i, ring in enumerate(n_ring_vecs): make_one_inset(self, context, bm=bm, ringvectors=ring, center=centers[i], normal=normals[i], t=width, base_height=base_heights[i] + second_height) bpy.ops.object.mode_set(mode='OBJECT') else: if face_type == "clsd_vertical": obj_name = context.active_object.name ClosedVertical(name=obj_name, base_height=self.base_height, use_relative_base_height=self.use_relative) elif face_type == "open_vertical": obj_name = context.active_object.name OpenVertical(name=obj_name, base_height=self.base_height, use_relative_base_height=self.use_relative) elif face_type == "bar": startinfo = prepare(self, context, self.remove_start_faces) result = [] bm = startinfo['bm'] rings = startinfo['rings'] centers = startinfo['centers'] normals = startinfo['normals'] spike_base_width = self.spike_base_width for i, ring in enumerate(rings): result.append(make_one_inset(self, context, bm=bm, ringvectors=ring, center=centers[i], normal=normals[i], t=spike_base_width)) next_ring_edges_list = extrude_edges(self, context, bm=bm, edge_l_l=result) top_spike = self.top_spike fac = top_spike object_matrix = startinfo['obj'].matrix_local for i in range(len(next_ring_edges_list)): translate_ONE_ring( self, context, bm=bm, object_matrix=object_matrix, ring_edges=next_ring_edges_list[i], normal=normals[i], distance=fac ) next_ring_edges_list_2 = extrude_edges(self, context, bm=bm, edge_l_l=next_ring_edges_list) top_extra_height = self.top_extra_height for i in range(len(next_ring_edges_list_2)): move_corner_vecs_outside( self, context, bm=bm, edge_list=next_ring_edges_list_2[i], center=centers[i], normal=normals[i], base_height_erlier=fac + top_extra_height, distance=fac ) bpy.ops.mesh.select_mode(type="VERT") bpy.ops.mesh.select_more() bpy.ops.object.mode_set(mode='OBJECT') return {'FINISHED'}
def prepare(self, context, remove_start_faces=True): """ Start for a face selected change of faces select an object of type mesh, with activated several (all) faces """ obj = bpy.context.view_layer.objects.active bpy.ops.object.mode_set(mode='OBJECT') selectedpolygons = [el for el in obj.data.polygons if el.select] # PKHG>INFO copies of the vectors are needed, otherwise Blender crashes! centers = [face.center for face in selectedpolygons] centers_copy = [Vector((el[0], el[1], el[2])) for el in centers] normals = [face.normal for face in selectedpolygons] normals_copy = [Vector((el[0], el[1], el[2])) for el in normals] vertindicesofpolgons = [ [vert for vert in face.vertices] for face in selectedpolygons ] vertVectorsOfSelectedFaces = [ [obj.data.vertices[ind].co for ind in vertIndiceofface] for vertIndiceofface in vertindicesofpolgons ] vertVectorsOfSelectedFaces_copy = [ [Vector((el[0], el[1], el[2])) for el in listofvecs] for listofvecs in vertVectorsOfSelectedFaces ] bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(obj.data) selected_bm_faces = [ele for ele in bm.faces if ele.select] selected_edges_per_face_ind = [ [ele.index for ele in face.edges] for face in selected_bm_faces ] indices = [el.index for el in selectedpolygons] selected_faces_areas = [bm.faces[:][i] for i in indices] tmp_area = [el.calc_area() for el in selected_faces_areas] # PKHG>INFO, selected faces are removed, only their edges are used! if remove_start_faces: bpy.ops.mesh.delete(type='ONLY_FACE') bpy.ops.object.mode_set(mode='OBJECT') obj.data.update() bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(obj.data) bm.verts.ensure_lookup_table() bm.faces.ensure_lookup_table() start_ring_raw = [ [bm.verts[ind].index for ind in vertIndiceofface] for vertIndiceofface in vertindicesofpolgons ] start_ring = [] for el in start_ring_raw: start_ring.append(set(el)) bm.edges.ensure_lookup_table() bm_selected_edges_l_l = [ [bm.edges[i] for i in bm_ind_list] for bm_ind_list in selected_edges_per_face_ind ] result = { 'obj': obj, 'centers': centers_copy, 'normals': normals_copy, 'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm, 'areas': tmp_area, 'startBMRingVerts': start_ring, 'base_edges': bm_selected_edges_l_l } return result
def create_snowflake(o, iterations=2): # Create rotation matrices rot_matrix = Matrix.Rotation(radians(90), 3, 'Z') turn_around_matrix = Matrix.Rotation(radians(180), 3, 'Z') # Select object and set it as active object o.select = True bpy.context.scene.objects.active = o # Ensure we're in edit mode and in vertex selection mode if o.mode != 'EDIT': bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_mode(type='VERT') for i in range(iterations): # Refresh object data and edge list (which changes with each iterations) d = o.data bm = bmesh.from_edit_mesh(d) bv = bm.verts edges = {e.index: [v.index for v in e.verts] for e in bm.edges} for edge_index, edge in enumerate(edges): # Go to vert selection mode bpy.ops.mesh.select_mode(type='VERT') # Deselect all verts bpy.ops.mesh.select_all(action='DESELECT') # Select current edge (by selecting its verts) bm.verts.ensure_lookup_table() # Update verts list for v in edges[edge]: bv[v].select = True bm.select_flush(True) # Subdivide edge result = bpy.ops.mesh.subdivide(number_cuts=2) bm.select_flush(True) # Find innermost edge selected_edges = { e.index : set([ v.index for v in e.verts ]) \ for e in bm.edges if e.select } # Innermost edge shares both its verts with the other edges mid = 42 # out-of-range index to to indicate if procedure worked for i in selected_edges.keys(): other_edges = set(selected_edges.keys()) - set([i]) # check how many joint verts this edge has with the others num_of_joint_verts = 0 for oe in other_edges: if selected_edges[i] & selected_edges[oe]: num_of_joint_verts += 1 # The middle edge will have two joint verts if num_of_joint_verts == 2: mid = i break # Select innermost edge (by selecting its verts) bm.verts.ensure_lookup_table() # Update verts list bpy.ops.mesh.select_all(action='DESELECT') for v in selected_edges[mid]: bv[v].select = True bm.select_flush(True) # Subdivide it once bpy.ops.mesh.subdivide(number_cuts=1) # Select innermost vert (joint vert between both edges) selected_edges_verts = [ set([v.index for v in e.verts]) for e in bm.edges if e.select ] # Find common vert by intersecting both vert sets joint_vert = list(selected_edges_verts[0] & selected_edges_verts[1]).pop() # Find the verts that aren't joint (via set symmetrical_difference) other_verts = list(selected_edges_verts[0] ^ selected_edges_verts[1]) # Make sure vertices are in right order if (other_verts[0] > other_verts[1]): other_verts[0], other_verts[1] = other_verts[1], other_verts[0] # Calculate its new position: should create an equilateral triangle bm.verts.ensure_lookup_table() # Update verts list vdiff = bv[other_verts[1]].co - bv[other_verts[0]].co vdiff[0] *= sqrt(3) / 2.0 vdiff[1] *= sqrt(3) / 2.0 vrot = vdiff * rot_matrix new_pos = bv[joint_vert].co + vrot # Select middle vert and translate it by the rotate vector bpy.ops.mesh.select_all(action='DESELECT') bv[joint_vert].select = True bm.select_flush(True) bpy.ops.transform.translate(value=tuple(vrot)) # Return to object mode bpy.ops.object.mode_set(mode='OBJECT')
def Twist(self, context): global L,LBSPhi,K,Links,RefFrm,TwistLbsFrm,LbsSFrm,TwstAxsAngl,AxsAngl,CnsVrt,FrVrt ########################## Selection ######################## bpy.data.objects['MySkelPose'].select_set(True) bpy.context.view_layer.objects.active = bpy.data.objects['MySkelPose'] obj=bpy.context.object bm=bmesh.from_edit_mesh(obj.data) SelVrt=[] for vs in bm.verts: if vs.select: SelVrt.append(vs.index) Id=0 NFrm=len(Links) #AxsAnglTmp=np.zeros((NFrm,3)) for j in Links: if SelVrt == j: theta=(context.scene.TwistAngle1)*(np.pi/180) C=np.cos(theta) S=np.sin(theta) T=1-C ######### LBS ###### w=LbsSFrm[:,4*Id] R=np.array([[T*(w[0]**2)+C,T*w[0]*w[1]-S*w[2], T*w[0]*w[2]+S*w[1]], [T*w[0]*w[1]+S*w[2],T*(w[1]**2)+C,T*w[1]*w[2]-S*w[0]], [T*w[0]*w[2]-S*w[1],T*w[1]*w[2]+S*w[0],T*(w[2]**2)+C]]) TwistLbsFrm[:,4*Id:4*Id+3]=R.dot(LbsSFrm[:,4*Id:4*Id+3]) ###################### w=RefFrm[:,4*Id] TwstAxsAngl[Id]=theta*w Id+=1 break Id+=1 Ncl=len(JntInd) JntPrFace=len(JntInd[0]) G=np.zeros((3,3*Ncl)) Theta=np.ones(7) for c in range(Ncl): Ind=JntInd[c] R=0 for i in range(JntPrFace): Y=W[3*c:3*c+3,3*i:3*i+3].dot(TwstAxsAngl[Ind[i]]+AxsAngl[Ind[i]]) R=R+Wgts[c,i]*AnglAxisToRotMat(Y) Theta[3*i:3*i+3]=AxsAngl[Ind[i]] G[:,3*c:3*c+3]=R.dot(np.reshape(H[9*c:9*c+9].dot(Theta),(3,3))) X=np.zeros((3,len(CnsVrt)+len(FrVrt))) X[:,CnsVrt]=TwistLbsFrm.dot(LBSPhi) X[:,FrVrt]=G.dot(L)-X[:,CnsVrt].dot(K) bpy.data.objects['MyMeshPose'].select_set(True) bpy.context.view_layer.objects.active = bpy.data.objects['MyMeshPose'] obj = bpy.context.active_object j=0 for v in obj.data.vertices: v.co=[X[0,j],-X[2,j],X[1,j]] j+=1 bpy.data.objects['MySkelPose'].select_set(True) bpy.context.view_layer.objects.active = bpy.data.objects['MySkelPose'] return
def invoke(self, context, event): if context.space_data.type == 'VIEW_3D': #print('name', __name__, __package__) preferences = context.user_preferences.addons[__name__].preferences create_new_obj = preferences.create_new_obj if context.mode == 'OBJECT' and (create_new_obj or context.object == None or context.object.type != 'MESH'): mesh = bpy.data.meshes.new("") obj = bpy.data.objects.new("", mesh) context.scene.objects.link(obj) context.scene.objects.active = obj #bgl.glEnable(bgl.GL_POINT_SMOOTH) self.is_editmode = bpy.context.object.data.is_editmode bpy.ops.object.mode_set(mode='EDIT') context.space_data.use_occlude_geometry = True self.scale = context.scene.unit_settings.scale_length self.unit_system = context.scene.unit_settings.system self.separate_units = context.scene.unit_settings.use_separate self.uinfo = get_units_info(self.scale, self.unit_system, self.separate_units) grid = context.scene.unit_settings.scale_length / context.space_data.grid_scale relative_scale = preferences.relative_scale self.scale = grid / relative_scale self.rd = bpy.utils.units.to_value(self.unit_system, 'LENGTH', str(1 / self.scale)) incremental = preferences.incremental self.incremental = bpy.utils.units.to_value( self.unit_system, 'LENGTH', str(incremental)) self.use_rotate_around_active = context.user_preferences.view.use_rotate_around_active context.user_preferences.view.use_rotate_around_active = True self.select_mode = context.tool_settings.mesh_select_mode[:] context.tool_settings.mesh_select_mode = (True, True, True) self.region = context.region self.rv3d = context.region_data self.rotMat = self.rv3d.view_matrix.copy() self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.bm = bmesh.from_edit_mesh(self.obj.data) self.location = Vector() self.list_verts = [] self.list_verts_co = [] self.bool_update = False self.vector_constrain = () self.keytab = False self.keyf8 = False self.type = 'OUT' self.len = 0 self.length_entered = "" self.line_pos = 0 self.out_color = preferences.out_color self.face_color = preferences.face_color self.edge_color = preferences.edge_color self.vert_color = preferences.vert_color self.center_color = preferences.center_color self.perpendicular_color = preferences.perpendicular_color self.constrain_shift_color = preferences.constrain_shift_color self.axis_x_color = tuple( context.user_preferences.themes[0].user_interface.axis_x) self.axis_y_color = tuple( context.user_preferences.themes[0].user_interface.axis_y) self.axis_z_color = tuple( context.user_preferences.themes[0].user_interface.axis_z) self.intersect = preferences.intersect self.create_face = preferences.create_face self.outer_verts = preferences.outer_verts self.snap_to_grid = preferences.increments_grid self._handle = bpy.types.SpaceView3D.draw_handler_add( self.draw_callback_px, (context, ), 'WINDOW', 'POST_VIEW') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} else: self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'}
def modal(self, context, event): if context.area: context.area.tag_redraw() if event.ctrl and event.type == 'Z' and event.value == 'PRESS': bpy.ops.ed.undo() self.vector_constrain = None self.list_verts_co = [] self.list_verts = [] self.list_edges = [] self.list_faces = [] self.obj = bpy.context.active_object self.obj_matrix = self.obj.matrix_world.copy() self.bm = bmesh.from_edit_mesh(self.obj.data) return {'RUNNING_MODAL'} if event.type == 'MOUSEMOVE' or self.bool_update: if self.rv3d.view_matrix != self.rotMat: self.rotMat = self.rv3d.view_matrix.copy() self.bool_update = True else: self.bool_update = False if self.bm.select_history: self.geom = self.bm.select_history[0] else: #See IndexError or AttributeError: self.geom = None x, y = (event.mouse_region_x, event.mouse_region_y) if self.geom: self.geom.select = False self.bm.select_history.clear() bpy.ops.view3d.select(location=(x, y)) if self.list_verts != []: previous_vert = self.list_verts[-1] else: previous_vert = None outer_verts = self.outer_verts and not self.keytab snap_utilities( self, context, self.obj_matrix, self.geom, self.bool_update, (x, y), outer_verts=self.outer_verts, constrain=self.vector_constrain, previous_vert=previous_vert, ignore_obj=self.obj, increment=self.incremental, ) if self.snap_to_grid and self.type == 'OUT': loc = self.location / self.rd self.location = Vector( (round(loc.x), round(loc.y), round(loc.z))) * self.rd if self.keyf8 and self.list_verts_co: lloc = self.list_verts_co[-1] orig, view_vec = region_2d_to_orig_and_view_vector( self.region, self.rv3d, (x, y)) location = intersect_point_line(lloc, orig, (orig + view_vec)) vec = (location[0] - lloc) ax, ay, az = abs(vec.x), abs(vec.y), abs(vec.z) vec.x = ax > ay > az or ax > az > ay vec.y = ay > ax > az or ay > az > ax vec.z = az > ay > ax or az > ax > ay if vec == Vector(): self.vector_constrain = None else: vc = lloc + vec try: if vc != self.vector_constrain[1]: type = 'X' if vec.x else 'Y' if vec.y else 'C' if vec.y else 'Z' if vec.z else 'shift' ##cme Y から C に変更 self.vector_constrain = [lloc, vc, type] except: type = 'X' if vec.x else 'Y' if vec.y else 'C' if vec.y else 'Z' if vec.z else 'shift' ##cme Y から C に変更 self.vector_constrain = [lloc, vc, type] if event.value == 'PRESS': if self.list_verts_co and (event.ascii in CharMap.ascii or event.type in CharMap.type): CharMap.modal(self, context, event) elif event.type in self.constrain_keys: self.bool_update = True if self.vector_constrain and self.vector_constrain[ 2] == event.type: self.vector_constrain = () else: if event.shift: if isinstance(self.geom, bmesh.types.BMEdge): if self.list_verts: loc = self.list_verts_co[-1] self.vector_constrain = ( loc, loc + self.geom.verts[1].co - self.geom.verts[0].co, event.type) else: self.vector_constrain = [ self.obj_matrix * v.co for v in self.geom.verts ] + [event.type] else: if self.list_verts: loc = self.list_verts_co[-1] else: loc = self.location self.vector_constrain = [ loc, loc + self.constrain_keys[event.type] ] + [event.type] elif event.type == 'LEFTMOUSE': # SNAP 2D snap_3d = self.location Lsnap_3d = self.obj_matrix.inverted() * snap_3d Snap_2d = location_3d_to_region_2d(self.region, self.rv3d, snap_3d) if self.vector_constrain and isinstance( self.geom, bmesh.types.BMVert): # SELECT FIRST bpy.ops.view3d.select(location=(int(Snap_2d[0]), int(Snap_2d[1]))) try: geom2 = self.bm.select_history[0] except: # IndexError or AttributeError: geom2 = None else: geom2 = self.geom self.vector_constrain = None self.list_verts_co = draw_line(self, self.obj, self.bm, geom2, Lsnap_3d) bpy.ops.ed.undo_push(message="Undo draw line*") # # elif event.type == 'TAB': # self.keytab = self.keytab == False # if self.keytab: # context.tool_settings.mesh_select_mode = (False, False, True) # else: # context.tool_settings.mesh_select_mode = (True, True, True) elif event.type == 'F8': self.vector_constrain = None self.keyf8 = self.keyf8 == False elif event.value == 'RELEASE': if event.type in {'NUMPAD_ENTER'}: ##cme 'RET'を削除して終了にした if self.length_entered != "" and self.list_verts_co: try: text_value = bpy.utils.units.to_value( self.unit_system, 'LENGTH', self.length_entered) vector = (self.location - self.list_verts_co[-1]).normalized() location = (self.list_verts_co[-1] + (vector * text_value)) G_location = self.obj_matrix.inverted() * location self.list_verts_co = draw_line(self, self.obj, self.bm, self.geom, G_location) self.length_entered = "" self.vector_constrain = None except: # ValueError: self.report({'INFO'}, "Operation not supported yet") ##cme 'MIDDLEMOUSE', 'A', 'SPACE', 'RET' を追加 elif event.type in { 'RIGHTMOUSE', 'ESC', 'MIDDLEMOUSE', 'A', 'SPACE', 'RET' }: # if self.list_verts_co == [] or event.type == 'ESC': bpy.types.SpaceView3D.draw_handler_remove( self._handle, 'WINDOW') context.tool_settings.mesh_select_mode = self.select_mode context.area.header_text_set() context.user_preferences.view.use_rotate_around_active = self.use_rotate_around_active ##cme 無駄なポリゴンを削除 # bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') # bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=False) # bpy.ops.mesh.delete(type='EDGE') # bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') # bpy.ops.mesh.select_loose(extend=True) # bpy.ops.mesh.delete(type='VERT') if not self.is_editmode: bpy.ops.object.editmode_toggle() return {'FINISHED'} # else: # self.vector_constrain = None # self.list_verts = [] # self.list_verts_co = [] # self.list_faces = [] a = "...... Finish = Esc, Return, Space, A " if self.list_verts_co: if self.length_entered: pos = self.line_pos a = 'length: ' + self.length_entered[: pos] + '|' + self.length_entered[ pos:] else: length = self.len length = convert_distance(length, self.uinfo) a = 'length: ' + length context.area.header_text_set( "hit: %.3f %.3f %.3f %s" % (self.location[0], self.location[1], self.location[2], a)) self.modal_navigation(context, event) return {'RUNNING_MODAL'}
import bpy import bmesh #Debemos estar en modo objeto, fallara si la escena esta vacia bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() #Creamos un cubo y entramos al modo edicion bpy.ops.mesh.primitive_cube_add(radius=1, location=(0, 0, 0)) bpy.ops.object.mode_set(mode='EDIT') #Almacena una referencia al mesh datablock mesh_datablock = bpy.context.object.data #Creamos un objetos bmesh llamado bm para usarlo bm = bmesh.from_edit_mesh(mesh_datablock) #Imprime el objeto bmesh print(bm)
def poll(cls, context): if context.mode == 'EDIT_MESH': bm = bmesh.from_edit_mesh(context.active_object.data) return bm.faces elif context.mode == 'OBJECT': return [obj for obj in context.selected_objects if obj.type == 'MESH' and obj.data.polygons]