おはこんばんちわ
TAチームリーダーの山本です。
この記事はMayaアドベントカレンダー2023の14日目の記事です。
https://qiita.com/advent-calendar/2023/maya
今回はアニメーター向けのテクニカルナレッジです。
はじめに
少し前に、うちのCOYOTEスタジオのアニメーションチームのスタッフからこんな質問をいただきまして。
「グラフエディタのカーブの表示・非表示をスクリプトで制御したいが、どう制御したらいいかわからない…」
なるほど。
この機能のスクリプト化は、たまにアニメーターからも要望をいただきます。
実際、スクリプト制御できればシェルフにも登録できて、着目したいグラフにのみ表示を切り替えながら作業ができて、すごく便利そうです。
しかし、ググってみると「これ!」という解決策までまとめられた記事にあまりヒットしません。
対応としてはとても簡単なので、わざわざ記事にまとめられないのかもしれません。
うーん。
なるほどね。
ということで今回は、この「グラフカーブのスクリプトでの表示・非表示の切り替え方法」について、私なりのアプローチをまとめたいと思います。
結果を先に
以下のスクリプトで、現在表示されているグラフエディタのカーブ(trans/rotate/scale/visibility)の表示・非表示を切り替えることができます。
import maya.cmds as cmds
import maya.mel as mel
def setFilter(tx = 0,ty = 0,tz = 0,rx = 0,ry = 0,rz = 0,sx = 0,sy = 0,sz = 0,vis = 0,*args,**kwargs):
indxList = [name[-1] for name in cmds.getPanel(scriptType='graphEditor')]
for indx in indxList:
mel.eval('filterUISelectAttributesCheckbox translateX {} "graphEditor{}OutlineEd";'.format(tx,indx))
mel.eval('filterUISelectAttributesCheckbox translateY {} "graphEditor{}OutlineEd";'.format(ty,indx))
mel.eval('filterUISelectAttributesCheckbox translateZ {} "graphEditor{}OutlineEd";'.format(tz,indx))
mel.eval('filterUISelectAttributesCheckbox rotateX {} "graphEditor{}OutlineEd";'.format(rx,indx))
mel.eval('filterUISelectAttributesCheckbox rotateY {} "graphEditor{}OutlineEd";'.format(ry,indx))
mel.eval('filterUISelectAttributesCheckbox rotateZ {} "graphEditor{}OutlineEd";'.format(rz,indx))
mel.eval('filterUISelectAttributesCheckbox scaleX {} "graphEditor{}OutlineEd";'.format(sx,indx))
mel.eval('filterUISelectAttributesCheckbox scaleY {} "graphEditor{}OutlineEd";'.format(sy,indx))
mel.eval('filterUISelectAttributesCheckbox scaleZ {} "graphEditor{}OutlineEd";'.format(sz,indx))
mel.eval('filterUISelectAttributesCheckbox visibility {} "graphEditor{}OutlineEd";'.format(vis,indx))
# 以下のせっていで実行するとtranslateだけ表示されます。
setFilter(1,1,1,0,0,0,0,0,0,0)
ポイントは
filterUISelectAttributesCheckbox
というmelコマンドを実行することで、任意のグラフエディタに対し、任意のフィルタリングをかけることができる、ということです。
ちなみに、このmelコマンドはスクリプトのエコーによって簡単に知りえることができます。
では、詳しく見ていきましょう。
カーブのフィルタリングについて
前提知識として、グラフエディタのメニューからカーブのフィルタリングができるんです。

ここですね。

これが…

こんな感じにできます。便利です。
または、何かtransformノードを選択した状態で…、

ここを選択すると、

こういうUIが出てきます。
適宜、該当箇所のチェックボックスにチェックを入れると…

translateXのみ。

rotateとvisibility

いろいろとまぜこぜ。
こっちの方が細かく指定できて、便利そうです。
こちらの機能をスクリプト化してみることにしましょう。
コマンドのエコーで正体を探る
月並みですが、コマンドのエコーをチェックしてみましょう。

スクリプトエディタのEcho Allにチェックを入れて操作してみます。
translateXのチェックボックスを操作すると
filterUISelectAttributesCheckbox translateX 1 graphEditor1OutlineEd;
…というmelコマンドがプリントされました。
試しにこのmelコマンドを実行してみると…

フィルタのUIにチェックが付き、グラフエディタの表示に反映されました。
ちなみに、引数を0に変えて
filterUISelectAttributesCheckbox translateX 0 graphEditor1OutlineEd;
…と実行してみると。。

