[UE5]AnimToTextureプラグインの使い方

# 概要

UE5のCityサンプルでは、SkeletalMeshをStaticMesh化してアニメーションを流す。といったことをやっていました。
その概要は以前の記事

https://qiita.com/marv_kurushimay/items/b3d98f208fa494f1ddec

でまとめています。

この記事では、そのワークフローで使われていたAnimToTextureプラグインの使い方についてまとめました。

確認したエンジンバージョンは、**UE5.0.0**です。

# SkeletalMeshからStaticMeshを作成
まずは、この仕組み用のStaticMeshを作成します。
AnimToTextureプラグインに実装されているBlueprint関数を呼び出すことで簡単に生成できます。
![BP_ConvertSkeletalToStatic-EventGraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/5939d3ca-39ff-5016-aa68-21e7ab7b1a19.png)

エディタユーティリティブループリントを作成し、Run関数をオーバーライドして、**ConvertSkeletalMeshToStaticMesh**のBP関数を配置します。
引数は
+ SkeletalMesh
    + コンバート元のSkeletalMeshアセットを指定
+ PackageName
    + 出力するStaticMeshアセット名を指定します
+ LODIndex
    + StaticMeshに出力するLODを選ぶ場合は、ここで指定します。-1の場合は、コンバート元SkeletalMeshに存在するすべてのLODを出力します。

あとは、エディタユーティリティブループリントを実行するだけです。
![SuccessToConvert.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/5f5f4f1f-c60c-9c98-2c9d-38d8e05d4ee9.png)
生成に成功すると上図のような通知が出ます。また、実行結果はログに出力されますので、うまく生成されないときはログを確認してください。

:::note info
***将来的な改善点***
今回は、決まったSkeletalMeshを決まったパスに出力することにしたので、簡単な構造になりました。

将来的には以下のような変更を加えると、使いやすいツールになりそうです。
+ AssetActionUtilityベースにして、SkeletalMeshの右クリックメニューから変換を実行
    + 引数付きの関数にして、PackageNameやLODIndexも選ばせるといいかも
+ EditorUtilityWidgetベースにして、各種パラメータを設定しやすくする
:::

# アニメーションをテクスチャに焼き付ける
今回はVertexAnimationとBoneAnimationの両方を作っていきます。
実際は、見た目や用途に応じてどちらか一つになると思いますが、その場合は要らないほうは無視して進めてください。

## アセットの準備
元となるアセットは、グレイマンの女性版(SK_Mannequin_Female)を使って作っていこうと思います。
![SK_Mannequin_Female.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/1a42499b-2523-12d4-fbd3-89d2dc2e90c8.png)
（UE5のQuinnにしなかったのは、テスト環境へのアセットの持ち込みが面倒だったから…）
### テクスチャ
まずは、アニメーションを焼き付ける先のテクスチャを用意します。VertexAnimationの場合は、PositionとNormalの2枚。BoneAnimationの場合は、PositionとRotation、Weightの3枚必要です。
![Textures.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/51f885cb-f93a-0fc7-db36-ed2489c3165e.png)
これはただの2Dテクスチャでいいのですが、エディタ上ではRenderTargetではないただのテクスチャアセットを作る術がありません。そのため、上図のように適当な画像ファイルをインポートしてアセットを作ります。

テクスチャのサイズやフォーマットは、のちほど実行するの変換の時に勝手に変更してくれます。そのため、その辺にある適当な画像ファイルをインポートしてアセットを作ってください。

### マテリアル
次にAnimToTextureの仕組みに対応したマテリアルとマテリアルインスタンスを作成します。
アニメーション計算に必要な機能は、マテリアルレイヤーのマテリアル関数化されていますので、それを参照するだけで済みます。
![M_Body_Animation-MaterialGraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/719ab126-8d85-961c-007c-231730088bc1.png)
SK_Mannequinを使っているので、ベースはM_Male_Bodyのマテリアルを使います。新たにノードを追加しますので、アセットをコピーして**M_Body_Animation**と名付けました。
追加部分は緑枠で囲った部分で、VertexAnimationは **/AnimToTexture/Materials/ML_VertexAnimation** 、BoneAnimationは **/AnimToTexture/Materials/ML_BoneAnimation** を使います。

