昨日に続き Maya Advent Calendar 2020 の20日目の記事です。
明日は tanakou829 さんです。
今回はタイトルにあるように Maya から Unity へUVアニメーションをエクスポートするための記事です。
実は2016年にも一度「【Maya/Unity】MayaからUnityにUVアニメやカラーアニメを持っていくスクリプト」という記事を書いていました。
ただ今見返すと力技過ぎてスマートではないので、改めて書いてみようと思いました。
これがきっかけの1つ目です。
2つ目としてはセガさんの2年前に「MayaからUnityへのUVアニメーションエクスポート
」という記事がありました。
こちらは C++ を使われているのでハードル高そうに感じる方もいらっしゃるだろうと思うので、
Python を使ったサンプルを作ってみようかなと。
※セガさんの記事では FBX SDK を使われていますが、こちらの記事では使っていません。
Python版の FBX SDK もあるようなので、そちらを使えば MSceneMessage.addCheckFileCallback() から
渡される MFileObject から書き出し後のFBXのパスを取得する事で FBX 自体を直接編集できると思います。
しかし、FBX SDK を触ったことがなく今回時間がなかったため、(余裕ができたら試します)
書き出し後に追加したアトリビュートを削除したり、新しいアニメーションノードを作らず
place2dTexture に接続されているものを流用してシーンをなるべく汚さないオプションを付けています。
解説しているファイルはこちらのリポジトリにあります。
試される場合は kkUvAnimationExport.py を Maya の Plugin のパスが
通っている所(よく分からない場合は C:\Program Files\Autodesk\Mayaバージョン\bin\plug-ins )に、
UvAnimPostprocess.cs を Unity のプロジェクトのどこかに Editor フォルダを作ってその中に、
それぞれコピーして下さい。
※使用にされた際に不具合が出ても責任は取れませんので自己責任でお試し下さい。
Maya側の処理について
< Mayaは2019.3.1で検証しています >
まず、Maya側でエクスポートする時に処理を走らすために maya.api.OpenMaya の MSceneMessage のコールバックを利用します。
(MSceneMessageのコールバックに関しては 前日の記事 をご覧下さい。)
今回使用したのは MSceneMessage.addCallback の kExportStarted と kAfterExport です。
こちらで書き出し直前と書き出し後に処理を走らせる事ができます。
ちなみに選択した状態で書き出す事を前提に作っています。
また、Game Exporterでの書き出しは MSceneMessage.addCallback でセットしていても呼ばれないので、
チームでGame Exporterを使われている場合はご注意下さい。
(Game Exporter の書き出し時にフックできる方法があれば教えて下さい…)
実際のファイルは下記にあります。
uvAnimationExport 関数が処理のメインとなる部分です。
選択しているノードとその子ノードを再帰的に取得し、
各メッシュに適用されているマテリアル → place2dTexture → アニメーションカーブ という流れで
UVアニメーションを取得します。
流用する場合はそのアニメーションのアウトプットを追加のアトリビュートに繋ぎます。
そうでない場合は getAnimData 関数でカーブの情報を辞書型を取得して、
setAnimData 関数で新しいアニメーションカーブにセットします。
出力後に削除するオプションがONの場合は、書き出し後に removeAnim 関数で
追加したカスタムアトリビュートや、追加したアニメーションカーブノードを削除しています。
※ファイル内にもメモしていますが、OpenMaya の removeAttribute() でアトリビュートを削除すると
なぜかMayaが落ちる (API 1.0, 2.0 どちらも) ので、仕方なく maya.cmds の deleteAttr() を使用しています。
そして、Unity 側で使用したい Shader 内のテクスチャープロパティ名を、
string 型のカスタムアトリビュートをセットして指定できます。
その際アトリビュートを TargetTexProp として下さい。
※何も指定されていなければ、Legacy パイプラインの _MainTex を指定するようにしています。
また、Unity 側で TargetTexProp でアトリビュート名が始まっているかしか見ていないため、
末尾に何かついていても大丈夫です。
下記の例ですと、URP のデフォルトの Lit Shader の BaseMap のアニメーションに変換します。
Unity側の処理について
< Unity は2020.1.17f1で検証していますが、使用している関数的に2018.4以降なら大丈夫だと思います >
次は書き出し後の FBX にセットしたカスタムアトリビュートを
Unity 側でインポート時に通常のUVアニメーションに自動変換されるような処理についてです。
こちらでは、
① OnPreprocessModel 関数
② OnPostprocessGameObjectWithUserProperties 関数
③ OnPostprocessGameObjectWithAnimatedUserProperties 関数
を使用しています。(この順番で処理されます)
①ここで modelImporter.extraUserProperties からこの処理に関わるプロパティを一旦全部削除します。
②ここで Maya側 でセットした TargetTexProp のカスタムアトリビュートがある場合、
modelImporter.extraUserProperties にその GameObject名 と一緒に追加していきます。
③ここではインポートされた GameObject と Maya でセットしたアニメーションしているカスタムアトリビュートのカーブ情報( EditorCurveBinding の配列)が入ってくるので、②で追加した modelImporter.extraUserProperties 内を検索して GameObject名 が一致するものがそれを propertyName に使用し、type は GameObject が持つ Renderer から判別し、path は AnimationUtility.CalculateTransformPath() を使用して相対パスをセットします。
こちらでの注意点としましては、Unity の Shader を書いてる方ならご存知だと思いますが、
Legacy パイプラインですとメインテクスチャーのプロパティ名は _MainTex ですが、
URP では _BaseMap、HDRP では _BaseColorMap となっている点です。
Legacyパイプラインから変えるのは100歩譲っていいですが、URPとHDRPで変えているのはなぜじゃ、なぜなのだ…
コメントをお書きください