import copy #ウェイト値のミラーコピースクリプト #使えるのはshade14以上 #shade14と15で動作確認 #このスクリプトの機能 #ウェイト値のミラーコピーを行います #キャラクターの片側へウェイトペイントなどをして調整したウェイト情報をミラーコピーするのに使います。 #使用上の注意 #各ボーンには固有の名前をつけ、同じ名前のボーンは存在しないようにする必要あり #名前で対のボーンを探す場合は、ジョイントの先頭か末尾に「LかR」あるいは「lかr」、「左か右」をつける事 # 例   肩ボーン1l と 肩ボーン1r とか、 rleg003 と lleg003 みたいな感じの名前の付け方に #上位パートに変換がかかっていると、正常にミラーされない事がある #スキンタイプは「頂点ブレンド」の時のみ使えます。「クラシック」では使えません。 #動作条件 #選択形状がポリゴンメッシュで、選択している形状は一つのみ #編集モードに入っていて、頂点編集モードでx座標の値が0より大きい頂点を一つ以上選択している事 #ポリゴンメッシュの形状はY座標軸を軸として線対象の形状になっていないと正常に機能しません。 def return_invert_point(aclist): #選択している頂点の、X座標0を対称点とした逆側の頂点を返す ashape=xshade.scene().active_shape() templist=[] boundsize=ashape.bounding_box_size gosax=boundsize[0]/100 if (gosax==0): gosax=10 gosay=boundsize[1]/100 if (gosay==0): gosay=10 gosaz=boundsize[2]/100 if (gosaz==0): gosaz=10 #選択頂点を囲むバウンディングボックス掲載 minx=ashape.vertex(aclist[0]).position[0] maxx=minx miny=ashape.vertex(aclist[0]).position[1] maxy=miny minz=ashape.vertex(aclist[0]).position[2] maxz=minz for ii in aclist: tempx=ashape.vertex(ii).position[0] tempy=ashape.vertex(ii).position[1] tempz=ashape.vertex(ii).position[2] if(tempxmaxx):maxx=tempx if(tempymaxy):maxy=tempy if(tempzmaxz):maxz=tempz #x座標的にバウンディングボックスを逆転 tempp=minx minx=-maxx maxx=-tempp #バウンディングボックスを誤差分ふくらませる minx=minx-gosax maxx=maxx+gosax miny=miny-gosay maxy=maxy+gosay minz=minz-gosaz maxz=maxz+gosaz #反転したバウンディングボックス内にある頂点を返す for pp in range(ashape.total_number_of_control_points): tempvec=ashape.vertex(pp).position if(tempvec[0]>=minx and tempvec[0]<=maxx and tempvec[1]>=miny and tempvec[1]<=maxy and tempvec[2]>=minz and tempvec[2]<=maxz): templist.append(pp) return templist def debugyou(motolist): print "デバッグ用リスト" for i in motolist: print i.name def exlist(alist,blist): #ジョイントの対リストを出力 print "リスト出力" for i in range(len(alist)): tex1=alist[i].name tex2=blist[i].name tex3=tex1+"の対となるジョイントは、"+tex2 print tex3 print " " def return_bindlist(): #そのポリゴンメッシュにバインドされている全てのジョイントのリストを返す #各ボーンには固有の名前をつける事(重要) 同じ名前のボーンがあると機能しない templist=[] count=0 for i in range(xshade.scene().active_shape().total_number_of_control_points): if (xshade.scene().active_shape().vertex(i).skin.number_of_binds>0) : for jj in range(xshade.scene().active_shape().vertex(i).skin.number_of_binds): tempb=xshade.scene().active_shape().vertex(i).skin.get_bind(jj).shape if (count==0): templist.append(tempb) count+=1 else: tuikasuru=1 for bb in templist: if (bb.center_position==tempb.center_position and bb.type==tempb.type and bb.name==tempb.name): tuikasuru=0 break if (tuikasuru==1): templist.append(tempb) return templist def return_negativelist(motolist,gosa): #ジョイントリストを元に、正反対にあるジョイントリストを返す templistr=[] motolist2=copy.copy(motolist) # gosa2=0.01 gosa2=0.01 for i in motolist: min=1000 count=0 # addobj=i for dd in motolist2: tempvec=i.center_position tempvec2=[-tempvec[0],tempvec[1],tempvec[2]] # if (dd.center_position[0]==tempvec2[0] and dd.center_position[1]==tempvec2[1] and dd.center_position[2]==tempvec2[2]): tempvec3=[dd.center_position[0],dd.center_position[1],dd.center_position[2]] kyori=(tempvec3[0]-tempvec2[0])**2+(tempvec3[1]-tempvec2[1])**2+(tempvec3[2]-tempvec2[2])**2 # if (((tempvec3[0]-tempvec2[0])**2+(tempvec3[1]-tempvec2[1])**2+(tempvec3[2]-tempvec2[2])**2)0): # tasu=5 if(leftright==0): tempname1=motoname[3:] tempname2=sakiname[3:] else: if("left" in motoname or "LEFT" in motoname or "Left" in motoname): tempname1=motoname[4:] tempname2=sakiname[5:] else: tempname1=motoname[5:] tempname2=sakiname[4:] # nagasa1=len(motoname) # nagasa2=len(sakiname) # tempname3=motoname[0:nagasa1-2] # tempname4=sakiname[0:nagasa1-2] if(tempname1==tempname2): dcount=0 if(leftright>0): dcount=1 if(motoname[0:1]=="R" and sakiname[0:1]=="L"): dcount=1 if(motoname[0:1]=="L" and sakiname[0:1]=="R"): dcount=1 if(motoname[0:1]=="r" and sakiname[0:1]=="l"): dcount=1 if(motoname[0:1]=="l" and sakiname[0:1]=="r"): dcount=1 if(motoname[0:3]=="右" and sakiname[0:3]=="左"): dcount=1 if(motoname[0:3]=="左" and sakiname[0:3]=="右"): dcount=1 if(dcount>0): count+=1 addobj=dd nagasa1=len(motoname) nagasa2=len(sakiname) ume=0 if(sakiname[nagasa2-3:nagasa2]=="左" or sakiname[nagasa2-3:nagasa2]=="右"): ume=2 tempname3=motoname[0:nagasa1-1-ume] tempname4=sakiname[0:nagasa1-1-ume] if(tempname3==tempname4): dcount=0 if(motoname[nagasa1-1:nagasa1]=="R" and sakiname[nagasa2-1:nagasa2]=="L"): dcount=1 if(motoname[nagasa1-1:nagasa1]=="L" and sakiname[nagasa2-1:nagasa2]=="R"): dcount=1 if(motoname[nagasa1-1:nagasa1]=="r" and sakiname[nagasa2-1:nagasa2]=="l"): dcount=1 if(motoname[nagasa1-1:nagasa1]=="l" and sakiname[nagasa2-1:nagasa2]=="r"): dcount=1 if(motoname[nagasa1-3:nagasa1]=="右" and sakiname[nagasa2-3:nagasa2]=="左"): dcount=1 if(motoname[nagasa1-3:nagasa1]=="左" and sakiname[nagasa2-3:nagasa2]=="右"): dcount=1 if(dcount>0): count+=1 addobj=dd # if (count==0): # addobj=dd # count+=1 # else: # if (dd.name!=i.name): # addobj=dd templistr.append(addobj) # templistr.append(1) return templistr dousasuru=0 ashape=xshade.scene().active_shape() xscene=xshade.scene() aclist=[] minusaclist2=[] #if xshade.scene().active_shape().type==7 and len(xshade.scene().active_shapes)==1: # if xscene.is_modify_mode==True and xscene.selection_mode==2: # for i in range(ashape.total_number_of_control_points): # if (ashape.vertex(i).position[0]>0 and ashape.vertex(i).active==True): # aclist.append(i) # if len(aclist)>0: # dousasuru=1 if xshade.scene().active_shape().type==7 and len(xshade.scene().active_shapes)==1: if xscene.is_modify_mode==True and xscene.selection_mode==2: for i in range(ashape.total_number_of_control_points): if (ashape.vertex(i).active==True): if(ashape.vertex(i).position[0]>0): aclist.append(i) if(ashape.vertex(i).position[0]<0): minusaclist2.append(i) if (len(aclist)>0 and len(minusaclist2)==0 and ashape.skin_type==1): dousasuru=1 if dousasuru>0: #上位パートに変換がかかっているなら動作しない if xshade.scene().active_shape().local_to_world_matrix!=((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0)): dousasuru=0 dialog=xshade.create_dialog() dialog.append_push_button('上位パートに変換がかかっているため') dialog.append_push_button('スクリプトが実行できません') dialog.append_push_button('上位パートの変換をリセットするか') dialog.append_push_button('ポリゴンメッシュを変換のかかっていない') dialog.append_push_button('パートに移動してから実行してください') dialog.ask('エラー') dousasuru=2 if dousasuru==0: dialog=xshade.create_dialog() idx1=dialog.append_push_button('ポリゴンメッシュを一つだけ選択し、') idx2=dialog.append_push_button('頂点選択モードで、X座標が0以上の頂点だけを') idx3=dialog.append_push_button('複数選択してください') idx4=dialog.append_push_button('スキンタイプは「頂点ブレンド」でのみ使えます') kekka=dialog.ask('ウェイトのミラーコピー') if dousasuru==1: gosa=0.01 sagasu=0 syuturyoku=False minusaclist=return_invert_point(aclist) # for tete in minusaclist: # xshade.scene().active_shape().vertex(tete).active=True dialog=xshade.create_dialog() # idx1=dialog.append_float('誤差') idx2=dialog.append_selection('対のボーンは/名前で探す/位置で探す') idx3=dialog.append_bool('ボーンリストの出力') # dialog.set_value(idx1,gosa) dialog.set_value(idx2,sagasu) dialog.set_value(idx3,syuturyoku) kekka=dialog.ask('ウェイトのミラーコピー') if kekka==True: # gosa=dialog.get_value(idx1) gosa=0.1 sagasu=dialog.get_value(idx2) syuturyoku2=dialog.get_value(idx3) xshade.scene().copy_object([0.0, 0.0, 0.0], [1, 1, 1], None, [0.0, 0.0, 0.0]) xscene.select_sister() xscene.active_shape().render_flag=0 xscene.active_shape().hide() xscene.select_brother() ashape=xscene.active_shape() bindlist=[] #そのポリゴンメッシュにバインドされているジョイントのリスト negabindlist=[] #反対位置にあるジョイントのリスト bindlist=return_bindlist() # negabindlist=return_negativelist(bindlist,gosa) if(sagasu==1): negabindlist=return_negativelist(bindlist,gosa) else: negabindlist=return_negativelist2(bindlist) if(syuturyoku2==True): exlist(bindlist,negabindlist) # for debug # debugyou(bindlist) # debugyou(negabindlist) # print bindlist # print negabindlist for i in aclist: error1=0 yaru=0 motobindsuu=ashape.vertex(i).skin.number_of_binds min1=100000 sakipoint=minusaclist[0] # for jj in range(ashape.total_number_of_control_points): for jj in minusaclist: tempvec=(-ashape.vertex(i).position[0],ashape.vertex(i).position[1],ashape.vertex(i).position[2]) tempvec2=(ashape.vertex(jj).position[0],ashape.vertex(jj).position[1],ashape.vertex(jj).position[2]) kyorii=(tempvec[0]-tempvec2[0])**2+(tempvec[1]-tempvec2[1])**2+(tempvec[2]-tempvec2[2])**2 if (kyorii0: # for ig in range(ashape.vertex(sakipoint).skin.number_of_binds): # ashape.vertex(sakipoint).skin.remove_bind(bindsuu2-ig-1) # xshade.skin_view().update() #スキンウインドウを更新して変更を反映する # xshade.scene().active_shape().update_skin_bindings() #スキンの設定を更新して変更を反映する #新たにバインドを追加 # for ig in range (ashape.vertex(i).skin.number_of_binds): # ashape.vertex(sakipoint).skin.append_bind() #bind数が違うなら、揃える bindsuu2=ashape.vertex(sakipoint).skin.number_of_binds if( (motobindsuu-bindsuu2)>0): tempnum=motobindsuu-bindsuu2 for tt in range(tempnum): ashape.vertex(sakipoint).skin.append_bind() if( (bindsuu2-motobindsuu)>0): tempnum=bindsuu2-motobindsuu tempnum2=tempnum for tt in range(tempnum): ashape.vertex(sakipoint).skin.remove_bind(tempnum2-tt) xshade.skin_view().update() #スキンウインドウを更新して変更を反映する xshade.scene().active_shape().update_skin_bindings() #スキンの設定を更新して変更を反映する for bb in range(motobindsuu): #反対側にあるジョイントをゲットする num1=0 for oo in bindlist: if(oo.name==ashape.vertex(i).skin.get_bind(bb).shape.name): break else: num1+=1 ashape.vertex(sakipoint).skin.get_bind(bb).shape=negabindlist[num1] # print negabindlist[num1].name ashape.vertex(sakipoint).skin.get_bind(bb).weight=ashape.vertex(i).skin.get_bind(bb).weight xshade.skin_view().update() #スキンウインドウを更新して変更を反映する xshade.scene().active_shape().update_skin_bindings() #スキンの設定を更新して変更を反映する if error1==0: dialog2=xshade.create_dialog() idx1=dialog2.append_push_button('ミラーコピーしました') kekka=dialog2.ask('ウェイトのミラーコピー') else: dialog2=xshade.create_dialog() idx1=dialog2.append_push_button('一部の頂点のミラーコピーに失敗しました') idx2=dialog2.append_push_button('誤差の値を上げてやり直してください') kekka=dialog2.ask('ウェイトのミラーコピー')