Unityのshader_feature_localやmulti_compile_localを正しく使おうというお話です。
Unity2020.3.15f2
グローバルキーワード・ローカルキーワード
Unityのシェーダでは、shader_featureやmulti_compileでディレクティブを記述することでバリアントを作ることができます。
これは便利な機能ですが、これらで定義できるキーワード(=グローバルキーワード)の合計数は1プロジェクト内で256個や384個(バージョンによる)といった制限があります(Unity2021.2までは / 後述)。
さらにUnityのビルトインシェーダがすでに使っているキーワードも多数あるので、実際はさらに少なくなります。
この制限への対策として、Unity2019からshader_feature_localとmulti_compile_localというディレクティブが登場しました。
これらを使うとシェーダキーワードを「ローカルキーワード」として定義できます。
ローカルキーワードは一つのシェーダに64個まで定義可能で、グローバルキーワードのように1プロジェクトにおける制限は存在しません。
特有の制限として、Shader.EnableKeyword()などのグローバルキーワードを操作するAPIではローカルキーワードを操作することができません。
使えるAPIと使えないAPIは以下の通りです。
API | 操作対象のキーワード |
---|---|
Shader.EnableKeyword() Shader.DisableKeyword() |
グローバルキーワードのみ ※ローカルキーワードは操作できない |
CommandBuffer.EnableShaderKeyword() CommandBuffer.DisableShaderKeyword() |
グローバルキーワードのみ ※ローカルキーワードは操作できない |
Material.EnableKeyword() Material.DisableKeyword() |
グローバルキーワード ローカルキーワード |
ComputeShader.EnableKeyword() ComputeShader.DisableKeyword() |
グローバルキーワード ローカルキーワード |
また、できる限りローカルキーワードを使うことでパフォーマンスの向上にもつながるようです。
You might see a change in performance when you start using local keywords, but the difference depends on how your Project is set up. The total number of local and global keywords per shader affects performance: in an ideal set-up, use more local keywords and fewer global keywords, to reduce the total keyword count per shader.
Unity - Manual: Declaring and using shader keywords in HLSL より
これらの仕様を踏まえて、基本的にグローバルな操作を行わないもの以外はローカルキーワードを使うべきです。
注意点
ローカルキーワードを使う上で、一点注意が必要そうな点がマニュアルに記載されていました。
If a Material has a local keyword enabled, and its shader changes to one that is no longer declared, Unity creates a new global keyword. Shader variants and keywords - Unity マニュアル より
つまり
- あるローカルキーワードをマテリアルに対して有効化する
- そのマテリアルのシェーダを変更する
- 2.のシェーダに1.のローカルキーワードが定義されていないと、それはグローバルキーワードとして扱われる
ということです。
普通に使っている分には問題にならなそうですが、仕様として覚えておいた方が良さそうです。
各シェーダステージ用suffixにも対応
シェーダバリアントが特定のシェーダステージでしか使われない場合にはディレクティブにfragmentやvertexといった接尾辞をつけることができます。
この機能はローカルディレクティブにも有効なので、以下のようにステージを指定したディレクティブを記述できます。
- shader_feature_local_vertex
- shader_feature_local_fragment
- multi_compile_local_vertex
- multi_compile_local_fragment
Unity2021.2からはシェーダキーワード上限数の制限が大幅に緩和
さてここまで現状のUnityの話をしてきましたが、現在ベータ版のUnity2021.2からはシェーダキーワードの上限数が大幅に増える予定です。
- グローバルキーワード: 4,294,967,294 個まで
- ローカルキーワード: 65,534個まで
実質無制限と言って良さそうです。
というわけでUnity2021.2以降を対象とする場合にはグローバルキーワードの個数問題を気にする必要はなさそうですが、
前述のパフォーマンスの話やコンパイル時間のことを考えると適切なディレクティブを記述するべきという方針は変わらないと思われます。