AnimToTextureプラグインに入っているサンプルでは、VertexAnimationとBoneAnimationは別のマテリアルで作られていましたが、今回は一つのマテリアルにStaticBoolParameterを使って分岐するようにしました。

また、各マテリアル関数から出力されたWorldPositionOffsetはそのまま使えますが、出力されたNormalは元のNormalとブレンドする必要がありますので、 **BlendAngleCorrecedNormals** ノードを使ってブレンドします。

### マテリアルインスタンス
マテリアルを用意したので、次はマテリアルインスタンスを用意します。今回は、VertexAnimationとBoneAnimationの両方を出力しますので、(Body, ChestLogo)×(Vertex, Bone)の組み合わせで4つのマテリアルインスタンス作ります。

先ほど作成したM_Body_Animationを親にしてマテリアルインスタンスを作ります
![MaterialInstance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/59a9f34f-aab1-8043-d31f-70731af58f62.png)
VertexAnimationとBoneAnimationで修正する箇所は赤枠の辺りです。

+ Animate
    + TRUEにする
+ Bone or Vertex
    + M_Body_Animationで追加したStaticBoolParameter
    + VertexAnimationのマテリアルインスタンスはOFF、BoneAnimationマテリアルインスタンスはONにする
+ UseFourInfluence (BoneAnimationのみ)
    + 普通のBoneAnimationと同じで、影響するBone数の指定
    + 1,2,4から選べるが、今回は一般的なBoneAnimationと同じで4を選択しました
+ UseUV1
    + アニメーション計算時の参照するUVを指定します
    + ST_Mannequin_Femaleを作った時に、ここで必要になるUVが追加されていますので、ここではUV1を使うように指定します。（UV0はテクスチャ用のUV）

そのほか、テクスチャは適切なFemaleのMaskテクスチャとNormalテクスチャをアサインしてください。

なお、GlobalScalarParameterValuesやGlobalTextureParameterValuesに、アニメーション用のパラメータがいくつかありますが、ここでは設定不要です。
テクスチャ出力時の処理で、必要な値を自動的に設定してくれます。

### スタティックメッシュ
次に、アニメーションを適用するスタティックメッシュを用意します。

SkeletalMeshから作ったStaticMesh(ST_Mannequin_Female)に、先ほど作ったマテリアルインスタンスを設定します。
VertexAnimationとBoneAnimationがありますので、ここでも2つ複製してそれぞれ**ST_Mannequin_Female_VertexAnim**、**ST_Mannequin_Female_BoneAnim**としました。
![ST_Mannequin_Female_BoneAnim.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/db31f1c9-5141-44c1-7d13-910510e9e885.png)
複製した各StaticMeshに、マテリアルインスタンスをアサインしてください。この時点では、上図のように壊れていますが気にしません。

### データアセット
Animationをテクスチャ変換するときのパラメータをデータアセットで指定します。
![DataAsset.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/57a040d9-0e65-bb5a-48d9-e04a0be43231.png)
コンテンツブラウザからデータアセットを作成し、クラスはAnimToTextureDataAssetを指定します。
![DA_BoneAnim.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/01b1ffc8-519c-7493-1ff5-14c9729ca7fa.png)
上図の内容はBoneAnimationのデータアセットの設定例です。

+ スケルタルメッシュ
    + Skeletal Mesh
        + 元となるSkeletalMeshアセットを指定します（ここではSK_Mannequin_Female）
+ スタティックメッシュ
    + Static Mesh
        + 先ほど複製した変換先のStaticMeshを指定します（ここではST_Mannequin_Female_BoneAnim）
        + ここで重要なのは、Animation対応のマテリアルインスタンスをアサインしたStaticMeshを指定することです
            + マテリアルを差し替えていないST_Mannequin_Femaleを指定すると正しく変換できません
    + UVChannel
        + マテリアルインスタンスで指定したUV1を使うので、1を指定します
