2012/04/15

[pymel] 頂点を整列させるツール

MELを始めて一番最初に作ったツールなんですが、
今回はこれをpymel化のいけにえにしてみました。


# -*- coding: utf-8 -*-
#------------------------------------------------------------------------------
# 頂点の整列ツール
#------------------------------------------------------------------------------
import pymel.core as pm
import sys
sys.dont_write_bytecode = True

#------------------------------------------------------------------------------
# 整列処理
#------------------------------------------------------------------------------
def AlignVertex(axis, mode, sp):
 # ~ 引数 ~
 # axis 0:X 1:Y 2:Z
 # mode 0:最小 1:センター 2:平均 3:最大
 #  sp  0:オブジェクトモード 1:ワールドモード
 space = ['object', 'world'][sp]

 # セレクションをバーテックスに変換
 if not pm.selected():
  return
 pm.runtime.ConvertSelectionToVertices(pm.selected(flatten=True))
 vtxList = pm.filterExpand(selectionMask=31)

 # 全頂点の座標を取得し、最大、最小、平均、中心を求める
 pos = [pm.PyNode(p).getPosition(space=space)[axis] for p in vtxList]
 posMax = max(pos)
 posMin = min(pos)
 posAve = sum(pos) / len(vtxList)
 posCen = (posMax + posMin) / 2

 # 押されたボタンから移動する場所を決める
 if mode == 0: value = posMin
 if mode == 1: value = posCen
 if mode == 2: value = posAve
 if mode == 3: value = posMax

 # オブジェクトモードならこっち
 if space == 'object':
  if axis == 0:
   pm.move(value, vtxList, moveX=True, objectSpace=True)
  if axis == 1:
   pm.move(value, vtxList, moveY=True, objectSpace=True)
  if axis == 2:
   pm.move(value, vtxList, moveZ=True, objectSpace=True)
 # ワールドモードならこっち
 else:
  if axis == 0:
   pm.move(value, vtxList, moveX=True)
  if axis == 1:
   pm.move(value, vtxList, moveY=True)
  if axis == 2:
   pm.move(value, vtxList, moveZ=True)

 # ビュー上でアンドゥが効かなくなるのでフォーカスを元に戻しておこう
 pm.setFocus(pm.getPanel(withFocus=True) )


#------------------------------------------------------------------------------
# GUI
#------------------------------------------------------------------------------
class GUI:
 windowName = "Align_Vertex_Tool"
 _checkBox = None

 # 初期化
 def __init__(self):
  if pm.window(self.windowName, exists=True):
   pm.deleteUI(self.windowName)

 # ボタンを押した時のアクション
 def callBack(self, axis, mode, *args):
  AlignVertex(axis, mode, self.checkBox.getValue() )

 def show(self):
  window = pm.window(self.windowName, title=self.windowName)
  window.setWidth(180)
  window.setHeight(240)

  labelText = ["X", "Y", "Z"]
  BGColor = [[1.0, 0.5, 0.5], [0.5, 1.0, 0.5], [0.5, 0.5, 1.0]]
  buttonLabel = ["- <-", "cen", "ave", "-> +"]
  with window:
   with pm.frameLayout(borderStyle="in", label=u"頂点の整列ツール"):
    for i in range(0, 3):
     with pm.frameLayout(borderStyle="in", label=labelText[i] + u"軸", marginHeight=4, marginWidth=4, backgroundColor=BGColor[i]):
      with pm.rowLayout(numberOfColumns=4):
       for j in range(0, 4):
        pm.button(label=buttonLabel[j], width=40, height=32, command=pm.Callback(self.callBack, i, j) )
    self.checkBox = pm.checkBox(label=u"ワールド軸(off / ローカル)", value=True)

def main():
 w = GUI()
 w.show()

main()

スクリプトエディタにコピペして実行するとこんなのが出来ます。


MELだと結構な行数取ってる最大、最小、平均、中心の計算が
それぞれ1行で出来ちゃうのがpythonのすごいとこですねー。
(↑pymel関係無いじゃん。。)

わりと使い勝手が良いので使ってやってください。


こっちが元になったMEL
// --------------------------------------------------------------------------
// 頂点の整列ツール
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// 頂点計算部分
// --------------------------------------------------------------------------
global proc AVT_AlignVertex(int $command) {
 string $selectComp[] = `ls -sl -fl`;
 if(size($selectComp) ) return;
 PolySelectConvert 3;
 string $vtxList[] = `filterExpand -sm 31`;

 float $maxX = $maxY = $maxZ = $minX = $minY = $minZ = 0.0;
 float $cenX = $cenY = $cenZ = $aveX = $aveY = $aveZ = 0.0;

 for($i = 0; $i < size($vtxList); $i++) {
  float $tmp[] = `pointPosition -w $vtxList[$i]`;
  if($i == 0) {
   $maxX = $minX = $tmp[0];
   $maxY = $minY = $tmp[1];
   $maxZ = $minZ = $tmp[2];
  }
  else {
   $maxX = `max $tmp[0] $maxX`;
   $minX = `min $tmp[0] $minX`;
   $maxY = `max $tmp[1] $maxY`;
   $minY = `min $tmp[1] $minY`;
   $maxZ = `max $tmp[2] $maxZ`;
   $minZ = `min $tmp[2] $minZ`;
  }
  $aveX += $tmp[0];
  $aveY += $tmp[1];
  $aveZ += $tmp[2];
 }

 $cenX = ($maxX + $minX) / 2;
 $cenY = ($maxY + $minY) / 2;
 $cenZ = ($maxZ + $minZ) / 2;
 $aveX /= $i;
 $aveY /= $i;
 $aveZ /= $i;

 switch($command) {
  case 1 : move -a -x $minX; break;
  case 2 : move -a -x $cenX; break;
  case 3 : move -a -x $aveX; break;
  case 4 : move -a -x $maxX; break;

  case 11 : move -a -y $maxY; break;
  case 12 : move -a -y $cenY; break;
  case 13 : move -a -y $aveY; break;
  case 14 : move -a -y $minY; break;

  case 21 : move -a -z $maxZ; break;
  case 22 : move -a -z $cenZ; break;
  case 23 : move -a -z $aveZ; break;
  case 24 : move -a -z $minZ; break;

  default : break;
 }

 string $panel = `getPanel -withFocus`;
 setFocus $panel;
}


