3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[maya] python で mel 変数の値を "より安全に" 取得する方法

Last updated at Posted at 2020-12-02
※記事に関しましてご注意下さい
普段使用する手法を「よりシンプルで柔軟な方法がないか」調査した内容になります。
あくまでも個人調査のメモです。間違い・勘違いが含まれている可能性もありますので予めご了承ください。

※ 結論だけ見たい方は 最後尾 へどうぞ。

調査のきっかけ

maya 内の python で mel 変数の値を取得する場合、一時的な代入を使い

from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')

のように取得する方法がよく使われると思います。
ここで個人的にずっとモヤモヤしている箇所がありました。

1. $tmp という変数はどこに作成されるのか (global 変数か local 変数か)
2. 1 が global 変数の場合、既存変数との型違いでエラーは起きないのか

という疑問です。
この確認と、よりトラブルを起こさない記述について調べることにしました。

調べた結果

1. $tmp は global 変数として作成される(そのまま後に残される)
2. 別の型の $tmp 変数が既にあった場合にはエラーが起こる

そのままでした。
つまり、頭に書いた記述には使用条件があり、

・変数 $tmp が初めて作成される場合 (mel が型を振ってくれる)
・変数 $tmp が同じ型で宣言されている場合

のどちらかである必要があります。

この問題を起こさない記述は 最後尾 にメモしています。

トラブルが起こる場面

この穴をついてエラーが起きる・エラーを起こす方法は簡単です。
思いつく場面として以下があると思います。

型違いの同名変数を mel で "先に" 準備した場合

int $tmp = 1;

を mel で実行した後、python 文を実行すると

from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')

progress_bar
# Result: 0L # 

この場面では文字を変数に変換しようとして 0 という数字になります

上は int $tmp; でしたが、int $tmp[]; のように配列だった場合など、
型変換すら行われずにエラーになる可能性大です。

型違いの同名変数を mel で "後から" 使用した場合

※こちらは python 側のエラーにはなりませんがのちの mel でエラーが起きます

from maya import mel
progress_bar = mel.eval('$tmp = $gMainProgressBar')

progress_bar
# Result: MayaWindow|toolBar3|MainHelpLineLayout|helpLineFrame|formLayout16|mainProgressBar # 

を python で実行した後、mel 文を実行するとエラーがでます。

int $tmp = 1;
// Error: int $tmp; // 
// Error: Line 1.10: Invalid redeclaration of variable "$tmp" as a different type. // 

基本的に mel での global 変数使用は最小限にするのが暗黙のルールであるためおそらく頻発はしないとは思います。が、そうはいいつつも起きそうな場面としては scriptEditor でのテスト時、数行のスクリプトを Shelf などに登録している場合などがあると思います。

実際にトラブルが発生した例

[2022/12 追記]
身近でトラブルが起こる場面に遭遇したため例を追記しました。
公式ツール、有名ツールだとしても意識していないものが多いようです。

MayaScanner + mgear を共に使用した場合

[2022/12 追記]
MayaScanner は Maya 起動時に発動し、File Open などでスクリプトが動作しますが、そこで以下のコードが実行されます。

MayaScannerCleaner.py
232:        if (mel.eval('whatIs "$autoUpdateAttrEd_aoto_int"') != "Unknown"):
233:            a = int(mel.eval('$temp=$autoUpdateAttrEd_aoto_int'))

ここで $temp が global 変数として自動定義されることになりますが、この場合 global int $temp 相当だと意識しておく必要があります。

一方 Maya 起動後に File Open し、mgear を使用してSynoptic > Space Transfer などのツールを使用すると (一時的に再描画を止めるため) 以下のコードが実行されます。

mgear4.0.9/release/scripts/mgear/core/utils.py
185:        gMainPane = mel.eval('global string $gMainPane; $temp = $gMainPane;')

ここで mgear としては $temp の想定は global string $temp ですが、事前に MayaScanner によって global int $temp で先に作られてしまっているため、エラーが発生します。

エラーメッセージ的にはこんな感じです。

# RuntimeError: paneLayout: Object '0' not found.

まさに上で書いたことがそのまま発生し、エラーが起こっています。

どう修正すべきかについては、
MayaScanner はこう ↓ するべきですし、

MayaScannerCleaner.py
        if (mel.eval('whatIs "$autoUpdateAttrEd_aoto_int"') != "Unknown"):
            a = int(mel.eval('$autoUpdateAttrEd_aoto_int = $autoUpdateAttrEd_aoto_int'))

mgear はこう ↓ 書くべきだと思います。

mgear4.0.9/release/scripts/mgear/core/utils.py
        gMainPane = mel.eval('$gMainPane = $gMainPane')

$temp は自分だけのものではない、と改めて感じる例です。

トラブルを起こさない記述

いろいろ試しつつ情報収集していたところ、
studiolibrary 内になるほどの記述がありました。
https://github.com/krathjen/studiolibrary/blob/master/install.py#L68

それは 自分自身に代入する方法 です。

from maya import mel
progress_bar = mel.eval('$gMainProgressBar = $gMainProgressBar')

先に変数の型を知る必要がなく、代入が自分自身なので型は当然同じ、そして代入で値を変化させず、かつ無駄な global 変数を作成しない 、非常にスマートな方法です。

一方的に勉強になりました。。。感謝。

この手法のもう一つの利点

頻繁に使用・問合せする以下はその多くが string ですが、

$gMainWindow
$gMainProgressBar
$gChannelBoxName
$gMainWindowMenu
$gMainPane

例えば以下は int の配列です。

$gCustomSelPriority

ですが、この場合もその型を事前に知る必要がなく

from maya import mel
gCustomSelPriority = mel.eval('$gCustomSelPriority = $gCustomSelPriority')

gCustomSelPriority
# Result: [10, 10, 2, 9, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 10, 10, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 11, 11] # 

のように取得することができます。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?