チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第42回:スクリプトを配布するためのMELの作法(2/2)

  • Maya
  • ゲーム
  • コラム
  • スクリプト・API
  • チュートリアル
  • 中級者
  • 学生・初心者
  • 教育
  • 映画・TV

MELでツールを作り始めて、関数というものを知り、「global proc」はなるべく使わないようにとヘルプには書いてあるけど、思ったように動作しないから、なんだかわからないけどとりあえず「global proc」としてグローバル関数にしておけばMELが正しく動いているようなので全部これでいいかな、というずぼらな感じでツール作成をしていたことも、あります。実際のところ。が、しかし、ローカル関数と使い分けることでより安全に、便利にツール作成が出来るようになったのもまた事実。

ある程度ヘルプドキュメントにも関数の使い分け、振る舞いが書いてありますが、どうも意味がわかりにくいですよね…。理屈はなんとなくわかった気がするけど、実際にmelファイルを作って使うのに、具体的にどう気をつければいいのよ?と思ったりしたものです。それを補う感じで前回使い所を説明をしました。

今回もその続きで、具体的な使い分け方法を紹介していきます。例によってスクリプト関係の話では華やかな画像が用意できないのですがお付き合い下さい。

proc(ローカル関数)はファイル内だけで有効

前回ちょっとお話しましたが、ローカル関数はファイル内だけで有効です。廊下を指で撫でて「まだ埃が残っているようですけど…」と嫁にいう小姑のようにくどいようですが、スクリプトエディタで「proc」と書いてローカル関数を定義しても、それは実質的にグローバル関数と変わりません。ローカル関数を有効に使うにはmelファイル化が必要です。

ローカル関数は定義してあるファイル内だけで有効…。そんなこと言わないで、どこからでも実行できたほうが便利では?とも思えます。ではこの制限にはどういう利点があるでしょうか?なんといっても「関数名が既存の関数とかぶって上書きされる」ことを防げるというところが便利です。

様々なmelファイルがMayaに読み込まれます。カスタマイズ性の高いMayaですから、おのずとmelファイル数は多くなっていきます。そうなると他のmelファイルの関数の名前とかぶってしまう可能性も高くなってしまいます。意図しない関数が実行されれば不具合となってしまいます。既に関数名が使われていないかどうか全てのmelファイルを確認することは大変です。

ローカル関数はファイル内だけで使用出来るので、どんなmelファイルがあろうと関係なく、書き手が好きな関数名をつけて使用できます。名前を適当につけても大丈夫というのはとても便利で安全なことなのです。

逆にグローバル関数は他の関数と名前が同じだと上書きしてしまうので、名前を慎重に決めないといけません。大抵は作ったツールの名前を入れたり、製作者のイニシャルを入れたりすると思います。そうすれば名前が重複することはほとんど起きません。万一関数名が重複してしまったら?当然関数名を変更するのですが、変更しないといけないのはグローバル関数名だけです。ローカル関数は関係ないですから手を入れなくて済みます。グローバル関数が少なければ少ないほど変更するところも減りますので、ローカル関数を多く使うとその点でも有利です。

グローバル関数はmelファイルの窓口で、ローカル関数は裏方という感じですね。



関数名のいろいろ

さて皆さんは関数に名前をつけるのに、どんな名前をつけていますか?関数名に使用できない文字もいくつかありますが、強い制限はないので書き手が好きなスタイルで命名できます。例えば今回作ったツールでは次の関数があります。

getList()


とても普通な名前です。この関数がローカル関数だとわかりやすくするために、関数名の始めにアンダーバーをつけてみます。

_getList()


ちょっと特別な感じが出ましたね。他にも関数がどのmelファイルの関数かわかりやすくしたいと考えるかもしれません。それなら、

listNumberOfPolygon_getList()


という名前にするとわかりやすいですし、偽オブジェクト志向(!)で行くなら、

listNumberOfPolygon.getList()


というのもできます。関数名に「.(ドット)」を使っても大丈夫です。色々試して好みの命名方法を見つけて見て下さい。

ちなみに私は、グローバル関数名は偽オブジェクト指向にしています。わかりやすいですし、なんかこう、かっこいい気がするので。ローカル関数名は単に名前だけ。時々アンダーバーをスペースと見間違えてしまうことがあるので…。

GUIから呼び出すのはグローバル関数