// --------------------------------------------------------------------------
//
// GUI関係
//
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// X軸レイアウト
// --------------------------------------------------------------------------
global proc string AVT_CreateXAxisPanel(string $GetPanel) {
 string $PanelName = `frameLayout -l " X軸" -bgc 1.0 0.5 0.5`;
 string $XButtonGrp = `formLayout -bgc 1.0 0.5 0.5`;
 button -l "-方向" -c "AVT_AlignVertex(1)" XButton1;
 button -l "中央" -c "AVT_AlignVertex(2)" XButton2;
 button -l "平均" -c "AVT_AlignVertex(3)" XButton3;
 button -l "+方向" -c "AVT_AlignVertex(4)" XButton4;

 formLayout -e
  -af XButton1 top  5
  -af XButton1 left 5

  -af XButton2 top  5
  -ac XButton2 left 5 XButton1

  -af XButton3 top  5
  -ac XButton3 left 5 XButton2

  -af XButton4 top  5
  -ac XButton4 left 5 XButton3
  -af XButton4 bottom 5
 $XButtonGrp;
 setParent ..;

 setParent $GetPanel;

 return $PanelName;
}


// --------------------------------------------------------------------------
// Y軸レイアウト
// --------------------------------------------------------------------------
global proc string AVT_CreateYAxisPanel(string $GetPanel) {
 string $PanelName = `frameLayout -l " Y軸" -bgc 0.5 1.0 0.5`;
 string $YButtonGrp = `formLayout -bgc 0.5 1.0 0.5`;
 button -l "+方向" -c "AVT_AlignVertex(11)" YButton1;
 button -l "中央" -c "AVT_AlignVertex(12)" YButton2;
 button -l "平均" -c "AVT_AlignVertex(13)" YButton3;
 button -l "-方向" -c "AVT_AlignVertex(14)" YButton4;

 formLayout -e
  -af YButton1 top  5
  -af YButton1 left 5

  -af YButton2 top  5
  -ac YButton2 left 5 YButton1

  -af YButton3 top  5
  -ac YButton3 left 5 YButton2

  -af YButton4 top  5
  -ac YButton4 left 5 YButton3
  -af YButton4 bottom 5
 $YButtonGrp;
 setParent ..;

 setParent $GetPanel;

 return $PanelName;
}


// --------------------------------------------------------------------------
// Z軸レイアウト
// --------------------------------------------------------------------------
global proc string AVT_CreateZAxisPanel(string $GetPanel) {
 string $PanelName = `frameLayout -l " Z軸" -bgc 0.5 0.5 1.0`;
 string $ZButtonGrp = `formLayout -bgc 0.5 0.5 1.0`;
 button -l "-方向" -c "AVT_AlignVertex(21)" ZButton1;
 button -l "中央" -c "AVT_AlignVertex(22)" ZButton2;
 button -l "平均" -c "AVT_AlignVertex(23)" ZButton3;
 button -l "+方向" -c "AVT_AlignVertex(24)" ZButton4;

 formLayout -e
  -af ZButton1 top  5
  -af ZButton1 left 5

  -af ZButton2 top  5
  -ac ZButton2 left 5 ZButton1

  -af ZButton3 top  5
  -ac ZButton3 left 5 ZButton2

  -af ZButton4 top  5
  -ac ZButton4 left 5 ZButton3
  -af ZButton4 bottom 5
 $ZButtonGrp;
 setParent ..;

 setParent $GetPanel;

 return $PanelName;
}


// --------------------------------------------------------------------------
// メイン
// --------------------------------------------------------------------------
global proc alignVertexTool() {
 if(`window -ex AVT_window`) deleteUI AVT_window;

 window -t "Align Vertex Tool" -s false AVT_window;

 int $uiWidth  = 145;
 int $uiHeight = 230;

 string $AllForm = `formLayout`;
 text -l "頂点の整列ツール" -w $uiWidth -font "boldLabelFont" TitleTxt;
 string $XPanel = `AVT_CreateXAxisPanel($AllForm)`;
 string $YPanel = `AVT_CreateYAxisPanel($AllForm)`;
 string $ZPanel = `AVT_CreateZAxisPanel($AllForm)`;

 formLayout -e
  -af TitleTxt top  5
  -af TitleTxt left 5

  -ac $XPanel  top  5 TitleTxt
  -af $XPanel  left 2
  -af $XPanel  right 2

  -ac $YPanel  top  5 $XPanel
  -af $YPanel  left 2
  -af $YPanel  right 2

  -ac $ZPanel  top  5 $YPanel
  -af $ZPanel  left 2
  -af $ZPanel  right 2
 $AllForm;
 setParent ..;

 showWindow AVT_window;
 window -e -wh $uiWidth $uiHeight AVT_window;
}

alignVertexTool();

1 件のコメント:

  1. 【Maya】大倶利伽羅の髪の毛を作る。4 | Create3D-3dCG制作作業日記

    こちらのページでスクリプトとその使い方を書かせていただきました。
    本当に、作ってくださってありがとうございます。ありがとうございます!

    返信削除