Part 1はこちらです:
続編:
1 はじめに
前回は、UnrealのPCGシステムを活用してライブの会場と観客を生成する方法を紹介しました。普通のActorではなく、Instanced Actorの形式で観客をレベル内に配置することで、Actorの数量を抑え、CPUの負担を軽減することができました。
しかし、Instanced Actorは、遠距離でActorをInstanced Static Meshに切り替えるという仕組みですので、ここで大きな問題が生じます:観客キャラクターは動かなくなります。Animation Sequenceにせよ、Animation Blueprintにせよ、一般的にUEでキャラクター動かす方法は、Skeletal Meshであることが前提です。Static Meshではカスタム処理を実行できないため、マテリアルでアニメーションを制御するしかありません。
そのため、本記事ではUnreal EngineのAnimToTextureプラグインを使用してVATを作成し、Static Meshのキャラクターモデル(および持ち物)を動かす方法を紹介したいと思います。
環境
Windows 11 25H2
Unreal Engine 5.7.1
プロジェクトのソースコードとアセットはこちら(GitHub)
https://github.com/n-ln/ue-penlight-crowd
2 VATとAnimToTextureプラグイン
2.1 VAT・BATとは
Vertex Animation Texture(VAT)は、メッシュ各頂点(Vertex)が各フレームでの位置を記録したテクスチャです。これをマテリアル内で読み込んで、頂点のWorld Position Offsetを制御することによって、メッシュを動かすことができます。通常はCPUが処理するアニメーションですが、この方法はスケルトンを介さないため、GPUで完結します。そのため、都市の人々や、ゾンビの群れなど、大量のNPCを実装したい場合がよく使われる技術です。
Bone Animation Texture(Skeleton Animation Textureともいう)はVATのバリエーションであり、主な違いは、BATのテクスチャでは頂点それぞれの位置ではなく、スケルトンのボーンの位置を記録します。レンダリングの時は、スケルトンのウェイトによって頂点のOffsetを計算します(スケルトンの情報は利用されますが、処理はGPU内で完結します)。

