Unity<=>Maya受け渡せるカスタムアトリビュートまとめ

[QualiArts Advent Calendar 2022](https://qiita.com/advent-calendar/2022/qualiarts) の6日目の記事になります。

# はじめに
ゲーム開発においてDCCツールでアニメーションを作成し、ゲームエンジンに取り込むフローは一般的です。
さらにFBXファイルを使用してアニメーションを受け渡す場合、オブジェクトの移動/回転/拡縮のキーが打たれるのが基本的だと思います。

ただしプロジェクト次第では、特殊なアニメーションをカスタムアトリビュートとして受け渡す需要があります。
今回は、Unity<=>Maya間におけるカスタムアトリビュートについて記述します。

# Maya
オブジェクトを選択し、修正 →アトリビュートの追加 から設定ウィンドウを読み出します。
アトリビュート名とデータ型を選択して追加します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/daf39dc7-31ad-8765-6cac-35a5eecbc38f.png" width=256><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/08a52900-65a9-1baf-b073-6b4bb3d9d66c.png" width=256>

vector, int, string, float, boolean, enumの６つのデータ型を選択することができます。
通常のグラフエディタで確認することができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/8d977e1f-e4fa-8a4a-4cf9-bc62c100fcf7.gif" width=512>

スクリプトから設定することで、"stringArray"など複雑なデータ型も指定することができますが、グラフエディタでは表示されません。
修正→アトリビュートの修正からアトリビュートの存在を確認することはできます。
```
cmds.addAttr('pCube1', ln='customStringArray', dt='stringArray')
cmds.setAttr('pCube1.customStringArray', 3, "a", "b", "c", type="stringArray")
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/4424ebd0-9f07-5488-a92f-59ac3878c075.png" width=256>

# Unity
FBXのImportオプションのAnimationｍ→AnimatedCustomPopertiesにチェックを付けることでカスタムアトリビュートを有効にできます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/4b638041-2001-1de6-e4b2-410c488f4775.png" width=256>

さてAnimationClipを見てみましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/6ea484df-dd45-a9ae-d1b3-765f3c5c20cc.png" width=256>

...Floatしか来てないですね、なぜでしょうか。。。

Fbxをインポートした際に呼ばれるAssetPostprocessorのOnPostprocessGameObjectWithUserPropertiesと、
OnPostprocessGameObjectWithAnimatedUserPropertiesを確認してみます。
```CustomPropertyMotionImporter.cs

using UnityEngine;
using UnityEditor;

public class CustomPropertyMotionImporter : AssetPostprocessor
{
    void OnPostprocessGameObjectWithUserProperties(GameObject go, string[] propNames, System.Object[] values)
    {
        Debug.Log("=====UserProperties=====");
        foreach (var propName in propNames)
            Debug.Log(propName);
    }

    void OnPostprocessGameObjectWithAnimatedUserProperties(GameObject go, EditorCurveBinding[] bindings)
    {
        Debug.Log("=====AnimatedUserProperties=====");
        foreach (var b in bindings)
        {
            Debug.Log(b.propertyName);
        }
    }
}
```
こちらの結果が得られました。
```
=====UserProperties=====
currentUVSet
customVector
customInt
customString
customFloat
customBoolean
customEnum
=====AnimatedUserProperties=====
customFloat
```
つまり、アトリビュート名を取得できるか、カーブが取得できるかは別だということです。
更にStringArrayのような複雑なデータ型はアトリビュート名すら取得することができませんでした。

| データ型    | アトリビュート名 | カーブ | 
| ----------- | ---------------- | ------ | 
| Float       | ◯               | ◯     | 
| Vector      | ◯               | ×      | 
| Int         | ◯               | ×      | 
| String      | ◯               | ×      | 
| Boolean     | ◯               | ×      | 
| Enum        | ◯               | ×      | 
| StringArray | ×                | ×      | 

# まとめ
Mayaでカスタムアトリビュートを設定する方法、Unityでカスタムアトリビュートを取得する方法と、データ型による違いを記述しました。
実用的なものはFloatのみであり少しさみしく感じましたが、アトリビュート名を工夫することで特殊な需要を満たせすことができるかもしれません。

Unity単体、Maya単体での記事はありますが、連携に関する記事はあまり見当たりません。
この記事がゲーム開発の一助になれば幸いです。