チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第74回:デフォルト値を取っておくツールを作ろう!
- Maya
- ゲーム
- コラム
- スクリプト・API
- チュートリアル
- 中級者
夏ですね。ここのところ強風で、外に置いていたものがどこかに飛ばされることもしばしば。適当に元の位置に戻しますが、デジタルの世界では座標という便利な仕組みのため、位置の数値を入れれば、正確に元の位置に戻ります。
背景のオブジェクトやリグのコントロールなど、オブジェクトをデフォルトの位置に戻せると便利なシチュエーションが多々あります。特にリグは、アニメーションを付けていると元のポーズに戻したいときがあります。ところが元のポーズに戻すのは意外と難しいものです。
Translate/Rotate/Scaleの値が0.0と1.0になるように作られていればまだ良いですが、1.23など微妙な値になっていると戻すのが難しくなります。リグのアトリビュートをすべてメモしても、復活の呪文をメモした日々のように、いつか間違えるときが来ます!そもそもマウスから手を放させないで!!横においているコーヒーがこぼれるから!という思いです。
ではどうやって元の位置を記録しておくか…。実はMayaには位置を記録しておく方法があります。キャラを作っている方にとってはおなじみのあの機能、Bind Skinです。バインドを行うと、バインドポーズというのが作られます。ジョイントの位置を変えてもGo to Bind Poseを実行すれば元の位置に戻ります。
この仕組はバインド以外にも使えます。というわけで、まずはバインドポーズの仕組みを見てみましょう。
バインドポーズの仕組み
例えばシーンのオブジェクトを選択してから、次のスクリプトを実行します。

1 | dagPose - save - name "myPose" ; |
実行するとmyPoseというノードが作られます。

このmyPoseのノード種類は「dagPose」で、その名の通りDAG(座標を持つオブジェクト)のポーズを記録するものです。ノードのどこに位置が記録されているかというと、worldMatrix配列アトリビュートに記録されます。
次のようにgetAttrでworldMatrixを取ると、各オブジェクトの座標が取れます。
1 2 3 4 | getAttr myPose.worldMatrix[ 0 ]; / / 1 0 0 0 0 1 0 0 0 0 1 0 - 3.133187 0 0 1 / / getAttr myPose.worldMatrix[ 1 ]; / / 1 0 0 0 0 1 0 0 0 0 1 0 3.097503 0 0 1 / / |
元の位置に戻すには、次のコマンドを実行します。
1 | dagPose - restore "myPose" ; |
指定したdagPoseノードに記録された位置に、オブジェクトが復元されます。ジョイントではないオブジェクトでも良いのです!
でも個別のオブジェクトを戻したり、回転だけ元に戻したり、ということは出来ません。しかもdagPoseといっているだけあって、座標しか記録できません。マテリアルの色などは記録できないのです。
というわけで、デフォルト値を取っておくツールを自作する時が来ます。(やったー!)
順番に機能を実装してみましょう。
デフォルト値の保存
さて、dagPoseはノードを作り、アトリビュートにすべての位置を保存していました。
この方法の利点は多いですが、dagPoseノードをゴミだと思って捨ててしまうとオジャンになってしまうので、今回はノードにデフォルト値を記録するアトリビュートを追加するようにします。
次のMELスクリプトを実行すると、選択しているオブジェクトのTranslate/Rotate/Scaleの値を、〇〇_defaultというアトリビュート名で保存します。細かい説明はスクリプト内のコメントをご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / デフォルト値を保存するアトリビュートの追加。(既に登録があれば更新) / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 単純なアトリビュートタイプにのみ対応。 string $nodes[] = `ls - sl`; / / 選択しているノードの取得します。 / / string $attrs[] = { "translateX" , "translateY" , "translateZ" , "rotateX" , "rotateY" , "rotateZ" , "scaleX" , "scaleY" , "scaleZ" }; / / 対象となるアトリビュートのリストを作ります。 string $attrs[] = { "tx" , "ty" , "tz" , "rx" , "ry" , "rz" , "sx" , "sy" , "sz" }; / / 対象となるアトリビュートのリストを作ります。 for ( $node in $nodes ){ / / 各ノードごとに実行します。 for ( $attr in $attrs ){ / / アトリビュートごとに実行します。 if ( `attributeQuery - node $node - exists $attr` = = 0 ){ / / 対象のアトリビュートがあるかどうか確認。無い場合は・・・ continue ; / / スキップして次のアトリビュートへ。 } string $nodeAttr = $node + "." + $attr; string $defaultAttr = $attr + "_default" ; / / デフォルト値用アトリビュートの名前はtranslateX_defaultなどとします。 string $nodeDefaultAttr = $node + "." + $defaultAttr; if ( `attributeQuery - node $node - exists $defaultAttr` = = 0 ){ / / デフォルト値アトリビュートがすでにあるかどうか確認。 / / 無い場合は、作成。 string $ type = ` getAttr - type $nodeAttr`; addAttr - longName $defaultAttr - attributeType $ type - keyable true $node; / / とりあえず今回は - keyable trueにしてチャンネルボックスに表示します。 } / / この時点でデフォルト値アトリビュートが必ずあるので、値を更新。 $v = ` getAttr $nodeAttr`; setAttr - lock false $nodeDefaultAttr; / / ロックを解除。 setAttr $nodeDefaultAttr $v; / / 値を設定。 setAttr - lock true $nodeDefaultAttr; / / 再びロック。 } } |
下記はキューブを選択して実行した結果です。ずらっと「〇〇 Default」というアトリビュートが追加されます。(実際のアトリビュート名は「tx_default」といった名前ですが、表示用にMayaが変換するので見た目は「Tx Default」となります。先頭文字は大文字に、アンダーバーはなくして、アンダーバーの後ろの文字も大文字になります。)