アニメーションを記録したBone Animation Textureの一例
通常のVATと比べると、Bone Animationのメリットは:
- 同じスケルトンであれば、複数のメッシュ間アニメーションを再利用しやすい。
- テクスチャが小さい(特に複雑なメッシュ)。BATはテクスチャの横幅としてボーン数(数十程度)分だけのピクセルが必要です。一方VATは頂点を一つずつ記録するため、データ量が膨大になります。
デメリットは:
- 解算の必要があるため、GPUにとってはVATより負荷が高い。
今回はBone Animation Textureを使用していますが、実装方法は両方に共通する部分が多いと思います。なお、厳密に言うとVertex AnimationとBone Animationは別物ですが、名前としてはVATの略称が広く通用するので、ここ以降はVATとBATを区別せずに呼びます。
2.2 AnimToTextureについて
VATの制作は主にHoudiniなどの専門DCCソフトで行われてきましたが、Epic Games公式は、UE5のDemo「City Example」の公開を伴って、AnimToTextureというプラグインを導入しました。これによって、Unreal Engine内でも直接的にVAT・BATを制作できるようになりました。
まずは PluginでAnimToTextureプラグインを有効にします。
再起動したら、今回利用するアセットはEngine→Plugins→AnimToTextureのContentフォルダで確認できます。
「Materials」フォルダには、VAT生成と解算のためのMaterial Functionがあります。
「Characters」フォルダには、作成したVertex AnimationとBone Animationの例、そしてVATを作るのに必須のアセットが揃っています。
これからはプラグインのアセットを利用してVATを作りますが、ここのファイルをそのまま編集・使用するとEngineのプラグインを上書きしてしまい、他のプロジェクトにも影響します。そのため、必ず編集前に対象のアセットを複製するか、もしくはプラグイン丸ごとプロジェクトに複製して、コピーを編集しましょう。
3 観客(キャラクター)のアニメーション
3.1 アニメーションを用意する
VATを作る前に、もちろんアニメーションが必要です。これは私があまり得意ではないので、今回はUnreal Engine内で作った、簡単な手を上下で振るアニメーションを一つだけ使います。
AnimToTextureプラグイン自体は、複数のアニメーションを一つのテクスチャにベークすることが対応しているので、アニメーションがあれば、群衆の動きの多様性を増やすことも簡単だと思います。
3.2 VAT用Static Meshとマテリアルの作成
まずは、素材のSkeletal MeshからStatic Meshをエクスポートします。Skeletal Meshのウィンドウに、上のMake Static Meshボタンで、Static Meshアセットを作成することができます。このStatic Meshは最終的にBone Animationで動くメッシュとなるので、名前に「BA」を付けて区別します。
VATのメッシュでもLODの対応が可能ですが、各LODのVAT処理が別になります。今回はシンプルに作りたいので、シングルLODで実装します。加えて、VATメッシュが基本的に遠距離用なので、ポリゴン数を高くする必要はそんなにありません。したがって、ここはSkeletal MeshのLODを2に固定し、10000 Triangleくらいのメッシュを作りました。
新しく生成したStatic MeshはNaniteが無効の状態ですが、次回で紹介する予定のライティング技術の最適なパフォーマンスはNaniteに依存するので、ここはNaniteを有効に変更します。
この時点では、新しく作成したStatic Meshと元のSkeletal Meshはまだ同じマテリアルを使っています。しかし、VATの実装はマテリアルを改変する必要があるため、元のSkeletal Meshに影響しないように、キャラクターのマテリアルを複製して、Static Meshに設定します。
UEのマテリアル自体はインスタンスを作らなくても使えますが、今回使うAnimToTextureプラグインはMaterial Instanceだけを処理できるので、VAT用メッシュのマテリアルはすべてMaterial Instance形式であることを確認しましょう。
次に、マテリアルにBone AnimationのMaterial Functionを追加します。
UEのマテリアルは、大体は今回使ったMannequinと似たような、Base Color、Normal、Roughnessなどをアウトプットに接続する形式ですが、Bone AnimationのFunctionの入力はMaterial Attributeなので、まずはこのマテリアルをMaterial Attribute形式に変換しましょう。
MakeMaterialAttributesノードを追加して、元々使っていたマテリアルピンをMaterial Attributeノード上の各ピンに移行します。
マテリアル出力ノードをクリックし、Use Material Attributesを有効にします。これで従来のピンが全てなくなり、一つのMaterial Attributeピンに変わります。MakeMaterialAttributesの出力をここと接続したら、マテリアルは元の見た目に戻るはずです。
移行したマテリアルの動作を確認したら、MakeMaterialAttributesと最終の出力ノードの間にMF_BoneAnimationノードを追加します。
デフォルトの状態だとこのFunctionノードが検索結果に出てきませんが、プラグインのサンプルマテリアルからコピーするか、またはMF_BoneAnimationのDetails欄でExpose to Libraryを有効にすることで解決できます。