ウインドウやボタンを作って、わかりやすく効率よく作業できるツールを作るときにも抑えておくポイントがあります。ボタンがあれば押して何かを実行します。このようにGUIがMELを実行することがあります。今回のツールではオブジェクト名のリストを選択すると、同名のオブジェクトを選択するMELが実行されます。



実はGUIから実行されるスクリプトは、スクリプトエディタで実行するのと同じことになります。GUIは作られた時点でもうmelファイル外なのです。melファイル外から実行するということは、ローカル関数にアクセス出来ないということです。GUIで実行できる関数はグローバル関数です。この点を注意しないと、melファイル化した途端に「ボタンが反応しなくなったー」とかいうことになります。



慌てず騒がず、ボタンなどから実行する関数を「global proc」と書き換えます。このためにグローバル関数が増えるのは必要なことです。

今回のツールでは、オブジェクト名のリストを選択した時に実行する関数をグローバル関数にします。次に示すの部分です。

proc selectItem()


ただ「selectItem」という名前は一般的なので他の重複する可能性があるので、ツール名を含めた名前にします。

global proc listNumberOfPolygon.select()


スクリプト内でselectItem()を実行している部分は全て新しい関数名に置き換えておきます。

GUI用グローバル関数のMayaでの一般的なアプローチ方法

Mayaに元々ついてくるスクリプトを見てみると、GUIから実行するグローバル変数を一つ用意し、ボタンごとに引数を変えて実行内容を変えるようにしています。こんな感じです。

global proc string performAlign( int $action, string $objectType, string $goToTool )


例えばウインドウを作って、ボタンを二つ作ったとします。一つは球を作るボタン、もう一つはキューブを作るボタンがある場合、

global proc createSphere()
{…}

global proc createCube()
{…}


とそれぞれのボタン用にグローバル関数を用意して実行する代わりに、一つだけグローバル関数を用意します。

global proc createPrimitive( int $type )
{…}


球を作る時は$typeに0を、キューブを作る時は1を設定します。あとは「createPrimitive」という関数内で適当に分岐して、必要に応じてローカル関数を呼び出します。これならどれだけボタンが増えても、グローバル関数は一つで済みます。美しい…。

シェルフのコマンドをmelファイル化する例

GUIということは、シェルフもマーキングメニューも同様なのです。メニューもそうです。Mayaの画面でクリックして実行しているモノたちは軒並みスクリプトエディタで実行されているのと同じことであり、グローバル関数にアクセスすることになります。

では想定されるケースを見てみたいと思います。
スクリプトエディタでツールを開発して、シェルフに登録して使う。それから配布用にmelファイル化するという流れです。

まずは次のスクリプトをツールということにして用意します。testという関数があります。実行すると「This is test」と表示されます。複雑な処理をした後のメッセージと思って下さい。



シェルフに登録してみます。実行した結果は、スクリプトエディタ上で実行した時と変わりません。



これをmelファイルにしてみましょう。
1) ファイル外からアクセスできるよう、ローカル関数をグローバル関数にします。



2) ファイル名をグローバル関数名と同じ名前にします。「test.mel」とします。
3) スクリプトのフォルダにmelファイルを置きます。
4) シェルフボタンのコマンドから、関数定義部分を削除して関数の呼び出し部分だけ残します。次の部分だけ残します。

test();


念のためMayaを起動しなおしてシェルフボタンを実行します。(起動しなおしてメモリ内に残っているproc test関数をまっさらにします)



メッセージがきちんと表示され、無事melファイル化されました。

大体こんな感じです。順にたどれば難しくはないですね。「global proc」にしないといけない、ファイル名と関数名を合わせないといけない、この二点がおざなりになって動かないというケースがほとんどです。

ルールをまとめると…

まあいろいろと試してみてきましたが、まとめてしまうとこういうルールがある、ということです。

・ proc(ローカル関数)は同melファイル内でのみアクセス可能
・ global proc(グローバル関数)はmelファイル外からでもアクセス可能
→ただし事前にmelファイル名と同じ名前のグローバル関数が呼ばれている必要あり。
・ melファイル名と同じ名前のグローバル関数が始めに読み込まれる。
→ない場合は、sourceコマンドで強制的に読み込む事になる。
・ スクリプトエディタで関数を定義したら、それはproc、global proc関係なくグローバル関数と同じ事。