+ テクスチャ
    + BonePositionTexture / BoneRotationTexture / BoneWeightTexture
        + 先ほど適当な画像ファイルで作った2Dテクスチャアセットを指定します。
    + Position and Rotation Precision
        + 座標と回転の精度(8bit or 16bit)を指定します
        + Cityサンプルのように、カメラから遠くにLODとして出すには8bitで十分だと思います
メッシュサイズが大きかったり、カメラの近くに出す場合は16bitを検討してください。当然、その分テクスチャ容量は増えます。
+ Animation
    + Animation Sequences
        + テクスチャにベイクしたいアニメーションアセットを指定します。（ここでは、Idle、Walk、Runの3つを登録しました）
        + 特定のフレームだけ出力することもできるようなので、必要に応じて調整してください

VertexAnimationのデータアセットも似たような感じで設定します。

## テクスチャに焼き付ける処理を行うBPを作成
本丸のテクスチャに焼き付ける処理を行うBlueprintを作ります。
といっても、基本的にAnimToTextureプラグインにあるアセットのコピペで済ませました。

**/AnimToTexture/Characters/Mannequin/BP_AnimToTexture** をプロジェクトの作業フォルダにコピーします。
![BP_AnimToTexture-EventGraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/56e3a994-40f6-0bf3-b917-1c14a349cdc0.png)
内容は上図のような構成で、前半がVertexAnimation、後半がBoneAnimationの焼き付け処理を行っています。

**AnimationToTexture** でテクスチャの焼き付け処理をして、データアセットに指定したテクスチャを更新します。

**UpdateMaterialInstanceFromDataAsset** では、焼き付けに使ったパラメータをMaterialInstanceに設定する処理が行われます。
この処理で、マテリアルインスタンス内にテクスチャやその他必要なパラメータが自動的に設定されます。

図にあるようにここで設定するパラメータは三種類です。
+ データアセット
    + VertexAnimation、BoneAnimationに合わせて、前項で作ったデータアセットを指定します。
+ マテリアルインスタンス
    + スタティックメッシュで指定しているマテリアルインスタンスを指定します。
    + 使用しているマテリアルインスタンスごとに行う必要があります。
将来的には、データアセット内のStaticMesh（もしくはSkeletalMesh）から、マテリアルインスタンスを取得してループを回す。とかしたほうが良さそうです。
+ マテリアルパラメータの場所
    + 変更対象のマテリアルパラメータの場所を指定します
    + 今回、ML_VertexAnimationやML_BoneAnimationはマテリアル関数として参照したので、Global Parameterを指定します

以上でデータのセットアップは終了です。

## 実行！
![ST_Mannequin_Female_BoneAnim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431039/32310c25-e6de-b7d2-7423-8a1d97931d8d.gif)
実行した結果、先ほどは壊れていたプレビューもこの通り正しい見た目になりました。

# あとがき
分かってしまえば、アニメーション付きStaticMeshのアセットは意外と簡単に作れることがわかりました。

ただ、実際のワークフローに組み込むには
+ 大量生産するには、便利ツールの作成が必要
    + ある程度自動化されていますが、大量生産するには手動対応部分がまだ多い
+ アニメーション情報テクスチャと、マテリアルインスタンスパラメータの結びつきが強い
    + アニメーション情報テクスチャだけ差し替えるのが難しい
    + マテリアルインスタンスごと差し替えていけば大丈夫？
+ 焼き付け処理の段階でマテリアルの個数を把握している必要がある
    + BPの修正で何とかなりそう？

などなど、いろいろと改善点がありそうです。

ただ、使いこなせればかなり強力な武器になると思います。遠景キャラの表現にはコーエーの無双シリーズ以来Imposterでテクスチャアニメーションさせる方法が良く使われてきましたが、この結果を見るとこちらの表現に置き換わっていきそうな気もしています。