スクリプト PRを含みます

【フリーmel配布】mayaのリグコントローラーをmelで作る

記事内に商品プロモーションが含まれます

今回は、mayaで使うリギングのサポートツールを作っていきます。

リグの形をワンクリックで作れるやつです。

実装した機能や感じたことを備忘録的にまとめました。

作ったmelは配布してますが、使用は自己責任でお願いします。

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)`;//コントローラーを作りつつ、コントローラーの名前を取得

//=============================
//=============================

iconTextButtoncommandフラグに、switch文の分岐条件をそのまま書いてます。

iconTextButton -c “main_KK_MakeController KK_CUBE”と書けば、 KK_CUBE を引数と認識してくれるので、そのままメインの関数に渡してます。

こんな書き方ができるのは知らなったので、汎用性が高いテクニックだと感じました。

みっつ

言われてみたら納得なんですが、意外と思いつかなかったですね…

【今後の改善】UIの見直しとPythonで書き直し

  • main部分のUI調整
  • Pythonで書き直し

作り終わって感じたことは以上の2点です。

順番に解説していきます。

main部分のUIが不細工なので、調整する方法を考える

グリッドレイアウトで作ってる弊害なのか、ウィンドサイズがサブメニューの大きさに依存するようになってます。

このままでも使えないことはないのですが、この隙間はどうも不格好ですね…

今考えてるのは、プルダウンメニューの採用ですかね。

タブで分けるのではなく、プルダウンで折りたためるようにした方が良いのかな~って考えてます。

そもそもPythonで作り直す

そもそもですが、melではなくPythonで作り直そうかと考えてます(今更…)

理由はリグの追加に対応するためです。

リグの形はcurvepointフラグを使い、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を無料でダウンロードする

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

melを無料でダウンロードする

それでは、良きリグライフを!

ではまた!

ABOUT ME
みっつ
CGアニメーター/リガー テクニカルアーティスト(TA)目指して精進中です 都内でゲーム作ってます。