GPU インスタンシングは、CPU レンダリングと比較して著しくパフォーマンスを向上させます。パーティクルシステムで、デフォルトの レンダリングモード の ビルボード パーティクルではなく、メッシュ パーティクルをレンダリングしたい場合に使用できます。
パーティクルシステムで GPU インスタンシングを使用できるようにするには、以下の手順を行います。
パーティクルシステムの Render Mode を Mesh に設定します。
GPU インスタンシングをサポートする Renderer の Material のシェーダーを使用します。
GPU インスタンシングをサポートするプラットフォームでプロジェクトを実行します
パーティクルシステムの GPU インスタンシングを使用可能するには、パーティクルシステムの Renderer モジュールの Enable GPU Instancing チェックボックスにチェックを入れる必要があります。
Unity には、GPU インスタンシングをサポートするビルトインのパーティクルシェーダーがありますが、デフォルトのパーティクルマテリアルはそれを使用しません。そのため、GPU インスタンシングを使用するには、これを変更する必要があります。GPU インスタンシングをサポートするパーティクルシェーダーは Particles/Standard Surface と呼ばれます。これを使用するには、独自の マテリアル を作成し、マテリアルのシェーダーを Particles/Standard Surface に設定します。次に、この新しいマテリアルをパーティクルシステムの Renderer モジュールの Material フィールドに割り当てます。
パーティクルに異なるシェーダーを使用する場合は、 ‘#pragma target 4.5’ 以上を使用する必要があります。詳細は、シェーダーコンパイルターゲットレベル を参照してください。この要件は Unity の通常の GPU インスタンシングよりも高くなります。なぜなら、パーティクルシステムは複数のドローコールにインスタンシングを分割するのではなく、すべてのインスタンスデータを 1 つの大きなバッファに書き込むからです。
GPU インスタンシングを使用するカスタムシェーダーも作成できます。詳細は、以下のセクションを参照してください。
以下は、パーティクルシステム GPU インスタンシングを使用したサーフェスシェーダーの完全な使用例です。
Shader "Instanced/ParticleMeshesSurface" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// 物理計算に基づいた標準のライティングもです。すべてのライトタイプに影を作ることが可能。
// インスタンシングサポートでシャドウパスを作ります
#pragma surface surf Standard nolightmap nometa noforwardadd keepalpha fullforwardshadows addshadow vertex:vert
// このシェーダーのインスタンシングを可能にします
#pragma multi_compile_instancing
#pragma instancing_options procedural:vertInstancingSetup
#pragma exclude_renderers gles
#include "UnityStandardParticleInstancing.cginc"
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
fixed4 vertexColor;
};
fixed4 _Color;
half _Glossiness;
half _Metallic;
void vert (inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input, o);
vertInstancingColor(o.vertexColor);
vertInstancingUVs(v.texcoord, o.uv_MainTex);
}
void surf (Input IN, inout SurfaceOutputStandard o) {
// 着色されるテクスチャのアルベド
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * IN.vertexColor * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
上記の例には、通常の サーフェスシェーダー と比べいくつかの小さな違いがあり、それによってパーティクルのインスタンス化と共に使用可能になります。
まず、手続き型のインスタンシングを使用可能にするために以下の 2 行を追加し、ビルトインの頂点設定の関数を指定する必要があります。この関数は UnityStandardParticleInstancing.cginc にあり、インスタンスごとの (パーティクルごとの) 位置データをロードします。
#pragma instancing_options procedural:vertInstancingSetup
#include "UnityStandardParticleInstancing.cginc"
この例のもう 1 つの変更は Vertex 関数 に行われています。 Vertex 関数に 2 行が加えられ、インスタンスごとの属性を適用します。具体的には、パーティクルの色と テクスチャシートアニメーション テクスチャの座標です。
vertInstancingColor(o.vertexColor);
vertInstancingUVs(v.texcoord, o.uv_MainTex);
以下は、パーティクルシステムの GPU インスタンシングを使用したカスタムシェーダーの完全な使用例です。このカスタムシェーダーは、標準のパーティクルシェーダーにはない機能である テクスチャシートアニメーション の個々のフレーム間のフェード、が可能になります。
Shader "Instanced/ParticleMeshesCustom"
{
Properties
{
_MainTex("Albedo", 2D) = "white" {}
[Toggle(_TSANIM_BLENDING)] _TSAnimBlending("Texture Sheet Animation Blending", Int) = 0
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile __ _TSANIM_BLENDING
#pragma multi_compile_instancing
#pragma instancing_options procedural:vertInstancingSetup
#include "UnityCG.cginc"
#include "UnityStandardParticleInstancing.cginc"
struct appdata
{
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
# ifdef _TSANIM_BLENDING
float3 texcoord2AndBlend : TEXCOORD1;
# endif
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 readTexture(sampler2D tex, v2f IN)
{
fixed4 color = tex2D(tex, IN.texcoord);
# ifdef _TSANIM_BLENDING
fixed4 color2 = tex2D(tex, IN.texcoord2AndBlend.xy);
color = lerp(color, color2, IN.texcoord2AndBlend.z);
# endif
return color;
}
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
o.color = v.color;
o.texcoord = v.texcoord;
vertInstancingColor(o.color);
# ifdef _TSANIM_BLENDING
vertInstancingUVs(v.texcoord, o.texcoord, o.texcoord2AndBlend);
# else
vertInstancingUVs(v.texcoord, o.texcoord);
# endif
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
half4 albedo = readTexture(_MainTex, i);
return i.color * albedo;
}
ENDCG
}
}
}
この例には、位置データをロードするためにサーフェスシェーダーと同じ設定コードが含まれています。
#pragma instancing_options procedural:vertInstancingSetup
#include "UnityStandardParticleInstancing.cginc"
頂点関数の変更はサーフェスシェーダーと非常によく似ています。
vertInstancingColor(o.color);
# ifdef _TSANIM_BLENDING
vertInstancingUVs(v.texcoord, o.texcoord, o.texcoord2AndBlend);
# else
vertInstancingUVs(v.texcoord, o.texcoord);
# endif
前出の最初の例と比較してここでの唯一の違いは、テクスチャシートアニメーションのブレンディングです。つまり、テクスチャシートアニメーションの 2 つのフレーム (1 つではなく) を読み込みブレンドするために、シェーダーに余分なテクスチャ座標のセットが必要だということです。
最後に、フラグメントシェーダーはテクスチャを読み込み、最終的な色を計算します。
前出の例では、パーティクルのデフォルトの頂点ストリーム設定のみを使用しています。これには、位置、法線、色、1 つの UV が含まれます。ただし、カスタム頂点ストリーム を使用することによって、速度、回転、サイズなど、他のデータをシェーダーに送信できます。
次の例では、シェーダーは特別な効果を示するように設計されています。より速いパーティクルをより明るく表示し、遅いパーティクルをより暗くします。速度の頂点ストリームを使用して、速度に応じてパーティクルを明るくするコードが加えられています。また、このシェーダーはテクスチャシートアニメーションを使用しない効果を想定しているため、テクスチャシートアニメーションはカスタムストリーム構造体からは削除されています。
以下は、完全なシェーダーです。
Shader "Instanced/ParticleMeshesCustomStreams"
{
Properties
{
_MainTex("Albedo", 2D) = "white" {}
}
SubShader
{
Tags{ "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
# pragma exclude_renderers gles
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#pragma instancing_options procedural:vertInstancingSetup
#define UNITY_PARTICLE_INSTANCE_DATA MyParticleInstanceData
#define UNITY_PARTICLE_INSTANCE_DATA_NO_ANIM_FRAME
struct MyParticleInstanceData
{
float3x4 transform;
uint color;
float speed;
};
#include "UnityCG.cginc"
#include "UnityStandardParticleInstancing.cginc"
struct appdata
{
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
o.color = v.color;
o.texcoord = v.texcoord;
vertInstancingColor(o.color);
vertInstancingUVs(v.texcoord, o.texcoord);
# if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID];
o.color.rgb += data.speed;
# endif
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
half4 albedo = tex2D(_MainTex, i.texcoord);
return i.color * albedo;
}
ENDCG
}
}
}
シェーダーは UnityStandardParticleInstancing.cginc
を含み、カスタム頂点ストリームが使用されていないときのデフォルトのインスタンシングデータレイアウトを含んでいます。そのため、カスタムストリームを使用する場合は、そのヘッダーで定義されているデフォルトのいくつかをオーバーライドする必要があります。これらのオーバーライドは include の 前 に置く必要があります。上の例では、以下のカスタムオーバーライドを設定しています。
最初に、UNITY_PARTICLE_INSTANCE_DATA マクロを使用して、カスタムストリームデータのための ‘MyParticleInstanceData’ というカスタム構造体を使用するよう指示しています。
#define UNITY_PARTICLE_INSTANCE_DATA MyParticleInstanceData
次に、もう 1 つの定義で、Anim Frame Stream (アニメーションフレームストリーム) がこのシェーダーで必要でないことをインスタンシングシステムに伝えています。なぜなら、この例の効果はテクスチャシートアニメーションでの使用を意図していないためです。
#define UNITY_PARTICLE_INSTANCE_DATA_NO_ANIM_FRAME
第 3 に、カスタムストリームデータの構造体が宣言されます。
struct MyParticleInstanceData
{
float3x4 transform;
uint color;
float speed;
};
これらのオーバーライドはすべて UnityStandardParticleInstancing.cginc
が含まれる前に置かれるため、シェーダーはこれらの定義にシェーダー自体のデフォルトを使用しません。
構造体を記述するとき、変数はパーティクルシステムの Renderer モジュールのインスペクターに列挙される頂点ストリームと一致する必要があります。つまり、Renderer モジュールの UI で使用したいストリームを選択し、それらをカスタムストリームデータ構造体の変数定義に同じ順序で加える必要があります。そのため、それらは一致します。
最初の項目 (Position) は必須なので、削除することはできません。プラス (+) とマイナス (-) のボタンを使って他のエントリーを自由に追加/削除することができ、頂点ストリームデータをカスタマイズできます。
リスト内で INSTANCED と示されるエントリーにはインスタンスデータが含まれているため、パーティクルインスタンスのデータ構造体に加える必要があります。INSTANCED という語のすぐ後に加えられた数字 (例えば、INSTANCED0 の 0 と INSTANCED1 の 1) は、最初の “transform” 変数の 後 に、変数を構造体に置く順番を示します。末尾の文字 (.x .xy .xyz .xyzw) は、変数の型を示し、シェーダーコードの float、float2、float3、float4 変数の型に対応します。
リストに表示されていて、INSTANCED と 示されていない 他の頂点ストリームデータは、パーティクルインスタンスのデータ構造体から削除できます。なぜなら、それらは、シェーダーによって処理されるインスタンス化されたデータではないからです。このようなデータは、UV、法線、接線などのソースメッシュに属しています。
例を完成させる最後の手順は、頂点シェーダー内のパーティクルの色に速度を適用することです。
# if defined(UNITY_PARTICLE_INSTANCING_ENABLED)
UNITY_PARTICLE_INSTANCE_DATA data = unity_ParticleInstanceData[unity_InstanceID];
o.color.rgb += data.speed;
# endif
すべてのインスタンシングコードを UNITY_PARTICLE_INSTANCING_ENABLED のチェック内にラップする必要があります。そのようにすると、インスタンス化が使用されていないときにもコンパイルできます。
この時点で、フラグメントシェーダーにデータを渡したい場合は、他のシェーダーデータの場合と同様に、v2f 構造体にデータを書き込むことができます。
この例では、カスタムの頂点ストリームで使用するカスタムシェーダーを変更する方法について説明しますが、サーフェスシェーダーにも全く同じアプローチで同じ機能を実現できます。
2018–03–28 公開ページ
パーティクルシステム GPU インスタンシングは Unity 2018.1 で追加NewIn20181
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.