Material FunctionのExpose to Library設定を有効にする
これでマテリアルの編集は一旦完成します。
3.3 Bone AnimationテクスチャをBakeする
まずはプラグインのフォルダから以下の必要なアセットをコピーします。
- Data Asset(DA_BoneAnimation):メッシュ、アニメーション、ベーク設定などを指定するアセット
- Editor Utility Blueprint(BP_AnimToTexture):テクスチャのベークを実行するEditor BP
- Bone Animationテクスチャ(3つ):BonePosition、 BoneRotation、BoneWeightを記録するテクスチャ。ベーク中が上書きされるため、現在の内容は何でも構いません。
Data Assetを開いて、VATの設定をセットアップします。
Skeletal MeshとStatic Meshで元のメッシュとVATメッシュを選択し、LODIndexではそれぞれ対応するLODを設定します。
Textureの部分で、ModeをBoneにして、下のテクスチャ欄で三つのテクスチャアセットを順番で設定します。Max Height/Weight、Precisionなどでテクスチャのファイルサイズをコントロールできますが、今回作るアニメーションは短いなので特に調整する必要がありません。
Animationの部分で、Sample Rateをアニメーションと同じフレームレートに設定し、Anim Sequencesで用意したアニメーションを追加します。ここは、前にアニメーションを作ったときに間違って0-30で31フレームのSequenceを作ってしまったので、Custom Range設定で0-29の区間に限定し、1秒ちょうどのアニメーションにしました。
その下、Material部分のAuto Play設定は後でMaterial Instanceで切り替えできるので、オン/オフどちらでも構いません。現時点ではAuto Playをオンにするほうが効果確認しやすいですが、最終的な実装ではAuto Playをオフにし、コードでアニメーションを制御する仕組みになります。
これでData Assetに関する設定が完成します。DAをセーブして、Editor Utility Blueprint(EUBP)を編集します。このBPはVertex AnimationとBone Animationの両方を処理できますが、Vertex Animationの部分は使わないので削除します。
Bone Data Assetには、先に作ったData Assetを指定します。
そして、Update Material Instance from Data Asset関数で、Material InstanceにカスタムMannequinのマテリアルを選択します。複数のMIがある場合はこのノードをMIの数量分コピーする必要があります。
DAとEUBPの設定が完了したら、セーブしてContent Browserに戻ります。EUBPを右クリックして、「Run Editor Utility Blueprint」でEUBPを実行できます。少し待ち、Output LogでErrorがなければベーク完了です。
Material Instanceを見ると、AnimToTextureに関するパラメータが追加されたことを確認できます。Auto PlayをOnにしたら、Static Meshがベークされたアニメーションと同様に動くようになりました。
3.4 Naniteに関するバグと解決方法
先ほど記事の通りStatic MeshのNaniteを有効にすると、AnimToTextureのバグに遭遇するかもしれません。具体的には、メッシュのWorld Rotationが0以外の場合、動いている部分が平らになってしまいます。
このバグの確認と解決方法については、Anonymous UserさんとChris AndersonさんのEpic Developer Community投稿が参考になりました。
要するに、Material Function内のTransform計算は、Local SpaceからInstance Spaceに変更する必要があります。アイデア自体は簡単ですが、変更の必要がある箇所が多重ネストされたので、実際の作業はかなり複雑になります。
以降のプロセスはプラグインアセットの変更になるので、上書きではなく、コピーして入れ替えるほうが安全です。特にObjectPivotPointはエンジン全体で使用されるMaterial Functionなので、他のエンジン機能に影響しないよう、必ず元のアセットは改変しないようをご注意ください。
流れは以下のとおりです。
(1) 先で使用したMF_BoneAnimationをコピーし、MF_BoneAnimation_Customなどの名前をつけます。作成したマテリアル内のMF_BoneAnimationをこの新しいMaterial Functionに置き換えます。
(2) ダブルクリックしてMF_BoneAnimation_Customの編集画面に入ります。ここでも同じ方法で、BlendBonePositionAndNormalとGetFrameSwitchの2つのMaterial Functionをコピーして、Customバージョンを作ります。GetFrameSwitchはこのパートではまだ編集する必要はありませんが、ここも一旦作成しておきます。
(3) BlendBonePositionAndNormal_Customをダブルクリックして開きます。ここにある4つのBonePositionAndNormalノードをすべてCustomバージョンに置き換えます。
(4) BonePositionAndNormalを開いて、ここで赤枠部分2つのTransformPositionノードの変換方式を、それぞれLocal Space to Absolute World Space/Tangent SpaceからInstance & Particle Space to Absolute World Space/Tangent Spaceに変更します。
(5) またBonePositionAndNormal内で、青枠部分のObjectPivotPointをコピーしてCustomにし、入ります。そこにある2つのTransformPositionノードも同様にLocal Space to Absolute World SpaceからInstance & Particle Space to Absolute World Spaceに変更します。
これにより、Naniteでの描画バグへの対処が完成します。合計で、プラグイン内のMaterial Functionを5つコピーして変更しました。今後VATのマテリアルを新しく作成したい時は、元のMF_BoneAnimationではなく、変更したCustomバージョンを使用することになります。
マテリアルが修正されたMannequinをレベルに配置して検証したら、どの角度でも正しい見た目になることを確認できます。
4 ペンライト(持ち物)のアニメーション
ここまでは、Instances ActorをVATで動かせるようになりましたが、ペンライトはまだ一緒に動いていません。Skeletal Meshであれば持ち物のStatic MeshをBoneやSocketに添付するのはシンプルな操作ですが、VATの状態になるとスケルトンが利用できなくなります。
もちろん、ペンライトをキャラクターモデルの一部にするのも解決策の一つですが、この方法だとモデル作りの手間が増え、柔軟性が損なわれるのが欠点になります。
実は、このシナリオのために、AnimToTextueプラグインが「Attach to Socket」という機能が提供されています。これにより、VATでもスケルトンのAttachと似たような効果が実現できます。
4.1 メッシュのPivot Pointを編集する
この方法を利用するには前提条件があります。それは、「持ち物」と「キャラクター」のPivot Point(原点)位置は同じであることです。
したがって、VATをベークする前に、ペンライトメッシュのPivot Pointを編集する必要があります。同じ理由で、ベーク後は、ペンライトとキャラクターの相対位置の回転やスケールの変更ができません。
まずは、Skeletal Meshでペンライトの持つ位置を定めます。
ペンライトのアセットをコピーして、Mannequinとペンライトをレベルに配置します。
そして、Viewport左上のSnap Optionで、Socketオプションを有効にしたら、キャラクターの手のSocketが表示されます。


