今回は、mayaで使うリギングのサポートツールを作っていきます。
リグの形をワンクリックで作れるやつです。
実装した機能や感じたことを備忘録的にまとめました。
作ったmelは配布してますが、使用は自己責任でお願いします。
参考ツールの紹介
今回のツールは無料で公開されてる『rig101 Wire Controllers』を元に作ってます
たしか、こちらのリグの本にダウンロード先のURLが載ってました。
本の情報なので、URLを載せるのは止めときます。
リグコントローラーツールの特徴5選
- 直感的にリグの形が分かる
- よく使う形とそうでない形に分けた
- 選択したノードにスナップ・その数だけリグを作る
- グリッドレイアウトで簡単キレイ
- 参考ツールにあった不要な形は除いた
このツールの特徴は以上の5つです。
順番に解説していきます。
【ボタンを画像化】直感的にリグの形が分かる【選択コストの削減】
参考ツールはテキストでリグの形が書いてあります。
しかし、わざわざ文字を読んで、「あ~squareって書いてあるから四角ね~」、、、
って、英語に疎い私はそんな風に変換してられません。
リグを作るたびに、
『日本語に置き換えて→形を想像し→ボタンを押す…』
毎回この工程をやってたら、キャラのアニメーション作る前にプロジェクト終わりますよ…
なるべく判断に時間を取られないように、ツールのUIは直感的に分かる作りにしました。
これなら英語が苦手な私のような人にも、簡単に使いこなすことができます。
よく使う形とそうじゃない形をタブで分けた
リグの形も頻出なものと、そうでないものがあります。
タブを分けることで、「あの形はどこだっけ~」といった判断の時間を減らしてます。
極力、使い手が迷わないUI設計を心掛けました。
選択したノードにスナップ・その数だけリグを作る
参考ツールでは、原点にしかリグが作られない仕様でした。
ジョイントを選択し、ツールのボタンを押しても、リグが原点に作られるのは使いにくいですね…
マウスを移動させてる間にプロジェクトが終わります。
そう考えたので、選択箇所にスナップするように作りました。
加えて、選択したノードの数だけリグが作られるようにしてます。
指のリグとか作ってるときに、コピペするのが面倒だったので実装しました。
グリッドレイアウトで簡単でキレイ
//====================================
// === レイアウトの記述例 ==================
string $tabs = `tabLayout -innerMarginWidth 1 -innerMarginHeight 1`;
string $grid_01 = `gridLayout -numberOfColumns 6 -cellWidthHeight 50 50`;
//====================================
//====================================
レイアウトには gridLayout
を使うことで、簡単でキレイなUIを実現してます。
たったの2つのフラグで見た目を調整できるので、保守管理も楽です。
(正直、columnとrowって苦手なんですよね…)
参考ツールにあった不要な形は除いた
正直、使うタイミングが不明なものが多かったので、個人的に不要と感じた形は削りました。
リグの形はシンプルなやつが好みですね。
【苦労話】アイコン作成は地味に大変
UIのアイコンは自作したのですが、これが意外に骨の折れる作業でした(笑)
トータル3時間くらいアイコン作ってましたね…
レイヤ名のリネームも、途中からやってません(笑)
今回のツールで勉強になった点
- 引数や戻り値の使い方
- switchのcaseに文字列を渡す時の記法
今回は以上の2点が勉強になりました。
引数や戻り値の使い方【基本が大事】
//====================================
global proc main_KK_MakeController(string $mode){
//選択したノードの位置情報をとってくる
float $pos[];
float $rot[];
int $i;
string $node[],$ctrName;
$node = `ls -sl`;
//選択してるノードがあるかを判定
if(0 == size($node)){
$ctrName = `KK_MakeController($mode)`;//コントローラーを作りつつ、コントローラーの名前を取得
}
else{
for($i=0;$i<size($node);$i++){
$ctrName = `KK_MakeController($mode)`;
$pos = `xform -q -t -ws $node[$i]`;
$rot = `xform -q -ro -ws $node[$i]`;
xform -t $pos[0] $pos[1] $pos[2] $ctrName;//コントローラーの名前を参照して、選択したノードの場所へスナップ
rotate $rot[0] $rot[1] $rot[2] $ctrName;
}
//====================================
//====================================
KK_MakeController($mode)がカーブでリグを作る関数になっており、$modeの値によって作られるリグが変わるようになってます。
KK_MakeController(KK_CUBE) なら、立方体のリグが作られます。
KK_MakeController($mode)の戻り値は、作ったリグの名前を返し、その名前を元にスナップ処理をしてます。
関数をまたぐ場合、今までならグローバル変数を使ってました。
しかし、それだと記述が多くなるし、もっとスマートな方法はないかと考えたとき、プログラムの原点にたどり着きましたね。
関数の答えを取得すればいいじゃなか!って…
まぁゴリゴリのプログラマーから言わせたら、当たり前じゃんって感じですが…
戻り値ってあんまり理解してなくて、うまく使えてなかったですが、今回のように使えばコードを簡略化できるっていうのを学べました。
関数に戻り値がある場合は、型を指定する必要がある
//=== 戻り値の記述例 ====================
global proc string KK_MakeController(string $TYPE )
//====================================
melは戻り値を返す場合、変数の型を指定しないといけないってのも勉強になりました。
Pythonならそんなことせずとも、戻り値は返せるので、その感覚でやってたら落とし穴にはまります…
この辺も知れたのは良い経験でした。
switchのcaseに文字列渡すときの書き方
//==== リグを作る関数 ==============
global proc string KK_MakeController(string $TYPE ){
string $cv;
switch($TYPE){
case "KK_CUBE":
$cv = `curve -d 1 -p 0.5 0.5 0.5 -p 0.5 0.5 -0.5 -p -0.5 0.5 -0.5 -p -0.5 -0.5 -0.5 -p 0.5 -0.5 -0.5
-p 0.5 0.5 -0.5 -p -0.5 0.5 -0.5 -p -0.5 0.5 0.5 -p 0.5 0.5 0.5 -p 0.5 -0.5 0.5 -p 0.5 -0.5 -0.5
-p -0.5 -0.5 -0.5 -p -0.5 -0.5 0.5 -p 0.5 -0.5 0.5 -p -0.5 -0.5 0.5 -p -0.5 0.5 0.5
-k 0 -k 1 -k 2 -k 3 -k 4 -k 5 -k 6 -k 7 -k 8 -k 9 -k 10 -k 11 -k 12 -k 13 -k 14 -k 15
-n "controller1"` ;
break;
//==== 省略 ==================
//==========================
}
//=============================
//====リグを作ってスナップ処理する関数 ==
global proc main_KK_MakeController(string $mode){
//選択したやつの位置情報をとってくる
float $pos[];
float $rot[];
int $i;
string $node[],$ctrName;
$node = `ls -sl`;
//選択してるノードがあるかを判定
if(0 == size($node)){
$ctrName = `KK_MakeController($mode)`;//コントローラーを作りつつ、コントローラーの名前を取得
//=============================
//=============================
iconTextButtonのcommandフラグに、switch文の分岐条件をそのまま書いてます。
iconTextButton -c “main_KK_MakeController KK_CUBE”と書けば、 KK_CUBE
を引数と認識してくれるので、そのままメインの関数に渡してます。
こんな書き方ができるのは知らなったので、汎用性が高いテクニックだと感じました。
言われてみたら納得なんですが、意外と思いつかなかったですね…
【今後の改善】UIの見直しとPythonで書き直し
- main部分のUI調整
- Pythonで書き直し
作り終わって感じたことは以上の2点です。
順番に解説していきます。
main部分のUIが不細工なので、調整する方法を考える
グリッドレイアウトで作ってる弊害なのか、ウィンドサイズがサブメニューの大きさに依存するようになってます。
このままでも使えないことはないのですが、この隙間はどうも不格好ですね…
今考えてるのは、プルダウンメニューの採用ですかね。
タブで分けるのではなく、プルダウンで折りたためるようにした方が良いのかな~って考えてます。
そもそもPythonで作り直す
そもそもですが、melではなくPythonで作り直そうかと考えてます(今更…)
理由はリグの追加に対応するためです。
リグの形はcurveのpointフラグを使い、CVを動かして整えてます。
curve -d 1 -p 0.5 0.5 0.5 -p 0.5 0.5 -0.5 -p -0.5 0.5 -0.5;
ご覧の通り、-pointってフラグをCVの数だけ書かないといけないんですよ…
しかし、Pythonなら、
cmds.curve(d=1,p=([0.5,0.5,0.5],[0.5,0.5,-0.5],[-0.5,0.5,-0.5]))
このような感じで、point をまとめて書く仕様になってます。
この記述が肝です。
作りたい形のCVを取得する方法
例えば、画像のような球状の形をスクリプトで作ろうとする場合。
■melの場合
// ====================================
string $nodeList[];
string $ctrName;
$nodeList =`ls -sl`;
$ctrName = $nodeList[0] + ".cv[*]";
getAttr $ctrName;
// 結果: 0 0 1 0 0.5 0.866025 0 0.866025 0.5 0 1 0 0 0.866025 -0.5 0 0.5 -0.866025 0 0 -1 0 -0.5 -0.866025 0 -0.866025 -0.5 0 -1 0 0 -0.866025 0.5 0 -0.5 0.866025 0 0 1 0.707107 0 0.707107 1 0 0 0.707107 0 -0.707107 0 0 -1 -0.707107 0 -0.707107 -1 0 0 -0.866025 0.5 0 -0.5 0.866025 0 0 1 0 0.5 0.866025 0 0.866025 0.5 0 1 0 0 0.866025 -0.5 0 0.5 -0.866025 0 0 -1 0 -0.5 -0.866025 0 -0.866025 -0.5 0 -1 0 0 -0.707107 0 0.707107 0 0 1 //
// ====================================
// ====================================
■Python
# =================================
cmds.getAttr((cmds.ls(sl=1)[0])+".cv[*]")
#結果: [(0.0, 0.0, 1.0), (0.0, 0.5, 0.866025), (0.0, 0.866025, 0.5), (0.0, 1.0, 0.0), (0.0, 0.866025, -0.5), (0.0, 0.5, -0.866025), (0.0, 0.0, -1.0), (0.0, -0.5, -0.866025), (0.0, -0.866025, -0.5), (0.0, -1.0, 0.0), (0.0, -0.866025, 0.5), (0.0, -0.5, 0.866025), (0.0, 0.0, 1.0), (0.707107, 0.0, 0.707107), (1.0, 0.0, 0.0), (0.707107, 0.0, -0.707107), (0.0, 0.0, -1.0), (-0.707107, 0.0, -0.707107), (-1.0, 0.0, 0.0), (-0.866025, 0.5, 0.0), (-0.5, 0.866025, 0.0), (0.0, 1.0, 0.0), (0.5, 0.866025, 0.0), (0.866025, 0.5, 0.0), (1.0, 0.0, 0.0), (0.866025, -0.5, 0.0), (0.5, -0.866025, 0.0), (0.0, -1.0, 0.0), (-0.5, -0.866025, 0.0), (-0.866025, -0.5, 0.0), (-1.0, 0.0, 0.0), (-0.707107, 0.0, 0.707107), (0.0, 0.0, 1.0)] #
# =================================
取得した結果、
melは0 0 1…のようにただの配列で返ってきますが、
Pythonなら、[(0.0,0.0,0.1),(0.0,0.5,0.886025)…]のようタプルで返ってきます。
カーブのスクリプトを書く場合、Pythonならこの結果をコピーするだけでOKです。
melだったら、わざわざ間に-p書いて、、、
ってとんでもない工数が発生しますからね…
拡張性、保守性、そういう意味でもPythonで記述するべきかと、今更ながらに思います…
コントローラーツールまとめ【シンプルisBEST】
- UIは直感的に分かるようにする
- 戻り値や引数を活用しコードを簡略化する
- 拡張性・保守性を考えるとPythonで書いた方が良い
ツールにしろリグにしろ、ユーザーが使いやすいのが正解かと思います。
視覚的に分かりやすい作りにして、迷ってる時間を1秒でもなくせたら、その分コスト削減になるのではないでしょうか。
また、melは変数の宣言やセミコロンが必須とか…
色々と面倒だなぁと、改めて感じました。
ツール開発後の取り回しを考えると、Pythonで書いた方が良いと思います。
melスクリプトとアイコン画像を入れる場所(windowsの場合)
■melスクリプト
C:\Users\{ユーザー名}\ドキュメント\maya\{mayaのバージョン}\ja_JP\scripts
■アイコン画像
C:\Users\{ユーザー名}\ドキュメント\maya\{mayaのバージョン}\prefs\icons
mayaのインストール場所がデフォルトなら、上記のパスにスクリプトとアイコン画像を配置して下さい。
スクリプトのパスを自分で指定する場合
Dドライブとか別の場所にmayaが入ってる人はどうするの?
こんな人もいるはずなので、その場合の対処法も書いておきます。
って言っても、mayaのenvファイルに環境変数の設定を書き足すだけです。
『maya/バージョン名/Maya.env』ってファイルがあるはずなので、それをメモ帳とかで開いて、そこにスクリプトとアイコン画像のパスを記載します。
//envファイルの記述例
// melの置き場所
MAYA_SCRIPT_PATH=C:\work\script\kmt_controller
// 画像の置き場所
XBMLANGPATH=C:\work\script\kmt_controller\icons
// EOF
それでは、良きリグライフを!
ではまた!