# -*- coding: utf-8 -*- from maya import cmds import math import json import os from . import qt from . import lang from . import common from . import vector #PySide2、PySide両対応 import imp try: imp.find_module('PySide2') from PySide2.QtWidgets import * from PySide2.QtGui import * from PySide2.QtCore import * except ImportError: from PySide.QtGui import * from PySide.QtCore import * save_path = os.path.join( os.getenv('MAYA_APP_DIR'), 'Scripting_Files') maya_ver = int(cmds.about(v=True)[:4]) class ExtrudeEdgeUV(qt.SubWindow): n_uvs = [] saw_edges = [] ex_edges = [] save_file = save_path+'\\sisidebar_extrude_setting_'+str(maya_ver)+'.json' def __init__(self, parent = None, menu_text=95, string_col=255, mid_color =160, bg_col=52, ui_color=50, text_col=0, hilite=192): super(ExtrudeEdgeUV, self).__init__(parent) self.load_data() wrapper = QWidget() self.setCentralWidget(wrapper) self.main_layout = QVBoxLayout() wrapper.setLayout(self.main_layout) qt.change_widget_color(self, textColor=menu_text, bgColor=ui_color) msg = lang.Lang( en='- UV extrusion distance -', ja=u'- UVの押し出し距離 -').output() label = QLabel(msg,self) qt.change_button_color(label, textColor=menu_text , bgColor= ui_color ) self.main_layout.addWidget(label) self.slider_layout = QHBoxLayout() self.main_layout.addLayout(self.slider_layout) self.d_ratio = QDoubleSpinBox(self)#スピンボックス self.d_ratio.setRange(0, 10) self.d_ratio.setValue(self.d_ratio_val)#値を設定 self.slider_layout.addWidget(self.d_ratio) qt.change_widget_color(self.d_ratio, textColor=string_col, bgColor=mid_color, baseColor=bg_col) #スライダバーを設定 self.d_ratio_sld = QSlider(Qt.Horizontal,self) self.d_ratio_sld.setRange(0, 1000) self.d_ratio_sld.setValue(self.d_ratio.value()*100) self.slider_layout.addWidget(self.d_ratio_sld) self.d_ratio_sld.installEventFilter(self) #スライダーとボックスの値をコネクト。連動するように設定。 self.d_ratio_sld.valueChanged.connect(lambda : self.d_ratio.setValue(self.d_ratio_sld.value()/100.0)) self.d_ratio.editingFinished.connect(lambda : self.d_ratio_sld.setValue(self.d_ratio.value()*100)) self.d_ratio_sld.valueChanged.connect(qt.Callback(self.push_out)) #ソフトエッジ角度の設定 self.main_layout.addWidget(qt.make_h_line()) msg = lang.Lang( en='- Smoothing Angle -', ja=u'- スムース角の設定 -').output() label = QLabel(msg,self) qt.change_button_color(label, textColor=menu_text , bgColor= ui_color ) self.main_layout.addWidget(label) self.slider_layout = QHBoxLayout() self.main_layout.addLayout(self.slider_layout) self.soft_angle = QDoubleSpinBox(self)#スピンボックス self.soft_angle.setRange(0, 180) self.soft_angle.setValue(self.soft_angle_val)#値を設定 self.slider_layout.addWidget(self.soft_angle) qt.change_widget_color(self.soft_angle, textColor=string_col, bgColor=mid_color, baseColor=bg_col) #スライダバーを設定 self.soft_angle_sld = QSlider(Qt.Horizontal,self) self.soft_angle_sld.setRange(0, 18000) self.soft_angle_sld.setValue(self.soft_angle.value()*100) self.slider_layout.addWidget(self.soft_angle_sld) #スライダーとボックスの値をコネクト。連動するように設定。 self.soft_angle_sld.valueChanged.connect(lambda : self.soft_angle.setValue(self.soft_angle_sld.value()/100.0)) self.soft_angle.editingFinished.connect(lambda : self.soft_angle_sld.setValue(self.soft_angle.value()*100)) msg = lang.Lang(en='Extrude edges', ja=u'エッジを押し出し').output() self.main_layout.addWidget(qt.make_h_line()) button = qt.make_flat_button(name = msg, text=text_col, bg=hilite, ui_color=ui_color, checkable=False, h_max=24, h_min=24) button.clicked.connect(qt.Callback(self.extrude_edge_uv)) self.main_layout.addWidget(button) msg = lang.Lang(en='Sew UV', ja=u'UVを縫合').output() self.main_layout.addWidget(qt.make_h_line()) button = qt.make_flat_button(name = msg, text=text_col, bg=hilite, ui_color=ui_color, checkable=False, h_max=24, h_min=24) button.clicked.connect(qt.Callback(self.marge_uvs)) self.main_layout.addWidget(button) def _init_ui(self): self.show() def closeEvent(self, e): self.save_data() #アンドゥチャンクを制御しておく def eventFilter(self, obj, event): if event.type() == QEvent.MouseButtonPress: #print 'in' cmds.undoInfo(openChunk=True) if event.type() == QEvent.MouseButtonRelease: #print 'out' cmds.undoInfo(closeChunk=True) return False def load_data(self): if os.path.exists(self.save_file):#保存ファイルが存在したら with open(self.save_file, 'r') as f: try: save_data = json.load(f) self.d_ratio_val = save_data['d_ratio'] self.soft_angle_val= save_data['soft_angle'] except Exception as e: self.d_ratio_val = 1.0 self.soft_angle_val = 120 print e.message else: self.d_ratio_val = 1.0 self.soft_angle_val = 120 def save_data(self): save_data = {'d_ratio':self.d_ratio.value(), 'soft_angle':self.soft_angle.value()} with open(self.save_file, 'w') as f: json.dump(save_data, f) def extrude_edge_uv(self): self.ex_edges = [] sel = cmds.ls(sl=True) self.s_edges = common.conv_comp(sel, mode='edge') s_vtx = common.conv_comp(sel, mode='vtx') #self.saw_uvs(mode='pre')#事前に押し出し対象のUVを縫い合わせておく self.marge_uvs(mode='pre') if not self.s_edges: return ev_dict ,vec_dict, ev_uv_dict = self.make_edge_vtx_dict(self.s_edges) #print 'ev_dict :', ev_dict #print 'vec_dict :', vec_dict #押し出しを実行する cmds.polyExtrudeEdge(self.s_edges, keepFacesTogether=True, smoothingAngle=self.soft_angle.value(), translate=[0, 0, 0]) self.ex_edges = cmds.ls(sl=True) n_edges = common.conv_comp(self.ex_edges, mode='edge') n_faces = common.conv_comp(self.ex_edges, mode='face') self.n_uvs = common.conv_comp(n_faces, mode='uv') #print 'pre_move_uvs :', self.n_uvs #根本の位置合わせする new_vec_dict = {} for nuv in self.n_uvs[:]: vtx = common.conv_comp(nuv, mode='vtx')[0] edge = common.conv_comp(nuv, mode='edge')[0] if edge+' '+vtx in ev_dict.keys(): uv_pos = ev_dict[edge+' '+vtx] #print 'get_uv_pos', nuv, uv_pos cmds.polyEditUV(nuv, u=uv_pos[0], v=uv_pos[1] ,r=False) self.n_uvs.remove(nuv) key_uv = ev_uv_dict[edge+' '+vtx] new_vec_dict[nuv] = vec_dict[key_uv] #print 'post push uvs :', self.n_uvs #押し出し先を根本につけて押し出しベクトル辞書をつくる self.uv_vec_dict = {} self.base_pos_dict = {} for nuv in self.n_uvs: edges = common.conv_comp(nuv, mode='edge') face = common.conv_comp(nuv, mode='face') f_uvs = common.conv_comp(face, mode='uv') for edge in edges: if edge in n_edges: continue #print 'get new edge :', edge e_uvs = common.conv_comp(edge, mode='uv') l_uvs = list(set(f_uvs) & set(e_uvs)) #print 'new edge uvs :', l_uvs for uv in l_uvs: if not uv in new_vec_dict.keys(): continue uv_pos = cmds.polyEditUV(uv, query=True) cmds.polyEditUV(nuv, u=uv_pos[0], v=uv_pos[1] ,r=False) self.uv_vec_dict[nuv] = new_vec_dict[uv] self.base_pos_dict[nuv] = uv_pos self.saw_edges.append(edge)#縫い合わせ用リストに入れておく self.push_out() cmds.setToolTo('moveSuperContext') def push_out(self): for uv in self.n_uvs: base_pos = self.base_pos_dict[uv] uv_pos = self.uv_vec_dict[uv] u = uv_pos[0]*self.d_ratio.value()/10+base_pos[0] v = uv_pos[1]*self.d_ratio.value()/10+base_pos[1] cmds.polyEditUV(uv, u=u, v=v ,r=False) #エッジと頂点のセットでuv座標を記録しておく def make_edge_vtx_dict(self, edges): edge_vtx_dict = {} vec_dict = {} pos_dict = {} ev_uv_dict = {} if not edges: return for edge in edges: uvs = common.conv_comp(edge, mode='uv') for uv in uvs: vtx = common.conv_comp(uv, mode='vtx')[0] pos = cmds.polyEditUV(uv, query=True) edge_vtx_dict[edge+' '+vtx] = pos vec_dict[uv] = self.culc_push_vec(uv) pos_dict[uv] = pos ev_uv_dict[edge+' '+vtx] = uv return edge_vtx_dict, vec_dict, ev_uv_dict #押し出し方向を計算する def culc_push_vec(self, uv): #s_edge_uv = common.conv_comp(edges, mode='uv') re_uvs = common.conv_comp(uv, mode='edge') re_uvs = common.conv_comp(re_uvs, mode='uv') rf_uvs = common.conv_comp(uv, mode='face') rf_uvs = common.conv_comp(rf_uvs, mode='uv') #論理積をとってベクトルをとるUVを絞り込む r_uvs = list(set(re_uvs)&set(rf_uvs)) # uv, r_uvs uv_pos = cmds.polyEditUV(uv, q=True) #それぞれのUVを取得して正規化 push_vec = [0.0,0.0] for ruv in r_uvs: #if ruv in s_edge_uv: #continue if ruv == uv: continue ruv_pos = cmds.polyEditUV(ruv, q=True) uv_vec = [uv_pos[0]-ruv_pos[0], uv_pos[1]-ruv_pos[1]] if vector.get_length(uv_vec) == 0.0:#ベクトル0の場合はスキップする continue #均等に押し広げるためにあらかじめ正規化したベクトルの合計を出す uv_vec = vector.normalize(uv_vec) push_vec = [push_vec[0]+uv_vec[0], push_vec[1]+uv_vec[1]] push_vec = vector.normalize(push_vec)#正規化 return push_vec #縫合よりもマージの方が簡単に済んだorz def marge_uvs(self, mode='after'): #print self.s_edges if mode == 'after' and self.s_edges is not None: saw_edges = self.saw_edges+self.s_edges self.n_uvs = [] else: saw_edges = self.s_edges if not saw_edges: return cmds.polyMergeUV(saw_edges, ch=1, d=0.01) if mode == 'after': cmds.select(self.ex_edges, r=True) #縫い合わせる,頑張って計算したけどマージの方が簡単に済んだので使用中止 def saw_uvs(self, mode='after'): if mode == 'after': saw_edges = self.saw_edges self.n_uvs = [] else: saw_edges = common.conv_comp(self.s_edges, mode='vtx') saw_edges = common.conv_comp(saw_edges, mode='edge') for edge in self.s_edges: saw_edges.remove(edge) if not saw_edges: return checked_edges = [] for edge in saw_edges: uvs = common.conv_comp(edge, mode='uv') uv_pos = [str(map(lambda x:round(x, 5), cmds.polyEditUV(uv, q=True))) for uv in uvs] #print len(uv_pos) uv_pos = list(set(uv_pos)) #if mode=='pre': #print edge, len(uv_pos) if len(uv_pos) > 2: continue checked_edges.append(edge) if checked_edges: cmds.polyMapSew(checked_edges, ch=True) cmds.polyMapSew(self.s_edges, ch=True)#付け根のUVを縫合する self.saw_edges = [] cmds.select(self.ex_edges, r=True) #ExtrudeEdgeUV()._init_ui()