UE Mannequinの手には既にHandGripというSocketがありますが、Socketがないモデルは新しく作成する必要があります。
ペンライトを選択し、Shiftを押しながらSocketをクリックします。これでペンライトがキャラクターの子Actorになります。
TransformをResetすると、ペンライトが手に付いていることが確認できます。ここで私はペンライトを45度回転して見た目調整もしました。
ペンライトの位置を整えたら、キャラクターとペンライトの親子関係を解除します。そして、今のキャラクターの位置と回転を記録しておきます。


キャラクター現在のPivot Pointをメモし、ペンライトのPivot Pointも同じ位置に変更します
Editor左上からModeling Modeに入ります。
Modeling Modeで、XForm(Transform)メニューをクリックし、Edit Pivot機能を選択します。
ここで先のキャラクラーの位置と回転を入力したら、ペンライトとキャラクターのPivot Pointを一緒にすることができます。
Acceptをクリックし、Modeling Modeを終了します。
4.2 マテリアル作成
メッシュの編集が終わったら、VATのマテリアルを作成します。この部分は前述のSkeletal Meshの手順と同じなので、詳細は省略します。先で述べたNaniteバグのため、修正したMF_BoneAnimation_Customを使用するよう注意しましょう。

すべてのマテリアルにVATのMaterial Functionを追加し、Material Instanceも用意します
ペンライトの相対位置によってVATテクスチャの情報も異なるので、ペンライトの回転などを変更したい際、既存のマテリアルを上書きしたくないのであれば、別のMaterial Instanceを作成する必要があります。(画像の例は45度回転したモデル用のMIなので、名前にR45を付けています。)
4.3 Attach to Socket
AnimToTextureのData Assetで、Static Meshをスケルトンのアニメーションにつけるように設定します。
上のSkeletal Meshと下のAnim Sequenceの部分は前で使用したキャラクターのままにします。Static MeshでPivot Pointが編集されたペンライトのメッシュを選択します。3つのテクスチャも新しく作成します。
そして、「Attach to Socket」の設定で左手のボーンネーム(Mannequinの場合はhand_l)を入力します。これでVATをBakeしたら、ペンライトがこのボーンの位置に基づいて動くようになるはずです。
ここで注意すべきのは、この設定はAttach to Socketと名乗っているのに、実際にはスケルトンのBoneにしかつけられず、Socketは使用できません。UE Mannequinは手の部分のSocketとBoneが同じ位置にあるのでそのまま問題なく使えますが、他のモデルを使用する際にズレるかもしれません。
EUBPを使ってData Assetを実行し、ペンライトをキャラクターと同じWorld Transformで配置したら、2つのメッシュの動きが同期され、ペンライトが握られているようなの効果を確認できます。


一緒に動いていますが、実際は独立した2つのメッシュのままです
5 完成効果&問題点
これでVATに関する作業が完了しました。VATの活用により、RuntimeでのBP・C++・Animation Blueprint実行と、アニメーションアセットの読み込みが一切不要な方式でキャラクターと持ち物を動かすことができます。Static Meshでも動ける特性があるため、Instanced Actorと組み合わせて、CPUの処理コストを大きく軽減しながら賑やかな観客を表現できます。
Part 1で作成した観客Actorの通常のメッシュをVAT化したのStatic Meshに置き換え、PCGで会場を生成すると、全会場の観客が一斉にペンライトを振る効果が得られます。
現時点の問題・バグについては、メッシュ間の遮蔽が多い時、動いている手の部分が消えてしまう、という現象があります。
最も顕著なケースは、カメラを低い位置でに置いて観客に向けて撮影する時です。一方、上から見下す際は、メッシュ間の重なりが少ないため、ほぼ問題がありません。メッシュのBounding Boxの調整を試してみると、少し改善がありましたが、完全解決の方法はまだ見つかっていません。
6 おわりに
今回はVATとUnreal EngineのAnimToTextureプラグインを紹介し、それらを利用して動くStatic Meshを作成しました。これによりInstanced Actorの最大の制限を乗り越えて、大量の観客を軽く制御することができます。
Part 3では、観客Actorでスケルトン制御とVATを切り替える仕組みを実装します。また、インパクトのある演出を作るため、単なる色ではなく、物理的な照明効果のあるライティングの実装とMegaLightsを用いた最適化方法を紹介したいと思います。





























































