2012/12/20

melからpymelへ書き換えてみる【その1】

凍りかけのプリンは美味しいですね!
今日は久しぶりにPythonネタです。
PyMELを推したりオブジェクト指向について思いを馳せたりしていましたが、結局のところは、書かないと身についたりはしないぜ!というのはあると思います。
とはいえ、なに書こっかなーとハタと立ち止まり改めて考えてみると思いつかなかったりしますし、
必要に迫られて書くとなると、だいたいそういう場合って鉄は熱いうちに打て的な感じでとにかくさっさと書きたいからつい慣れてるmelに走りがち、という向きはあるのではないかと思います。
自分がそうです……

お題は見つけやすいところからということで、
今回は先日のセットアップの記事に載せたmelを取り上げつつ
MELからPyMELへの書き換えについて、順を追って考えていってみたいと思います。

【その2】はこちらへ!


※考え方を追っていくというのが主眼ですので、陥りやすい間違いとして回り道をしている部分も多々あります。
※原則「 import pymel.core as pm 」でpymelをインポートした状態として書いています。
「from pymel import *」はオーバーライド(隠蔽)が不安なこともあり、ここでは使いません。


ひとつめはこのようなスクリプトでした↓

string $objs[]=`ls -sl`;
for ($obj in $objs){
    move 0 0 0 ($obj+".scalePivot") ($obj+".rotatePivot") ;
    FreezeTransformations;
    }

[フリーズをかけてpivotを原点にもっていくスクリプト]。モデリング完了時、セットアップ開始前に使うげなやつです。
ここではこれをPyMELに書き換えていきたいと思います。


string $objs[]=`ls -sl`;

スクリプトの起点として頻出する「ls -sl」ですが、
PyMELでは、この部分を使いやすく改善するちょっとした提案がなされています。
selected()というメソッドが用意されていて、これが「ls -sl」と同じ働きをします。

ヘルプはこちら→http://download.autodesk.com/largefiles/jp/product/20100520_2011_maya_onlinehelp/PyMel/generated/functions/pymel.core.general/pymel.core.general.selected.html#pymel.core.general.selected 
help書くまでもないぜ!といわんばかりのドラスティックな解説です。

Maya上でオブジェクトを選択して

pm.selected()

を実行すると、オブジェクトのリストが返ってきます。
このとき、MELのls -slだと、選択したオブジェクトの名前の配列が返ってきていたことに留意してください。
つまり文字列(の配列)が返ってきていたわけです。
怨念の文字列駆動

ところがここで返ってくる「オブジェクトのリスト」とは、Pythonの方のオブジェクト(coreモジュール内のTansformクラス)のリストです。MELのリストは数値や文字列しか入れられませんでしたが、Pythonのリストはそれに限らずいろいろな物が入ります。ここではオブジェクト(=値と関数をまとめたやつ)をリストにして返してくれています。

さて…
このようにして取得したオブジェクトのリストを、for-inループに入れます。
こんな感じ↓

for obj in pm.selected():
    (処理)

最初のMELでは、ls -slを一旦 変数$objsに入れてからループに使っていましたが、ここでは変数に一旦入れるなどせず、いきなりループに入れています。
実はこういうダイレクトアタックな書き方は、MELでも可能です。

for ($obj in `ls -sl`){
    move 0 0 0 ($obj+".scalePivot") ($obj+".rotatePivot") ;
    FreezeTransformations;
    }



続いて処理の部分を書き換えていきます。
もとはこれですね。

    move 0 0 0 ($obj+".scalePivot") ($obj+".rotatePivot") ;
    FreezeTransformations;

一行目ではオブジェクトのPivotを原点に持ってきています。moveで移動してますね。
二行目ではフリーズをかけています。

ここで、ちょっとPythonなマインドになってみます。
pm.selected()で、いまオブジェクトのリストを受け取っているところでした。
オブジェクトとは、値(=プロパティ)と関数(=メソッド)をまとめたものです。
ということは、pivotの座標も「値」として持っているのではないかと想像できます。
さらに、Pythonのオブジェクトのセオリーとして、持っている「値」それぞれに対して読み書きや有無の確認を行うメソッドが用意されていることがほとんどです。
プロパティ○○について、値を取得するのがget○○、値を設定するのがset○○、さらに確認や判定用にis○○has○○も用意されていることがあります。
これらはお約束のように用意されている定番メソッドだと言えると思います。