チェックが外れて、表示が元通りになりました。
これでいいじゃないの。(笑)
では同様にして、他のアトリビュートも調査すると…、
filterUISelectAttributesCheckbox translateX 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox translateY 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox translateZ 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox rotateX 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox rotateY 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox rotateZ 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox scaleX 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox scaleY 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox scaleZ 1 graphEditor1OutlineEd;
filterUISelectAttributesCheckbox visibility 1 graphEditor1OutlineEd;
という感じですね。
引数の数字を任意に0か1で実行できるようにすれば解決できそうです。
でも1点気になるのが
graphEditor1OutlineEd
この表記。
任意のグラフエディタを指定しているようですが、例えば、別途拡張したグラフエディタなど、Maya既定のものとは別に作っていた場合に、ここの文字列が変わります。
グラフエディタを拡張してリリースしている場合などでは、自身のグラフエディタの名前から指定してあげればOKですが、シェルフから実行する場合には、「どれが対象のグラフエディタなのか」わからなくなってしまいそうです。
少しだけ工夫を足してみます。
現在存在するグラフエディタすべてを対象にする
ひとまず、現在存在しているグラフエディタすべてを対象にするように、スクリプトをカスタマイズしてみます。
graphEditor1OutlineEd
この名前の数字部分は、存在するグラフエディタの数で順番に増加し、末尾に足されていくため、対象のグラフエディタの末尾の数字を調べて、引用してあげれば大丈夫そうです。
グラフエディタをリストアップし、for文を回して末尾のインデックスを取得するコードは以下の通り。
import maya.cmds as cmds
indxList = [name[-1] for name in cmds.getPanel(scriptType='graphEditor')]
for indx in indxList:
print(indx)
グラフエディタのリストアップは
cmds.getPanel(scriptType='graphEditor')
上記のところで行っています。
ここに、先ほどのmelコマンドを実行させる記述を追加して…
import maya.cmds as cmds
import maya.mel as mel
indxList = [name[-1] for name in cmds.getPanel(scriptType='graphEditor')]
for indx in indxList:
mel.eval('filterUISelectAttributesCheckbox translateX 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox translateY 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox translateZ 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox rotateX 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox rotateY 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox rotateZ 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox scaleX 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox scaleY 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox scaleZ 1 "graphEditor{}OutlineEd";'.format(indx))
mel.eval('filterUISelectAttributesCheckbox visibility 1 "graphEditor{}OutlineEd";'.format(indx))
こんな感じに。
最後に関数化して。。
import maya.cmds as cmds
import maya.mel as mel
def setFilter(tx = 0,ty = 0,tz = 0,rx = 0,ry = 0,rz = 0,sx = 0,sy = 0,sz = 0,vis = 0,*args,**kwargs):
indxList = [name[-1] for name in cmds.getPanel(scriptType='graphEditor')]
for indx in indxList:
mel.eval('filterUISelectAttributesCheckbox translateX {} "graphEditor{}OutlineEd";'.format(tx,indx))
mel.eval('filterUISelectAttributesCheckbox translateY {} "graphEditor{}OutlineEd";'.format(ty,indx))
mel.eval('filterUISelectAttributesCheckbox translateZ {} "graphEditor{}OutlineEd";'.format(tz,indx))
mel.eval('filterUISelectAttributesCheckbox rotateX {} "graphEditor{}OutlineEd";'.format(rx,indx))
mel.eval('filterUISelectAttributesCheckbox rotateY {} "graphEditor{}OutlineEd";'.format(ry,indx))
mel.eval('filterUISelectAttributesCheckbox rotateZ {} "graphEditor{}OutlineEd";'.format(rz,indx))
mel.eval('filterUISelectAttributesCheckbox scaleX {} "graphEditor{}OutlineEd";'.format(sx,indx))
mel.eval('filterUISelectAttributesCheckbox scaleY {} "graphEditor{}OutlineEd";'.format(sy,indx))
mel.eval('filterUISelectAttributesCheckbox scaleZ {} "graphEditor{}OutlineEd";'.format(sz,indx))
mel.eval('filterUISelectAttributesCheckbox visibility {} "graphEditor{}OutlineEd";'.format(vis,indx))
これでどうだい。
実際に実行してみると…
setFilter(1,1,1,0,0,0,0,0,0,0)</code></pre>

よし!問題なく動いた!
ハラショー!!
まとめ
今回は手短ですが、以上になります。
普段の手作業のこととなると、ちょっとしたスクリプト化での作業効率化がおざなりになりがちと思います。
今回のスクリプト化はTAでなくとも、アニメーターでも簡単に対応しやすいと思います。
記事では、「すべてのグラフエディタを対象にする」というところまで少し踏み込んでいますが、Echoコマンドのコピペだけでも全然使えることが分かったと思います。
ぜひ参考にしていただければ幸いです!
いやー、Mayaスクリプトっていいもんですね。
ではまた次の機会に!
サヨナラ!
サヨナラ!
サヨナラ!!
COYOTE 3DCG STUDIO
公式HP:https://3d.crdg.jp/COYOTE 3DCG STUDIOはクリーク・アンド・リバー社が運営するゲーム専門3DCG制作集団です。 キャラモデル、背景モデル、3Dアニメーション、テクニカルアーティストによるツール開発などを得意としています。 新規立ち上げにおけるコンサルティングから量産制作まで幅広く対応可能な体制を保有しており、出向にも柔軟に対応しております。