import random #選択している頂点が、その頂点の法線方向へ移動 #上位パートに変換がかかっていると使用できないように変更(2010.03.03) #角の丸めがONの状態でも正常に動作するよう修正(2010.11.20) #ダイアログ #ラジオボタン「頂点の法線方向へ移動」「接続点の平均法線方向へ移動」「接続点の中心方向へ移動」 #チェックボックス「選択点は除外」・・・・「接続点の〜」が選択の時のみ機能。接続点のうち選択状態の頂点は平均値算出の際対象外にする #数値入力「移動量」 #ラジオボタン「ふくらます」「へこます」・・・・「移動量」にマイナスを入れてもへこませる #チェックボックス「座標を固定X」・・・・・X座標は固定する #チェックボックス「座標を固定Y」・・・・・Y座標は固定する #チェックボックス「座標を固定Z」・・・・・Z座標は固定する #連続・・・・・取り消しの場合、再びダイアログを開いて数値入力可能に #下の階層(弟)に「法線情報_開いた線形状」があったら「特定の方向へ移動」オプションを表示 #「連続」チェックボックスがONの状態で結果をキャンセルするとダイアログが再び開いてやり直しできる #動作条件 #現在編集モードに入っている #選択形状がポリゴンメッシュ #頂点が一つでも選択されている #頂点選択モードになっている #頂点を移動する度に頂点の法線方向が変わるかもしれないので、最初に各頂点の法線情報のリストを作成 def hanteiss(str): #文字列の中に@がないか確認してあったら1を返す、無かったら0を返す hantei=0 for i in range(len(str)): if str[i]=='@':hantei+=1 if hantei>0: return(1) else: return(0) def return_pointlist2(): #接続点のリストを頂点番号順に格納したリストを作成して返す(一度作っておけば、後はすぐ接続頂点をわりだせる) setuzokulist=[] for i in range(xshade.scene().active_shape().total_number_of_control_points): setuzokulist.append([]) for i in range(xshade.scene().active_shape().number_of_edges): p1=xshade.scene().active_shape().edge(i).v0 p2=xshade.scene().active_shape().edge(i).v1 temp=setuzokulist[p1] temp.append(p2) setuzokulist[p1]=temp temp=setuzokulist[p2] temp.append(p1) setuzokulist[p2]=temp return setuzokulist def return_uvpar(pointnum): #頂点番号pointnumのパラメーターベースのUV値(二項のタプル)を返す関数(距離ベースの場合は修正して使用) #面を持ってない場合は-1の値を返す returnnum=[-1,-1] pointorder=0 breakon=0 #頂点が属している面を一つでも発見する for uu in range(xshade.scene().active_shape().number_of_faces): pointlist2=list(xshade.scene().active_shape().face(uu).vertex_indices) for vv in range(len(pointlist2)): if pointlist2[vv]==pointnum: returnnum=xshade.scene().active_shape().face(uu).parameter_uv[vv] breakon=1 break if breakon==1: break return returnnum def return_uvkyori(pointnum): #頂点番号pointnumのパラメーターベースのUV値(二項のタプル)を返す関数(距離ベースの場合は修正して使用) #面を持ってない場合は-1の値を返す returnnum=[-1,-1] pointorder=0 breakon=0 #頂点が属している面を一つでも発見する for uu in range(xshade.scene().active_shape().number_of_faces): pointlist2=list(xshade.scene().active_shape().face(uu).vertex_indices) for vv in range(len(pointlist2)): if pointlist2[vv]==pointnum: returnnum=xshade.scene().active_shape().face(uu).distance_uv[vv] breakon=1 break if breakon==1: break return returnnum def sort_point_by_active_order(pointlist): #頂点の選択番号(active_order)順にリストの頂点番号をソートして頂点リストを返す #ソート templist=[] for i in pointlist: templist.append(i) newlist=[] while(len(newlist)0: activepointlist.append(i) # activepointlist2=sort_point_by_active_order(activepointlist) 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.ask('エラー') if dousasuru==1: if xshade.scene().is_modify_mode==True and xshade.scene().active_shape().type==7 and xshade.scene().selection_mode == 2 and len(activepointlist)>0: ttt=11 else: dousasuru=0 #角の丸めがかかってるなら警告を表示 #if dousasuru==1: # motoround=xshade.scene().active_shape().round # ashape=xshade.scene().active_shape() # xscene=xshade.scene() # num1=ashape.total_number_of_control_points # xscene.copy() # xscene.paste() # xshade.scene().active_shape().convert_to_polygon_mesh_with_subdivision_level(1) # num2=xshade.scene().active_shape().total_number_of_control_points # xscene.clear() # xscene.enter_modify_mode() # name2=xshade.scene().active_shape().name # if num1!=num2 and hanteiss(name2)==0: # dialognum=xshade.create_dialog() # dialognum.append_push_button('角の丸めがONに') # dialognum.append_push_button('なっています。') # dialognum.append_push_button('結果がおかしくなる') # dialognum.append_push_button('場合は、一時的に角の丸め') # dialognum.append_push_button('をOFFにしてください') # dialognum.ask('警告') #条件を満たしているならプログラムスタート if dousasuru==1: yarinaosi=1 #ここにダイアログの初期値 idoumode=0#0で頂点法線方向へ 1で接続点の法線平均値方向へ 2で接続点の中心方向へ zyogai=0#接続点の法線平均値方向へ移動の場合、選択されてる頂点は平均値の算出の対象外とするかどうか0でOFF、1でON hukuramasu=1#1でふくらます、-1でへこます idouryou=200#移動量 renzoku=1#結果を取り消した場合に1なら改めてウインドウを開く、0なら終了 xkotei=0#1ならx座標固定、0なら固定しない ykotei=0#1ならy座標固定、0なら固定しない zkotei=0#1ならz座標固定、0なら固定しない randomon=0#1ならランダムON、0ならOFF randommin=0 randommax=100 sikiimin=0#底値 sikiimax=100#天井値 setuzokutenon=0#接続点の選択状態によって移動量を減らす nikai=0#接続点の接続点の選択状態を調べるかどうか skeisuu=0.7#減らす量 dainikeisuu=0.9#減らす量その2 sankai=0#接続点の接続点の接続点も調べるかどうか daisankeisuu=0.9#減らす量その3 gazouok=0#1ならUV画像を使うかどうかのダイアログを足す gazoutukau=0#1ならUV画像を使う kizyun=0#0ならグレーを0に(-1から1)、1なら黒を0に(0から1) hanten=0#1なら画像を反転 uvpar=0#1ならUVで0なら距離で displace=1.00000000#画像によるディスプレイスメントの掛け率 tokutei=0#これが1なら特定の方向へ押し出す #表面材質を持ってて、かつ、レイヤー1に画像を設定しており、かつuv値が設定されているか? if xshade.scene().active_shape().has_surface_attributes==1: if xshade.scene().active_shape().surface.mapping_layer(0).pattern_name=='イメージ' and xshade.scene().active_shape().face(0).has_uv==1: gazouok=1 while(renzoku==1): #ダイアログを開く dialog=xshade.create_dialog() # dialog.begin_group('方向') # idx1=dialog.append_radio_button('/頂点の法線方向へ/接続点の平均法線方向へ/接続点の中心方向へ') # idx2=dialog.append_bool('接続点のうち選択点は除外') # dialog.end_group() dialog.begin_group() idx3=dialog.append_radio_button('/ふくらます/へこます') idx4=dialog.append_float('移動量') dialog.end_group() #ポリゴンメッシュ形状のすぐ下(弟階層)に「法線情報_開いた線形状」があったら特別なオプション表示 if xshade.scene().active_shape().has_bro==1: if xshade.scene().active_shape().bro.name[:6]=='法線': idx44=dialog.append_bool('特定の方向へ移動') dialog.begin_group() tuikabun='' # if xshade.scene().active_shape().total_number_of_control_points>3000: # tuikabun='(非推奨)' # if xshade.scene().active_shape().total_number_of_control_points>3000: # tuikabun='(危険:総頂点数が多すぎます)' idx14=dialog.append_bool('接続点の選択状況で移動量を減らす'+tuikabun) idx15=dialog.append_float('係数(0〜1)') idx16=dialog.append_bool('接続点の接続点も調べる(slow)') idx17=dialog.append_float('第二係数(0〜1)') #選択している頂点数が多すぎる場合は↓は表示しない if xshade.scene().active_shape().number_of_active_control_points<4000: idx31=dialog.append_bool('接続点の接続点の接続点も調べる(more slow)') idx32=dialog.append_float('第三係数(0〜1)') dialog.end_group() if gazouok==1: dialog.begin_group() idx21=dialog.append_bool('UV画像を使用する(slow)') dialog.begin_box(False) idx22=dialog.append_radio_button('基準/グレーを0に/黒を0に') idx24=dialog.append_radio_button('タイプ/距離/UV') dialog.end_box() idx23=dialog.append_bool('反転') dialog.end_group() dialog.begin_group() idx6=dialog.append_bool('x座標固定') idx7=dialog.append_bool('y座標固定') idx8=dialog.append_bool('z座標固定') dialog.end_group() dialog.begin_group() idx9=dialog.append_bool('ランダム') idx10=dialog.append_int('最小値') idx11=dialog.append_int('最大値') idx12=dialog.append_int('底値') idx13=dialog.append_int('天井値') dialog.end_group() #210 idx5=dialog.append_bool('取り消しの際はダイアログを再び開く') # dialog.set_value(idx1,idoumode) # dialog.set_value(idx2,zyogai) if hukuramasu==1: dialog.set_value(idx3,0) else: dialog.set_value(idx3,1) dialog.set_value(idx4,idouryou) dialog.set_value(idx5,renzoku) dialog.set_value(idx6,xkotei) dialog.set_value(idx7,ykotei) dialog.set_value(idx8,zkotei) dialog.set_value(idx9,randomon) dialog.set_value(idx10,randommin) dialog.set_value(idx11,randommax) dialog.set_value(idx12,sikiimin) dialog.set_value(idx13,sikiimax) dialog.set_value(idx14,setuzokutenon) dialog.set_value(idx15,skeisuu) dialog.set_value(idx16,nikai) dialog.set_value(idx17,dainikeisuu) if xshade.scene().active_shape().number_of_active_control_points<4000: dialog.set_value(idx31,sankai) dialog.set_value(idx32,daisankeisuu) if xshade.scene().active_shape().has_bro==1: if xshade.scene().active_shape().bro.name[:6]=='法線': dialog.set_value(idx44,tokutei) if gazouok==1: dialog.set_value(idx21,gazoutukau) dialog.set_value(idx22,kizyun) dialog.set_value(idx23,hanten) dialog.set_value(idx24,uvpar) kekka1=dialog.ask('法線方向へ移動') # idoumode=dialog.get_value(idx1) # zyogai=dialog.get_value(idx2) if dialog.get_value(idx3)==0: hukuramasu=1 else: hukuramasu=-1 idouryou=dialog.get_value(idx4) renzoku=dialog.get_value(idx5) xkotei=dialog.get_value(idx6) ykotei=dialog.get_value(idx7) zkotei=dialog.get_value(idx8) randomon=dialog.get_value(idx9) randommin=dialog.get_value(idx10) randommax=dialog.get_value(idx11) sikiimin=dialog.get_value(idx12) sikiimax=dialog.get_value(idx13) setuzokutenon=dialog.get_value(idx14) skeisuu=dialog.get_value(idx15) nikai=dialog.get_value(idx16) dainikeisuu=dialog.get_value(idx17) if xshade.scene().active_shape().number_of_active_control_points<4000: sankai=dialog.get_value(idx31) daisankeisuu=dialog.get_value(idx32) if xshade.scene().active_shape().has_bro==1: if xshade.scene().active_shape().bro.name[:6]=='法線': tokutei=dialog.get_value(idx44) if gazouok==1: gazoutukau=dialog.get_value(idx21) kizyun=dialog.get_value(idx22) hanten=dialog.get_value(idx23) uvpar=dialog.get_value(idx24) if kekka1==False: renzoku=0 if kekka1==True: #元の形状をクリップボードにコピーしておく xshade.scene().active_shape().copy() xshade.scene().enter_modify_mode() #形状の頭に「@」をつける # tname=xshade.scene().active_shape().name # xshade.scene().active_shape().name='@'+tname # xshade.scene().active_shape().round=0 # xshade.scene().update_figure_window() #最初に各頂点の現在の法線リストを作る # normallist2=[] # for i in range(xshade.scene().active_shape().total_number_of_control_points): # #以下のようにまわりくどい事をしてないと法線情報を書き換えてしまう事になる? # tempvec55=xshade.scene().active_shape().vertex(i).normal # normallist2.append((tempvec55[0],tempvec55[1],tempvec55[2])) #最初に選択頂点の現在の法線リストを作る xshade.scene().active_shape().setup_normal() normallist2=[] for i in activepointlist: #以下のようにまわりくどい事をしてないと法線情報を書き換えてしまう事になる tempvec55=xshade.scene().active_shape().vertex(i).normal normallist2.append((tempvec55[0],tempvec55[1],tempvec55[2])) #ワイヤーフレームの更新を一時停止 xshade.scene().active_shape().begin_set_point() #次に(画像を使う場合は)UV情報のリストを頂点番号順に格納していく if gazoutukau==1: uvlist=[] for uvv in range(xshade.scene().active_shape().total_number_of_control_points): uvlist.append([1.0,1.0]) for uvv in range(xshade.scene().active_shape().number_of_faces): vlist=xshade.scene().active_shape().face(uvv).vertex_indices if uvpar==1: tyoutenuvlist=xshade.scene().active_shape().face(uvv).parameter_uv else: tyoutenuvlist=xshade.scene().active_shape().face(uvv).distance_uv for vmmm in range(len(vlist)): uvlist[vlist[vmmm]]=tyoutenuvlist[vmmm] #接続点を使う場合は頂点番号順に接続点のリストを作る if setuzokutenon==1: setuzokutenlist2=return_pointlist2() #最初に各頂点の座標リストを作る # positionlist=[] # for i in range(xshade.scene().active_shape().total_number_of_control_points): # positionlist.append([xshade.scene().active_shape().vertex(i).position[0],xshade.scene().active_shape().vertex(i).position[1],xshade.scene().active_shape().vertex(i).position[2]]) #選択頂点を法線方向へ移動 # xshade.scene().inhibit_update() #「特定の方向へ移動」がONの場合の移動方向と長さを設定 if tokutei==1: otouto=xshade.scene().active_shape().bro tempnormal=[otouto.control_point(0).position[0]-otouto.control_point(1).position[0],otouto.control_point(0).position[1]-otouto.control_point(1).position[1],otouto.control_point(0).position[2]-otouto.control_point(1).position[2]] #長さを調整 temppointn=xshade.scene().active_shape().vertex(activepointlist[0]).normal nagasakizyun=pow((temppointn[0])**2+(temppointn[1])**2+(temppointn[2])**2,0.5) tempnnagasa=pow((tempnormal[0])**2+(tempnormal[1])**2+(tempnormal[2])**2,0.5) tempnormal=[tempnormal[0]*nagasakizyun/tempnnagasa,tempnormal[1]*nagasakizyun/tempnnagasa,tempnormal[2]*nagasakizyun/tempnnagasa] pnumber=0 for i in activepointlist: #元の座標を保存しておく motoposition=(xshade.scene().active_shape().vertex(i).position[0],xshade.scene().active_shape().vertex(i).position[1],xshade.scene().active_shape().vertex(i).position[2]) #方向のベクトルを求める houkou=[0,0,0] if idoumode==0: #302 houkou=xshade.scene().active_shape().vertex(i).normal houkou=normallist2[pnumber] #「特定の方向へ移動」がONの場合は全ての頂点が同じ方向へ移動 if tokutei==1: houkou=tempnormal if idoumode==1: #接続点の平均値をリスト化して求める setuzokutenlist=return_pointlist(i) #選択除外の場合は(このモードは使用せず) if zyogai==1: setuzokutenlist=substract_b_from_a(setuzokutenlist,activepointlist) #法線の平均値は tempvec=[0,0,0] for pp in range(len(setuzokutenlist)): # xvec=xshade.scene().active_shape().vertex(setuzokutenlist[pp]).normal[0] # yvec=xshade.scene().active_shape().vertex(setuzokutenlist[pp]).normal[1] # zvec=xshade.scene().active_shape().vertex(setuzokutenlist[pp]).normal[2] xvec=normallist2[pp][0] yvec=normallist2[pp][1] zvec=normallist2[pp][2] tempvec[0]=tempvec[0]+xvec tempvec[1]=tempvec[1]+yvec tempvec[2]=tempvec[2]+zvec houkou=[tempvec[0]/len(setuzokutenlist),tempvec[1]/len(setuzokutenlist),tempvec[2]/len(setuzokutenlist)] if idoumode==2: #接続点の中心座標を求める(このモードも使用せず) tempsetuzokulist=return_pointlist(i) tempvecx=0 tempvecy=0 tempvecz=0 for jjj in tempsetuzokulist: tempvecx+=positionlist[jjj][0]-positionlist[i][0] tempvecy+=positionlist[jjj][1]-positionlist[i][1] tempvecz+=positionlist[jjj][1]-positionlist[i][2] #中心位置 houkou=[(tempvecx/len(tempsetuzokulist))/idouryou,(tempvecy/len(tempsetuzokulist))/idouryou,(tempvecz/len(tempsetuzokulist))/idouryou] #頂点を法線方向へ移動 # tempx=xshade.scene().active_shape().vertex(i).position[0]+idouryou*hukuramasu*houkou[0] # tempy=xshade.scene().active_shape().vertex(i).position[1]+idouryou*hukuramasu*houkou[1] # tempz=xshade.scene().active_shape().vertex(i).position[2]+idouryou*hukuramasu*houkou[2] temprandom=1 tempkeisuu=1 #接続点の非選択数によって減らすか? if setuzokutenon==1: # tempsetulist=return_pointlist(i) tempsetulist=setuzokutenlist2[i] tempcount=0 for ss in tempsetulist: if xshade.scene().active_shape().vertex(ss).active_order<1: tempcount+=1 tempcount2=0 tempcount3=0 if nikai==1: tasulist=[] for mm in tempsetulist: # tasulist+=return_pointlist(mm) tasulist+=setuzokutenlist2[mm] for mm in tasulist: if xshade.scene().active_shape().vertex(mm).active_order<1: tempcount2+=1 tasulist2=[] if sankai==1: for ccd in tasulist: tasulist2+=setuzokutenlist2[ccd] for ccd in tasulist2: if xshade.scene().active_shape().vertex(ccd).active_order<1: tempcount3+=1 temtem=1 if tempcount>0: temtem=temtem*skeisuu if nikai==1 and tempcount2>0: temtem=temtem*dainikeisuu if sankai==1 and tempcount3>0: temtem=temtem*daisankeisuu tempkeisuu=temtem if tempkeisuu<0: tempkeisuu=0 if randomon==1: temprandom=random.randint(int(randommin),int(randommax)) if sikiimin>temprandom: temprandom=sikiimin if sikiimax=imagewidth: basyox=imagewidth-1 if basyoy>=imageheight: basyoy=imageheight-1 tempred=image1.get_pixel(basyox,basyoy)[0] if kizyun==0: tempred=(tempred-0.5)*2 if hanten==1: if kizyun==0: tempred=tempred*(-1) else: tempred=1-tempred displace=tempred tempx=motoposition[0]+idouryou*hukuramasu*houkou[0]*temprandom*tempkeisuu*displace tempy=motoposition[1]+idouryou*hukuramasu*houkou[1]*temprandom*tempkeisuu*displace tempz=motoposition[2]+idouryou*hukuramasu*houkou[2]*temprandom*tempkeisuu*displace #固定がonの場合は元座標に戻す if xkotei==1: tempx=motoposition[0] if ykotei==1: tempy=motoposition[1] if zkotei==1: tempz=motoposition[2] xshade.scene().active_shape().vertex(i).position=(tempx,tempy,tempz) pnumber+=1 # xshade.scene().allow_update() #形状の頭から@を取る # xshade.scene().active_shape().name=tname # xshade.scene().active_shape().round=motoround #ワイヤーフレームの更新を再開 そしてウインドウ更新 xshade.scene().active_shape().end_set_point() xshade.scene().update_figure_window() #やりなおすかどうか kekka=True #ダイアログを表示して、選択頂点数と結果を確認してもらう #okで確定(何もせず)cancelだと元に戻す # dialog2=xshade.create_dialog_with_uuid('0x51933F00') dialog2=xshade.create_dialog_with_uuid() idxa1=dialog2.append_push_button('選択頂点'+str(len(activepointlist))+'個の') idxa2=dialog2.append_push_button('移動を完了しました。') idxa3=dialog2.append_push_button('結果を確定する場合はokを') idxa4=dialog2.append_push_button('取り消す場合はcancelを押してください') kekka=dialog2.ask('法線方向に移動') #キャンセルなら形状を削除してクリップボードの形状を元に戻す #さらに頂点の選択状態も元に戻す? if kekka==False: idou1=0 if xshade.scene().active_shape().has_sis==True: idou1=1 xshade.scene().paste() xshade.scene().select_sister(1) xshade.scene().clear() if idou1==1: xshade.scene().select_brother() xshade.scene().enter_modify_mode() for i in activepointlist: xshade.scene().active_shape().vertex(i).active=True #選択番号が変更されているので、入れなおし(今回は見送り) # for i in range(len(activepointlist2)): # xshade.scene().active_shape().vertex(activepointlist2[i]).active_order=i+1 #戻す終わり if kekka==True: renzoku=0 xshade.scene().exit_modify_mode() xshade.scene().enter_modify_mode()