デフォルト値は間違えて変えられると困るので、作成時にアトリビュートをロックしておきます。ツールが作りやすいので、今はアトリビュートをチャンネルボックスに表示していますが、実際に仕事で使うときは「setAttr -keyable false ノード.アトリビュート」を実行して、非表示にすると良いです。
デフォルト値のアトリビュートから値を復元する
デフォルト値を設定できるようになりました。次は値を復元する機能を作ります。次のMELスクリプトを実行すると「〇〇_default」という名前のアトリビュートがあれば値を復元します。割と単純です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / デフォルト値のアトリビュートから値を復元する / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / string $nodes[] = `ls - sl`; for ( $node in $nodes ){ string $attrs[] = `listAttr - string "*_default" $node`; / / _defaultという名前のアトリビュートをリストします。 for ( $attr in $attrs ){ string $ buffer []; tokenize $attr "_" $ buffer ; / / translateX_defaultなどの名前が$attrに来ているので、アンダーバーで文字列を分割します。 string $targetNodeAttr = $node + "." + $ buffer [ 0 ]; string $cachedNodeAttr = $node + "." + $attr; / / Default値を復元。 $v = ` getAttr $cachedNodeAttr`; setAttr $targetNodeAttr $v; print ( "Set " + $targetNodeAttr + "\n" ); } } |
結果としては下のような感じで、Translate値を見ていただくとデフォルト値に戻っているのがわかります。

リグや背景のオブジェクト、小物の配置には十分な機能が既に実装されています。でもよく考えたら、アトリビュートを作ったのはいいけれど削除出来ないと気持ち悪いです…。(誰かにゴミアトリビュート呼ばわりされるかもしれないですし。)
デフォルト値のアトリビュートを削除するツールも作りましょう。
デフォルト値のアトリビュートを削除
こちらも簡単なものでして、下のMELスクリプトを実行すると、選択したノードに〇〇_defaultという名前のアトリビュートがあれば削除します。アトリビュートがロックされていると削除できないので、事前にロックを解除するところがポイントです。
1 2 3 4 5 6 7 8 9 10 11 12 | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / デフォルト値のアトリビュートを削除 / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / string $nodes[] = `ls - sl`; for ( $node in $nodes ){ string $attrs[] = `listAttr - string "*_default" $node`; / / _defaultという名前のアトリビュートをリストします。 for ( $attr in $attrs ){ string $nodeAttr = $node + "." + $attr; setAttr - lock false $nodeAttr; deleteAttr $nodeAttr; } } |
実行するとこんな風になります。
…画像ではArnoldのアトリビュートが表示されていますが、気にしないようにしましょう!
もっと使い勝手を良くするために改良しよう!
とりあえずはこれでツールとしては使えますが、リグでは特定のアトリビュートのみデフォルト値に戻したい!ということがあります。チャンネルボックスで選択しているアトリビュートでのみ、デフォルト値の保存・復元ができると良いと思いませんか?
実は、割と簡単に出来ます。次のMELスクリプトを実行すると、選択しているアトリビュート名を得られます。
1 | channelBox - q - selectedMainAttributes mainChannelBox; |

