なおしのこれまで、これから

学んだこと・感じたこと・やりたいこと

VAT(Vertex Animation Texture)を使用してシェーダーでアニメーションをさせる

f:id:vxd-naoshi-19961205-maro:20200917214605g:plain

始めに

野球ゲームの観客だったり、最近ではVtuberのライブの観客だったりで多くのNPCを表示させてかつアニメーションもさせています。

どうやれば実装できるかと思っているとき、VAT(Vertex Animation Texture)という技術を知りました。

このVATを使うことでUnityのAnimatorよりも軽量にアニメーションをさせることが出来ます。

ということで、今回はVATについてまとめていこうと思います。



VAT(Vertex Animation Texture)

Vertex Animation Textureとはモデルの頂点座標や回転の情報が書き込まれたテクスチャを指します。このテクスチャを使用することでモデルにアニメーションをさせることが出来ます。

Houdiniの記事にはなりますが、こちらが参考になりました。

houdinifx.jp



Animation Texture Baker

今回は0から作るのではなくgithubにあるプロジェクト「Animation Texture Baker」を使ってVATをしていこうと思います。

github.com



シェーダーでアニメーションをさせるまでの手順

先ほどのgithubプロジェクトを使っていきます。


モデルの準備

モデルは Assets/Horse/Model/Horse を使用します。 HorseをHierarchyに追加します。

f:id:vxd-naoshi-19961205-maro:20200917212347p:plain



コンポーネントの設定

次にHorse用の AnimatorController を作成して、Horseに元からあるAnimatorコンポーネントのControllerに設定します。作成したAnimatorControllerは何も設定しなくて大丈夫です。

f:id:vxd-naoshi-19961205-maro:20200917212901p:plain



次に Animation Clip Texture Bakerコンポーネントを追加して Assets/AnimationBaker/Shaders に入っている Info Tex GenにMeshInfoTextureGen.computeを、Play Shaderに2つのshaderファイルのどちらかを設定します。

Clipsには実行したいアニメーションを追加していきます。今回は Assets/Horse/Animation にあるHorse_Idle、Horse_Run、Horse_Walkを追加します。

f:id:vxd-naoshi-19961205-maro:20200917213629p:plain

VATの作成

Animation Clip Texture Bakerを右クリックするとメニューの一番下にbake textureがあります。 こちらを選択することでVATとVATを使用したPrefabが生成されます。

f:id:vxd-naoshi-19961205-maro:20200917213954p:plain

f:id:vxd-naoshi-19961205-maro:20200917214605g:plain

また、作成されたPrefabファイルは Assets/BakedAnimationTex に保存されています。



AssetStoreにあるモデルで試す

次にこちらのゾンビのモデルで試してみます。 手順は先ほどと同じです。

assetstore.unity.com


結果はモデルがx軸に-90度回転したものが出来てしまいました。

f:id:vxd-naoshi-19961205-maro:20200917215250p:plain



続いて次のロボットのモデルで試してみます。 RobotのRigをHumanoidに設定して同様の手順を行います。

assetstore.unity.com

assetstore.unity.com


先ほどとは異なり、回転があっていました。

f:id:vxd-naoshi-19961205-maro:20200917220901g:plain



回転オフセットを追加する

いくつか試している際にモデルの回転があっていない現象がたびたびありました。

なのでVATを作成する際に回転のオフセットを設定できるよう改良してみました。


やっていることは単純で頂点座標テクスチャの値に回転行列をかける処理を追加しただけです。

// AnimationClipTextureBaker.csの91行目
 infoTexGen.SetInt("VertCount", vCount);

infoTexGen.SetFloat("AngleOffsetX", angleOffset.x);
infoTexGen.SetFloat("AngleOffsetY", angleOffset.y);
infoTexGen.SetFloat("AngleOffsetZ", angleOffset.z);
            
infoTexGen.SetBuffer(kernel, "Info", buffer);
infoTexGen.SetTexture(kernel, "OutPosition", pRt);
infoTexGen.SetTexture(kernel, "OutNormal", nRt);
infoTexGen.SetTexture(kernel, "OutTangent", tRt);


// MeshInfoTextureGen.computeの17行目
float AngleOffsetX;
float AngleOffsetY;
float AngleOffsetZ;

#define Deg2Rad 0.0174532924
float4x4 eulerAnglesToRottationMatrix(float3 angles) {

    float cx = cos(angles.x * Deg2Rad); float sx = sin(angles.x * Deg2Rad);
    float cy = cos(angles.z * Deg2Rad); float sy = sin(angles.z * Deg2Rad);
    float cz = cos(angles.y * Deg2Rad); float sz = sin(angles.y * Deg2Rad);

    return float4x4(
        cz*cy + sz*sx*sy, -cz*sy + sz*sx*cy, sz*cx, 0,
        sy*cx, cy*cx, -sx, 0,
        -sz*cy + cz*sx*sy, sy*sz + cz*sx*cy, cz*cx, 0,
        0, 0, 0, 1);

}

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    int index = id.y * VertCount + id.x;
    MeshInfo info = Info[index];

    // OutPosition[id.xy] = float4(info.position, 1.0);
    float3 angle = float3(AngleOffsetX, AngleOffsetY, AngleOffsetZ);
    float4 position = mul(eulerAnglesToRottationMatrix(angle), float4(info.position, 1.0));
    OutPosition[id.xy] = position;
    OutNormal[id.xy] = float4(info.normal, 1.0);
    OutTangent[id.xy] = float4(info.tangent, 1.0);
}



結果、インスペクターから回転を指定することで作成されるPrefabの回転を合わせることが出来ました。

f:id:vxd-naoshi-19961205-maro:20200917223853p:plain

f:id:vxd-naoshi-19961205-maro:20200917223836p:plain



有効なモデルについて

いくつか試してみてSkinnedMeshRendererを使用しているモデルのみ有効のようです。

例えば、次のRobot SphereではSkinnedMeshRendererを使用していないためVATを作成するのは出来ませんでした。

assetstore.unity.com


また、VATの作成では1つのSkinnedMeshRendererを使用して1つのテクスチャを作成しているため複数のSkinnedMeshRendererが付いたモデルではその数分のVATを作成しなくてはいけません。

以下のアセットでは2つのSkinnedMeshRendererを使用しているので2つVATを作成して同じ座標に置くことで上手くいきました。

assetstore.unity.com

f:id:vxd-naoshi-19961205-maro:20200917233516g:plain


1つのSkinnedMeshRendererを使用しているモデルについては問題なくVATを作成することが出来ました。

Mini Legion Rock Golem PBR HP Polyart | Characters | Unity Asset Store

f:id:vxd-naoshi-19961205-maro:20200917225727g:plain



感想

VATによってCPU負荷を減らしてアニメーションを行うことが出来ました。

VATだけでの検証でしたが、これからGPUインスタンシングと組み合わせてみようと思います。

参考

こちらの記事とUnity Graphics Programming vol.3 を参考にしています。 また、Unity Graphics Programming vol.3では詳しい解説が載っているので知りたい方は拝見してください。

tsubakit1.hateblo.jp

github.com