Posted at

UNITY DrawCall調査 particles GPU Instancing ~ UNITY2018.3.6f1 ~

前回に続き、DrawCall削減で、ParticleのGPU Instancing関連を調査


ParticleSystem


Billboard

通常Particleを表示させると下記のようになる

SnapCrab_NoName_2019-3-5_2-45-18_No-00.png

SnapCrab_NoName_2019-3-5_2-45-34_No-00.png

DynamicBatchingが効いてちゃんと効率化されてます

ParticleSystemのRenderingを見てみましょう。

RenderModeがBillboardですね。BillboardではGPU Instancingは使えないが

DynamicBatchingでいいようにしてくれます


mesh

GPU Instancingを使うにはmeshにします

meshにすると、メッシュをパーティクルとして飛ばせます

デフォルトで Default-ParticleSystemというメッシュが付いています

そしてそのシェーダーはGPU Instancing対応しています

SnapCrab_NoName_2019-3-5_2-53-27_No-00.png

GPU Instancing無し

SnapCrab_NoName_2019-3-5_2-56-36_No-00.png

DynamicBatchingは効いてるが、GPU Instancingはありません

GPU Instancingあり

SnapCrab_NoName_2019-3-5_2-54-46_No-00.png

GPU Instancing効いてます


自作のマテリアルをつける

Shader "Instancing2"

{
SubShader
{
Tags { "RenderType" = "Opaque" "DisableBatching" = "True"}

Pass
{
Tags { "LightMode" = "ForwardBase" }

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#pragma multi_compile_instancing
#pragma instancing_options procedural:vertInstancingSetup

#include "UnityCG.cginc"
#include "UnityStandardParticleInstancing.cginc"

struct appdata
{
float4 vertex : POSITION;
float4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct v2f
{
float4 color : TEXCOORD1;
float4 vertex : SV_POSITION;
};

v2f vert(appdata v)
{
UNITY_SETUP_INSTANCE_ID(v);

v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.color = i.color;

return o;
}

fixed4 frag(v2f i) : SV_Target
{
return i.color;
}

ENDCG
}
}
}

前回とほぼ同じだが、

#pragma instancing_options procedural:vertInstancingSetup

がないとちゃんと動かなかった。基本的にGPU Instancingを行う時は上記オプションをつけたほうがよさそうだ

また、Colorプロパティーに関するものは今回無いので削除した

SnapCrab_NoName_2019-3-5_3-10-30_No-00.png

ちゃんと効く


グラデーションをする

ParticleのパラメータでStartColorをグラデーションにしてみる

色が変わる=マテリアルが変わるので、普通に行うと色の数だけマテリアルが生成されると思うが


Default-ParticleSystem

SnapCrab_NoName_2019-3-5_3-15-15_No-00.png

グラデーションでパーティクルが表示されたが

DrawCallは GPU Instancingの有無にかかわらず単色の時と変わらない

何故だろうか?


自作メッシュ

メッシュを自作に変更する

GPU Instancing無しだとちゃんと表示されるが

有りにすると全部白いパーティクルになった

SnapCrab_NoName_2019-3-5_3-21-18_No-00.png

何かがおかしい

答えは、Instancingの仕組みにある

頂点属性や、プロパティーは INSTANCE_IDにより配列から値を取り出す

Positionは実は UnityObjectToClipPos の内部で計算されている

が、Colorはそのままなのでダメ

Colorの変換には vertInstancingColor という関数が用意されている

頂点シェーダーの Color代入部分を下記に変更

                o.color = v.color;

vertInstancingColor(o.color);

SnapCrab_NoName_2019-3-5_3-46-51_No-00.png

これで、パーティクルも GPU Instancingが正常に行われた

SnapCrab_NoName_2019-3-5_3-51-59_No-00.png

もちろん、前回の方法で、ShadowCasterもGPU Instancing化された


今回できなかったやつ

本当はこのあたりもちゃんと調査したかったけど

案件が炎上したので、火消しに戻るため参照で


パーティクルのカスタムデータ

頂点属性をカスタマイズすることが出来ます

https://docs.unity3d.com/jp/current/Manual/PartSysCustomDataModule.html


コンピュートシェーダでインスタンシングデータ作成

コンピュートシェーダでデータ作る

https://qiita.com/mao_/items/920bec69f44d5f5a9382


パーティクルのインスタンス事にプロパティ変更

マテリアル変数を UNITY_INSTANCING_BUFFER_START でブロック化し

インスタンス事に変数を与える方法は以前行ったが

これもパーティクルで行えるはずである