今回は、pivotを原点に持っていく、つまり0,0,0に「設定する」わけですから、set○○的なのが欲しい気がします。なんかsetPivotとか、set~~pivotとか、多分そういう名前のメソッドがあるだろうな~と念頭に置きながら、PyMELヘルプのTransformの項を眺めてみます。


さすがになにかと出会うことの多いTransformだけあって、ヘルプページの量も多いですね。まともに読み下すとなると、やや面倒です。

そこで、もとのMELの内容からメソッドを当て推量して検索してみましょう(笑
moveコマンドの行ですが、対象となっている文字列に($obj+".scalePivot")($obj+".rotatePivot")というのがありました。
scalePivotとrotatePivotはアトリビュートです。今回これらを変えたい(setしたい)わけですから、おぼろげながらこんな(↓)メソッドがあるんじゃなかろうかーと妄想します。

set scale pivot
set rotate pivot

当該ページをおもむろに検索。

「こんなメソッド無いかなー」と思って検索すると、わりかし出てきます
ありましたw


メソッド探しのもう一つの方法として、webを使わないものもご紹介しておきます。
Maya内のPyMELのhelpを利用するものです。

help()関数を使います。

今、forループに入れているオブジェクト=Transformノードについてのhelpが欲しいわけです。とりあえず、さっきのforループにいれたときと同じアプローチで、helpに入れてみましょう
↓こうなります

help(pm.selected())

すると…
help(pm.selected()) を実行

Listオブジェクトのヘルプが返ってきました。…欲しいものと違います。漂うコレジャナイ感。
そういえば先ほどpm.selected()からは「オブジェクトのリスト」が返ってきていました。中身が数値であろうと文字列であろうとオブジェクトであろうと返ってきているものはリストなので、helpに入れても、やはりリストについてのヘルプが返ってくるわけです。
欲しいのはリストの中に入っている、Transformについてのヘルプです。
リストや配列から個別の中身を取り出す場合は、[1]のように角括弧で囲ってインデックスを指定するのでした。
↓こうなります

help(pm.selected()[0])

すると、
help(pm.selected()[0]) を実行
あ、そうすか…というような返事が返ってきました。
でもこの返事から、ここで狙っているあいつは nt.Transform(u'mayaでのオブジェクト名') というクラスだということが分かりましたので、懲りずにhelpします。

help(nt.Transform)

help(nt.Transform)
でません(T_T
それもそのはず、ntなんてPythonさんにしてみたら「誰それ」ってなもんです。今回は、pymel.coreをpmとして読み込んでいるのでした。そしてもちろん、nt(=nodetypeの略)もTransformクラスもその中です。
というわけで正しくはこう↓

help(pm.nt.Transform)

help(pm.nt.Transform)
実行すると、ヘルプがずらっと表示されます。ワンテンポ遅れて。長いですからね。読み込みにちょっとかかるみたいです。
こうしてTransformクラスのヘルプがスクリプトエディタ上に表示できます。といっても、ココではだいぶ右往左往しましたが、どう調べればいいか掴んでしまえばもちろんこんなに手数はかかりません。(そしてアウトライナとかではなくビューで選択した場合はほぼTransformノードと決まっているようなものなので、最初から help(pm.nt.Transform) と覚えておいてしまえば話は早いですw)

ここで出てくるhelpはwebのものと基本的に同一で、やはりけっこうな量があります。テキストエディタに貼り付けてみると、約2600行ほどありました。


さて、
ヘルプを眺めていて気づいたのですが、
先ほど見つけていた setRotatePivot や setScalePivotとは別にsetPivotsというメソッドもあるようですね。なんだかとてもおいしそうな香りがします。
どういう匂いかというと、なんとなくRotateとScaleで分かれてたのを一括して編集できるんじゃないかなーという、そういう香ばしい感じです。
そんな期待を込めてhelpを読むと、まさにそのようなことが書いてあります( "convenience method"!)
即採用!
setPivots。 複数形なトコに意欲的な姿勢を感じます
というわけで↓この行は

    move 0 0 0 ($obj+".scalePivot") ($obj+".rotatePivot") ;
     ↓
    obj.setPivots([0,0,0])

と置き換えることができそうです。
二行目、フリーズの部分がまだですが、ここでちょっとテストしてみましょう。

import pymel.core as pm

for obj in pm.selected():
    obj.setPivots([0,0,0])

ジャーン
ジャーン
うまくいきません。
[0,0,0]を指定したはずですが、pivotたちは全然原点には来ていないですね。よく見ると、オブジェクトそれぞれの原点に来ているようです。
ヘルプをもう一度よく見てみると、Flagsの項目にobjectSpase、worldSpace、worldSpaceDistance が並んでいます。どうやら、どのフラグも有効にしない場合、デフォルトではオブジェクトスペースで効果が働くようです。ヘルプよく読まないといけませんね!
ここではワールドスペースのフラグを有効にしましょう。

    obj.setPivots([0,0,0],worldSpace=1)

これで、無事pivotが原点に移動してくれるようになりました。
最後にフリーズです。

これもメソッドあるかな…と期待したのですが見当たらないので、おとなしくmelやmaya.cmdsでのフリーズトランスレーションと同様makeIdentityを使います(そうじゃないもっとよい方法があれば是非…)

    pm.makeIdentity(obj,a=1,t=1,r=1,s=1)

引数の順番は maya.cmds のときと同じく最初に対象になるオブジェクト、つづけて各種フラグを指定します。aフラグ(apply)については、実際maya上で実行したログでも  -apply true と返ってきているのでそれに準じています。

フリーズによって軸の向きも揃っています。
このようにして完成したPythonスクリプトは↓こんな感じ

import pymel.core as pm

for obj in pm.selected():
    obj.setPivots([0,0,0],ws=1)
    pm.makeIdentity(obj,a=1,t=1,r=1,s=1)

最初のMEL版は、こうでした↓

string $objs[]=`ls -sl`;
for ($obj in $objs){
    move 0 0 0 ($obj+".scalePivot") ($obj+".rotatePivot") ;
    FreezeTransformations;
    }

後者はもうちょっと冗長性を排することもできますが、いずれにしても、Pythonすっきりしてるような気がします?

当該記事ではほかに2つのスクリプトを紹介していましたが、残りの2つについても是非また。

続きはこちら!


■参考リンク

selectedメソッド
http://autodesk.com/us/maya/2011help/PyMel/generated/functions/pymel.core.general/pymel.core.general.selected.html#pymel.core.general.selected
※melではこちら
http://download.autodesk.com/global/docs/maya2012/ja_jp/Commands/ls.html#flagselection
※maya.cmdsではこちら
http://download.autodesk.com/global/docs/maya2012/ja_jp/CommandsPython/ls.html#flagselection


Transformクラス
http://download.autodesk.com/largefiles/jp/product/20100520_2011_maya_onlinehelp/PyMel/generated/classes/pymel.core.nodetypes/pymel.core.nodetypes.Transform.html#pymel.core.nodetypes.Transform
※melではxformに相当するそうです
http://download.autodesk.com/global/docs/maya2012/ja_jp/Commands/xform.html
※maya.cmdsではこちら
http://download.autodesk.com/global/docs/maya2012/ja_jp/CommandsPython/xform.html

setPivotsメソッド
http://download.autodesk.com/largefiles/jp/product/20100520_2011_maya_onlinehelp/PyMel/generated/classes/pymel.core.nodetypes/pymel.core.nodetypes.Transform.html#pymel.core.nodetypes.Transform.setPivots


makeIdentityメソッド
http://download.autodesk.com/largefiles/jp/product/20100520_2011_maya_onlinehelp/PyMel/generated/functions/pymel.core.general/pymel.core.general.makeIdentity.html#pymel.core.general.makeIdentity
※mel
http://download.autodesk.com/global/docs/maya2012/ja_jp/Commands/makeIdentity.html
※maya.cmds
http://download.autodesk.com/global/docs/maya2012/ja_jp/CommandsPython/makeIdentity.html

pythonで繰り返し作業 ~for-inループ編~ @萌えるmel読本の中の人が書くブログ
http://sproutmel.blogspot.jp/2012/05/pythonfor-in.html

help関数 @Python 標準ライブラリ>>2. 組み込み関数
http://docs.python.jp/2/library/functions.html?highlight=help#help

PyMELはだれのために?@pymel - Python in Maya Done Right
http://code.google.com/p/pymel/#Who_is_PyMEL_for?

0 件のコメント:

コメントを投稿