Maya 2022.1 の File Translator プラグインの問題のまとめ

追記: Maya2022.3 では問題が解決されていることを確認しました。リリースノートのUSDのところに書いてある "Export selection with animation does not export animation MAYA-113800" だと思います（USDだけの問題ではないのですが）。performFileAction.mel の差分を見ると、FBX用に対処されたコードが無くなっています。
https://help.autodesk.com/view/MAYAUL/2022/JPN/?guid=Maya_ReleaseNotes_2022_3_release_notes_html

追記: Maya2022.2 でもこの問題は解決されていませんが、同じ対処方法で解決できます。

Maya2022.1がリリースされましたが、ちょっとやらかしちゃっている？バージョンかもしれません。
たとえば、別件で[「こんなこと」](https://knowledge.autodesk.com/support/maya/troubleshooting/caas/sfdcarticles/sfdcarticles/Marking-Menu-Editor-not-opening-in-Maya-2022-1.html)もあったりしますが、それは簡単に解決できるのでよしとして…、今回紹介するのは、FBX 以外の File Translator プラグインが軒並みちゃんと動かなくなるという、なかなか衝撃的な問題です。その現象と解決方法、そして「どういうわけでこんなことに？」という話をまとめます。
アップデートにはいろいろな改善も盛り込まれているわけなので、次のアップデートを待つなんて言わずに、このように対策して使っていきましょう。。


#問題の確認と解決方法
「FBX 以外の File Translator プラグイン」なので、いろいろなものが該当すると思いますが、たとえば USD ですね。
私が軽く確認した限り、USD ではジオメトリのアニメーションや、スケルトンのスキニング情報が出力できなくなっていました。

試してみましょう。
まず、以下の mel スクリプトを実行して、簡単なスキンアニメーションシーンを作ります。

``` mel
file -f -new;
joint -p 0 -5 0 ;
joint -p 0 0 0 ;
joint -p 0 5 0 ;
polyCylinder -r 1 -h 10 -sx 20 -sy 10 -sz 1 -ax 0 1 0 -rcp 0 -cuv 3 -ch 1;
group -n root joint1 pCylinder1;
select joint1 joint2 pCylinder1;
skinCluster -tsb -bm 1 -nw 1 -wd 0 -dr 4;
playbackOptions -ast 0 -aet 100;
setKeyframe -at rz -t 0 -v 0 joint2;
setKeyframe -at rz -t 25 -v 90 joint2;
setKeyframe -at rz -t 50 -v 0 joint2;
setKeyframe -at rz -t 75 -v -90 joint2;
setKeyframe -at rz -t 100 -v 0 joint2;
```

こんな風にシリンダーがボーン2本にバインドされてパキパキと横に振れるだけのアニメーションです。関係ないけど、そういればView Cubeがなんか新しくなって復活してますね。![cylinder_anim.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/01639fef-5da0-4858-70a4-1a5eea80fe90.png)
んで、USD プラグインをロードして、ルートを選択して、

``` mel
loadPlugin mayaUsdPlugin;
select root;
```

メニューから File > Export Selection します。
File Type は USD Export を選んで、こんな設定で、まずはスケルトンではなくジオメトリのアニメーションで出力してみます。
![usd_geom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/e8365b32-3ccd-490f-9248-cbab262177fa.png)
で、usdview で見てみても、

``` sh
% usdview test.usd
```

アニメーションが出ていません。
![usdview_geom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/e56bf915-8981-15fb-cfd5-89f884a2f4cf.png)
今度は、スケルトンアニメーションで出してみます。こんな設定で、
![usd_skel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/cf850b8f-4ac9-3c64-91a7-47bc270fc8c6.png)
usdviewで見てみても、やっぱりアニメーションは出ていません。usdファイルの中身を見ると分かりますが、実はスキンのバインド情報も出ていません。
![usdview_skel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/a49a4dcc-8d56-2a5b-1d8b-1135f255a41f.png)

とまあこんな感じで、形状は出力されるのですが、アニメーションや、スキンバインド情報などが出力されなくなっているわけです。

この問題が発生するのは、File > Export Selection から出力する、mayaシーンと FBX 以外の特別な対策がされていないもの全てです。
きちんと確認したわけではありませんが、形状データだけのOBJなんかは問題ないかもしれません。
ATOM は、メニューの File > ATOM > Export Animation... から出力する分には対策されていて問題ありませんが、File > Export Selection から出力すると同じ問題が発生します。
Alembic のエキスポートは File Translator ではなくて Command なので問題ありません。

では、対策してみましょう。
Windows だと C:\Program Files\Autodesk\Maya2022\scripts\others にある performFileAction.mel を書き換えます。
**万一、この書き換えにより損害が生じても当方は一切の責任を負いません。くれぐれも自己責任でお願いします!!**

問題は525行目です。

元の状態がこれです。

``` mel
				if (`optionVar -q exportIncludeInputs` && $isMayaFileType) {
```

それを次のように書き換えます。

``` mel
				if (`optionVar -q exportIncludeInputs` && ! $isFbxFileType) {
```

そして、Maya を再起動するか、しないなら次の mel コードを実行して、スクリプトを書き換えたことを Maya に知らせます。

``` mel
source performFileAction;
```

そして、さっきと同じように USD のアニメーションをエキスポートしてみます。

まずは、ジオメトリアニメーションです。ちゃんと動いています！
![usdview_geom2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/5754c457-c359-4621-6021-abf643f453e7.png)

スキニングのスケルトンアニメーションとしてエキスポートしても、ちゃんと動いています！
jointのrotationのアニメーションとスキンバインド情報が問題なくエキスポートされています。
![usdview_skel2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/c938be6f-3666-fa89-00b9-d6666fec9d7b.png)

システムmelを書き換えてしまったので、これで、USDはもちろん、他のファイルタイプの場合でも問題は解決されています。
ちなみに、この問題をきちんと解決するには、現状、このようにシステムmelを書き換える以外の方法はありません。たぶん。


#技術解説
それでは、なぜこんなことになっちゃっているのか、説明します。

実は、Export Selection のファイルダイアログに、これ気にしている人いるのか？という Include Options というオプションの一画があるのですが、これに原因があります。
![file_opts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/4cd42b45-fcc2-adc4-c750-9fcf85b44e86.png)

エキスポートするファイルタイプが mayaAscii か mayaBinary の場合、次のようになります。
![file_maya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/e01bc548-f136-8313-90c5-e25f92f5ed19.png)
FBXは特別扱いされていて、次のようになります。
![file_fbx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/b7d8887f-0a4a-09b0-d607-c890ec9737db.png)
その他のファイルの場合、次のようになります。
![file_other.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/d333dc2d-07e2-7c51-aab9-5d1648a06407.png)
その他のファイルタイプで全部グレーアウトされるってことは、その他のタイプにはこんなオプション関係ねーから気にすんなってことですよね。
でもね、本当に関係ないならいいのですが、実は関係大ありなんすよ。

これらのオプションは遥か大昔からあり、扱われ方はずっと変わってこなかったのですが、2022.1 で変わりました。
2022.1 では FBX は別の値として個人設定に保存されるようになっています。
その制御をしているのが performFileAction.mel です。

2022 までは、mayaシーンファイルであっても、FBXであっても、その他のタイプであっても、別け隔てなく、これらの設定値がエキスポートする際の file コマンドに指定されておりました。
ところが、2022.1 からは、mayaシーンファイルならこれまでと変わらず、FBXなら専用の設定値を利用、そしてその他のタイプは強制的に全て Off 扱いという制御がされるようになりました。performFileAction.mel のコードがそうなっています。書き換え前の該当箇所を引用します。

``` mel
			//	Set up the export parameters.
			if (`optionVar -ex exportIncludeInputs`) {

				// MAYA-108336 The following Include options for export 
				// selection should only be applied for Maya Ascii and
				// Maya Binary files.
				//
				// The corresponding UI in the Export Selection option
				// box only enables the checkboxes for Maya file types.
				// For all other file types the checkboxes are disabled.
				// Therefore, we must make sure the associated file 
				// command flags are only applied for Maya files.
				//
				// FBX export selection now has it's own UI section
				// for indicating what options to include on export.
				//
				int $isMayaFileType = $fileType == "mayaAscii" || $fileType == "mayaBinary";
				int $isFbxFileType = $fileType == "FBX export";

				if (`optionVar -q exportIncludeInputs` && $isMayaFileType) {
					file -chn `optionVar -q exportIncludeChannels`;
					file -ch `optionVar -q exportIncludeHistory`;
					file -exp `optionVar -q exportIncludeExpressions`;
					file -con `optionVar -q exportIncludeConstraints`;

				} else if ($isFbxFileType) {

					file -chn `optionVar -q exportIncludeChannelsFbx`;
					file -ch  `optionVar -q exportIncludeHistoryFbx`;
					file -exp `optionVar -q exportIncludeExpressionsFbx`;
					file -con `optionVar -q exportIncludeConstraintsFbx`;

				} else {
					file -chn false;
					file -ch false;
					file -exp false;
					file -con false;
				}
			} // Else don't change the default values.
```

ちなみに 2022 だと、次のコードでした。

``` mel
			//	Set up the export parameters.
			if (`optionVar -ex exportIncludeInputs`) {
				if (`optionVar -q exportIncludeInputs`) {
					file -chn `optionVar -q exportIncludeChannels`;
					file -ch `optionVar -q exportIncludeHistory`;
					file -exp `optionVar -q exportIncludeExpressions`;
					file -con `optionVar -q exportIncludeConstraints`;
				} else {
					file -chn false;
					file -ch false;
					file -exp false;
					file -con false;
				}
			} // Else don't change the default values.
```

上記のコードは、GUI上のオプションの History、Channels、Expressions、Constraints に関する制御部分なのですが、Include texture info に関してはその少し後で次のようにコードなっています。こちらの扱い方は 2022.1 でも変更されていません。

``` mel
			if (`optionVar -ex exportIncludeShaders`) 
			{
				if (`optionVar -q exportIncludeShaders`) 
				{
					file -sh true;
				} else {
					file -sh false;
				}
			} // Else don't change the default value.
```

そして、これらの設定値によって、File Translator 実行中に、そのプラグインが Maya シーンにどのようにアクセスできるかが変わるようなのです。コマンドと違って File Translator の実行中というのは、何か最適化された状態になるのでしょうかね。。
たとえば、History が Off だと、プラグインはコンストラクションヒストリが取れなくなります。よって、ジオメトリのアニメーションや、スキンバインド情報がエキスポートできなくなります。
たとえば、Channels が Off だと、translate や rotate などのアトリビュートのアニメーションが取れなくなります。アニメーションを評価できなくなり、たとえばタイムを進めてアトリビュート値を得ても値は変わらなくなります。
Expressions や Constraints や Include texture info については確認してないので分かりません。エクスプレッションやコンストレインが評価されなくなったり、マテリアルが取れなくなったりするんですかね。知らんけど。

mel コードを見てもわかりますが、これらのオプションは、file コマンドのオプションにすると、順番に -constructionHistory(-ch)、-channels(-chn)、-expressions(-exp)、-constraints(-con)、-shader(-sh) となります。マニュアルによると、これらは -exportSelected(-es) の挙動を修飾するオプションであると説明されています。
そして、実はこれらは、ただのオプションではなく「ステート」なのです。Export Selection の file コマンドを呼び出すときに同時に指定して修飾するのではなく、状態として設定が残り続けるのです。
実は、Maya起動後、一度も Export Selection をメニューから実行せずに、file コマンドから USD エキスポートなどを呼び出す分には問題は起こりません。しかし、一度メニューから maya シーンや FBX ではない何かをエキスポートしてしまうと全てのステートが Off にされるので、以降は file コマンド直接呼び出しでもエキスポートできなくなります。maya シーンや FBX をメニューからエキスポートすれば全てのステートが On になって、以降は file コマンド呼び出しでもエキスポートできるようになります。

結局、File Translator プラグインにとって、これらは重要なステートであり、普通は全て On でなくてはなりません。
だから、そのプラグインにとって必要なステートを On にして呼ばれるようにするということも、プラグインの責任といえるのかもしれません。
たとえば、ATOM は、File Translator として実装されていますが、メニューから呼び出す専用のダイアログを持っています。そこからの呼び出しでは doExportAtom.mel というシステムmelが呼ばれるのですが、そこでは、最初に現在のステートを変数に保存してから必要なものを On にし、エキスポートを実行、最後に元に戻すということがされています。
でも、ATOM も Export Selection から呼び出してしまうと、そこを通らないので問題になります。結局、現状の performFileAction.mel の造りは、Export Selection から呼び出す場合に、プラグイン側でステート設定に責任を持つことができない造りなのです。

ただ、このような技術的背景が分かっていれば、たとえシステムmelを書き換えなくても、不便ながら対処は可能です。
たとえば、メニューから USD をエキスポートします。でもアニメーションは出ません。
なので、スクリプトエディタにログされたコマンドをコピペして次のように実行するのです。

``` mel
file -chn 1; file -ch 1; file -exp 1; file -con 1; file -sh 1;
// ↓ ログからコピペした file コマンド。以下のような感じ。
file -force -options ";exportUVs=1;exportSkels=auto;exportSkin=auto;exportBlendShapes=0;exportColorSets=1;defaultMeshScheme=catmullClark;defaultUSDFormat=usda;animation=1;eulerFilter=0;staticSingleSample=0;startTime=0;endTime=100;frameStride=1;frameSample=0.0;parentScope=;exportDisplayColor=0;shadingMode=useRegistry;convertMaterialsTo=UsdPreviewSurface;exportInstances=1;exportVisibility=1;mergeTransformAndShape=1;stripNamespaces=0" -typ "USD Export" -pr -es "D:/tmp/test.usd";
```

でも、こんなこと不便でやってられないと思いますので、システムmel書き換えとなりました。

ちなみに、システムmelを書き換えずに対処できそうな方法がもう1つだけあります。
問題箇所の直後に次のようなコードがあります。

``` mel
			//	If the file type is an animation type, then
			//	set the channels value to true. Animation 
			//	exporters should set an int optionVar in the
			//	export options script. The optionVar should be
			//	set true to always export animation.
			//
			string $isAnimOptVar = ($fileType+"AnimationFile");
			float $channelsValueChanged = false;
			float $oldChannelsValue = `file -q -chn`;

			if (`optionVar -ex $isAnimOptVar` && 
				`optionVar -q $isAnimOptVar`) 
			{
				file -chn true;
				$channelsValueChanged = true;
			}
```

何やら、ファイルタイプ名の後に "AnimationFile" を付け足した optionVar を 1 に設定しておくと、-channels だけは On になるようですね。
たとえば USD の場合は "USD ExportAnimationFile" という名前になります。
やってみました。

``` mel
optionVar -iv "USD ExportAnimationFile" 1;
```

この値は個人設定に保存されるので、一度やれば良いです。
システムmelを書き換える前の状態で、この設定で USD でスケルトンアニメーションをエキスポートしてみたところ、こうなりました。
![usdview_jntonly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230590/58e6870f-d640-525b-40bd-4f74135e572f.png)
joint のアニメーションは正常に出力されていて動いているのですが、-constructionHistory が Off のためにスキンバインド情報が出力されておらず、メッシュが置いてきぼりになっています。。

やっぱりダメですね。設定した optionVar は削除しておきましょう。

``` mel
optionVar -rm "USD ExportAnimationFile";
```

この抜け道が用意されている意図はあまりよく分かりませんが、はるか昔のバージョンから存在するようです。
スケルトンのアニメーションだけのファイルのような、アトリビュート値のアニメーションが取れれば問題ないプラグインなら使えるかもしれません。その場合、プラグインのロード時に呼ばれる initializePlugin() で optionVar を設定すれば良さそうです（実際に試して、それで大丈夫でした）。しかし、-channels 以外のステートが全て Off であることによる弊害が他に無いかどうか、私も深くは調べていないので確実なことは言えません。

やはり、システムmel書き換えが、現状の最善策といったところでしょうか。
とりあえず、それでしのいで、次のアップデートでの修正を期待して待つことにしますかね。。。