これさえ知っておけばmelファイル化が安全に行えるはず!melファイル間のやり取りもスムーズに出来るのではないでしょうか。

配布可能になったツール

というわけで、これまでの情報を元に今回のツールを配布可能な状態にしてみます。「listNumberOfPolygon.mel」という名前のファイルを作り、下記のスクリプトを保存します。元々はローカル関数ばかりでしたが、必要なところはグローバル関数に変更しています。まずローカル関数にしておいてひと通り動くものを作り、あとでグローバル関数にする。アプローチ方法は意外とシンプルですね。

配布自体は簡単で、このmelファイルを以下のフォルダにコピーしてもらうだけです。
全Mayaバージョンで使用可能にする場合
「C:\Users\ユーザー名\Documents\maya\scripts」

特定のバージョンだけで使用可能にする場合
「C:\Users\ユーザー名\Documents\maya\20○○\scripts」(英語モード)
「C:\Users\ユーザー名\Documents\maya\20○○\ja_JP\scripts」(日本語モード)

Mayaで実行する時はファイル名と同じグローバル関数をスクリプトエディタなどで実行します。今回のツールではシーン内にメッシュオブジェクトがあることを確認して、次のスクリプトを実行するとGUIが現れます。

listNumberOfPolygon();



proc string[] getList(){

string $meshes[] = `ls -v -sl`;
if ( size($meshes) == 0 ){
$meshes = `ls -v -type mesh`;
}

int $nums[];
string $data[];
for ( $mesh in $meshes ){
int $numTris[] = `polyEvaluate -t $mesh`;
$nums[ size($nums) ] = $numTris[0];
$data[ size($data) ] = $mesh + "-" + $numTris[0];
}
$nums = sort($nums);

//ソートした配列を逆順で辿る
//(数字の大きな方から表示するため)
//
string $results[];
clear $results;
for ( $i = size($nums)-1; $i >= 0; $i-- ){
string $num = $nums[$i];

// 該当のメッシュを探す。
// 見つかったら値を空""にして、二重に見つからないようにしておく。
//
for ( $j = 0; $j < size($data); $j++ ){
if ( `gmatch $data[$j] ( "*-" + $num )` ){
$results[size($results)] = $data[$j];
$data[$j] = "";
}
}
}
return $results;
}

proc int numTris(){

string $meshes[] = `ls -v -sl`;
if ( size($meshes) == 0 ){
$meshes = `ls -v -type mesh`;
}
int $numTris[] = `polyEvaluate -t $meshes`;
return $numTris[0];
}

global proc listNumberOfPolygon.select(){

string $items[] = `textScrollList -q -si lnp_slist`;
// e.g. "pSphere-403"

select -cl;
for ( $item in $items ){
string $buffer[];
tokenize $item "-" $buffer;
select -add $buffer[0];
}
}

global proc listNumberOfPolygon(){

string $win = "listNumberOfPolygonWin";
if ( `window -q -ex $win` ){
deleteUI $win;
}

window -t "List Num of Polygon" $win;

int $numTris = numTris();
frameLayout -l ("List of mesh:" + $numTris );

textScrollList -ams true -sc "listNumberOfPolygon.select()" lnp_slist;

string $data[] = getList();
for ( $item in $data ){
textScrollList -e -a $item lnp_slist;
}

showWindow $win;

}
//listNumberOfPolygon();

まとめ

ようやく晴れてポリゴン数をカウントするツールを配布できるようになりました。他のツールを作るときもこれと同じ様に作って配布出来ます。十一回に渡ってMEL関係を見て来ました。シンプルなツールから複雑なツールまでの制作手順の、これがひと通りの全貌です。

後はこれらの話を踏まえて、フリーのMELをダウンロードして自分なりに改変して
慣れながらツール制作を覚えていけば、いつの間にかアナタもテクニカルアーティストの仲間入り!


さすがにMELの話がこれだけ続くと飽きてきますので、次回は通常営業に戻ってもうちょっとアーティストよりの、すぐに役立つシンプルなところの話を出来ればと考えています。本当は先日GDCに行って来ましたので、遅ればせながらその話が出来ると面白いかもと思っています。では!

製品購入に関するお問い合わせ
オートデスク メディア&エンターテインメント 製品のご購入に関してご連絡を希望される場合は、こちらからお問い合わせください。