このコマンドでいけそうですね!
何もチャンネルを選択していなければ、すべてのキー可能アトリビュートを対象にすることで、わざわざ対象のアトリビュートをスクリプトにハードコードしなくてもすむようになります。そういった諸々を反映させたMELスクリプトは以下の様になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / デフォルト値を保存するアトリビュートの追加。(既に登録があれば更新) / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 単純なアトリビュートタイプにのみ対応。 string $nodes[] = `ls - sl`; / / 選択しているノードの取得します。 string $attrs[] = `channelBox - q - selectedMainAttributes mainChannelBox`; / / チャンネルボックスの選択を元に、対象となるアトリビュートのリストを作ります。 if ( size($attrs) = = 0 ){ / / チャンネルボックスに選択がなかった場合は、すべてのキー可能アトリビュートが対象。 $attrs = `listAttr - keyable - shortNames $nodes[ 0 ]`; } for ( $node in $nodes ){ / / 各ノードごとに実行します。 for ( $attr in $attrs ){ / / アトリビュートごとに実行します。 if ( `attributeQuery - node $node - exists $attr` = = 0 ){ / / 対象のアトリビュートがあるかどうか確認。無い場合は・・・ continue ; / / スキップして次のアトリビュートへ。 } string $nodeAttr = $node + "." + $attr; string $defaultAttr = $attr + "_default" ; / / デフォルト値用アトリビュートの名前はtranslateX_defaultなどとします。 string $nodeDefaultAttr = $node + "." + $defaultAttr; if ( `attributeQuery - node $node - exists $defaultAttr` = = 0 ){ / / デフォルト値アトリビュートがすでにあるかどうか確認。 / / 無い場合は、作成。 string $ type = ` getAttr - type $nodeAttr`; addAttr - longName $defaultAttr - attributeType $ type - keyable true $node; / / とりあえず今回は - keyable trueにしてチャンネルボックスに表示します。 } / / この時点でデフォルト値アトリビュートが必ずあるので、値を更新。 $v = ` getAttr $nodeAttr`; setAttr - lock false $nodeDefaultAttr; / / ロックを解除。 setAttr $nodeDefaultAttr $v; / / 値を設定。 setAttr - lock true $nodeDefaultAttr; / / 再びロック。 } } |
チャンネルボックスを選択していると、こんな感じでアトリビュートが追加されます。

デフォルト値に戻すスクリプトも、チャンネルボックスでの選択に対応させましょう。こちらもチャンネルボックスで何も選択していない場合は、すべてのキー可能アトリビュートが対象となるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / デフォルト値のアトリビュートから値を復元する / / 選択したアトリビュートの値を復元。(「選択したアトリビュート_default」というアトリビュートがあればそれをデフォルト値として使用。) / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / string $nodes[] = `ls - sl`; string $attrs[] = `channelBox - q - selectedMainAttributes mainChannelBox`; / / チャンネルボックスの選択を元に、対象となるアトリビュートのリストを作ります。 if ( size($attrs) = = 0 ){ / / チャンネルボックスに選択がなかった場合は、すべてのキー可能アトリビュートが対象。 $attrs = `listAttr - keyable - shortNames $nodes[ 0 ]`; } for ( $node in $nodes ){ for ( $attr in $attrs ){ string $defaultAttr = $attr + "_default" ; if ( `attributeQuery - node $node - exists $defaultAttr` = = 0 ){ / / 対象のアトリビュートがあるかどうか確認。無い場合は・・・ continue ; / / スキップして次のアトリビュートへ。 } string $targetNodeAttr = $node + "." + $attr; string $cachedNodeAttr = $node + "." + $defaultAttr; / / Default値を復元。 $v = ` getAttr $cachedNodeAttr`; setAttr $targetNodeAttr $v; print ( "Set " + $targetNodeAttr + "\n" ); } } |
まとめ
今回作成したツールは、オブジェクトの位置だけでなく、マテリアルなどあらゆるノードで機能します。汎用的にいろいろと使って様子を見てください。もっと機能が欲しくなると思いますので、改造してより良いツールに仕上げてみましょう!
こういうツールは、コードが短い割に仕事ではずいぶん役に立つものです。コードの内容も難しいものではなく、アトリビュートをMELでどう操作するかがわかれば様々なツールに発展できると思います。
Mayaはカスタマイズしてなんぼですので、どんどんツールを作ってみましょう!
(そして、今回はツールとして使用しなかったdagPoseもうまく活かせば何かのツールにできるかもしれません)