コンピュートシェーダーは、通常のレンダリングパイプラインとは異なって、グラフィックスカード上で実行するプログラムです。これは超並列 GPGPU アルゴリズム、またはゲームレンダリングの一部を加速させるために使用できます。効果的に使用するためには、しばしば GPU アーキテクチャおよび並列アルゴリズム、さらには DirectCompute、OpenGL Compute、CUDA、OpenCL に関する深い知識が必要です。
Unity のコンピュートシェーダーは、DirectX 11 DirectCompute テクノロジーと良く似ています。コンピュートシェーダーが使用できるプラットフォームは以下の通りです。
DirectX 11 または DirectX 12 グラフィックス API と Shader Model 5.0 GPU を伴う Windows と Windows ストア
Metal グラフィックス API を使用する macOS と iOS
Vulkan API を伴う Android、Linux、Windows プラットフォーム
現段階で一般的に使用されている OpenGL プラットフォーム (Linux または Windows の OpenGL 4.3、Android の OpenGL ES 3.1)。Mac OS X は OpenGL 4.3 をサポートしません。
現段階で一般的に使用されている多くのコンソール (Sony PS4、Microsoft Xbox One)
コンピュートシェーダーのサポートの有無はランタイムに SystemInfo.supportsComputeShaders を使って確認できます。
通常のシェーダー と同様に、コンピュートシェーダーは、プロジェクトのアセットファイルで .compute ファイル拡張子を持ちます。これらは DirectX 11 スタイルの HLSL 言語で書かれ、最低数の #pragma コンパイラーディレクティブを持ち、コンピュートシェーダーカーネルとしてどの関数をコンパイルするかを示します。
こちらは、コンピュートシェーダーファイルの基本例です。出力テクスチャを赤で塗りつぶします。
// test.compute
#pragma kernel FillWithRed
RWTexture2D<float4> res;
[numthreads(1,1,1)]
void FillWithRed (uint3 dtid : SV_DispatchThreadID)
{
res[dtid.xy] = float4(1,0,0,1);
}
言語は標準の DX11 HLSL で、#pragma kernel FillWithRed
ディレクティブが追加されています。1つのコンピュートシェーダーアセットファイルには、呼び出し可能な1つ以上の コンピュートカーネル
が含まれていなければなりません。そして、その関数は #pragma ディレクティブ
で示されます。 ファイルにはそのほかのカーネルが存在する可能性があります。その場合は、単に 複数の #pragma kernel
を追加するだけです。
複数の#pragma kernel
を使用する場合は、#pragma kernel
ディレクティブと同じ行に//
のコメントは許可されていないことに注意してください。使用すると、コンパイルエラーの原因となります。
#pragma kernel
行はオプションとして、カーネルをコンパイルしている間に複数のプリプロセッサーマクロを後に続けて定義することが可能です。サンプルとしては、
# pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337
# pragma kernel KernelTwo OTHER_DEFINE
// ...
スクリプトで ComputeShader 型の変数を定義し、アセットへの参照を割り当てます。こうすると ComputeShader.Dispatch 関数を使用してそれらを呼び出すことができます。 詳細は、ComputeShader class を参照してください。
ComputeBuffer クラスはコンピュートシェーダーと密接に関係し、任意のデータバッファ (DX11 用語の 「構造化バッファー」) を定義します。レンダーテクスチャ は、「ランダムアクセス」フラグが設定されている場合 (DX11 の「unordered access view」)、コンピュートシェーダーからの書き込みも可能です。 詳細については、RenderTexture.enableRandomWrite を参照してください。
テクスチャとサンプラーは、Unity では別々のオブジェクトではありません。そのため、コンピュートシェーダでそれらを使用するには、以下の Unity 特有のルールに従う必要があります。
テクスチャ名と同じ名前を使用し、最初にsampler
と表記します (たとえば、Texture2D MyTex
; SamplerState samplerMyTex
)。 この場合、サンプラーはテクスチャの filter/wrap/aniso 設定に初期化されます。
あらかじめ定義されたサンプラーを使用してください。 このため、名前にはLinear
または Point
(フィルタモード用) と、Clamp
または Repeat
(ラップモード用) が必要です。 たとえば、SamplerState MyLinearClampSampler
は、リニアフィルターモードとクランプラップモードを持つサンプラーを作成します。
詳細は、サンプラー状態 を参照してください。
通常のシェーダと同様に、Unity はコンピュートシェーダーを HLSL から他のシェーダー言語に 変換 することができます。したがって、最も簡単なクロスプラットフォームビルドのために、HLSL にコンピュートシェーダーを記述します。ただし、これを行う際に考慮が必要な要因がいくつかあります。
DirectX 11 (DX11) は、他のプラットフォーム (Metal や OpenGL ES など) ではサポートされていない多くの操作をサポートしています。 したがって、DX11 だけの環境を考えるより、サポートが少ないプラットフォームで、シェーダーの挙動を明確に定義する必要があります。 考慮すべき点は以下のとおりです。
アウトオブバンドのメモリアクセスが悪い点。DX11 は、読み込み時に常にゼロを返し、問題なくデータの一部を読み込むかもしれませんが、サポートが少ないプラットフォームでは、これを行う際に GPU がクラッシュする可能性があります。DX11 特有のハック、スレッドグループサイズの倍数と一致しないバッファーサイズ、バッファーの先頭や末尾から隣接するデータ要素を読み取ろうとすること、などの同様の非互換性に注意してください。
リソースを初期化する点。 新しいバッファーとテクスチャの内容は未定義です。 プラットフォームの中にはすべてゼロを示すものもありますが、そうでないものでは、NaN を含めどんな値になることもありえます。
コンピュートシェーダーが宣言するすべてのリソースをバインドします。シェーダーが分岐のために現在の状態でリソースを使用しないことが確実にわかっていても、リソースがバインドされていることを確認する必要があります。
Metal (iOS と tvOS プラットフォーム用) は、テクスチャのアトミック操作をサポートしません。Metal は、バッファーの GetDimensions
クエリもサポートしません。必要な場合は、バッファーサイズの情報を定数としてシェーダーに渡します。
OpenGL ES 3.1 (Android, iOS, tvOS プラットフォーム用) は、一度に 4 つのコンピュートバッファーしかサポートしません。実際の実装では、より多くをサポートすることもありますが、一般的には OpenGL ES 用に開発する場合は、それぞれのバッファーに各データを格納するよりも、関連するデータを構造体でグループ化することを検討する必要があります。
通常、コンピュートシェーダーファイルは HLSL で記述され、自動的に、必要なすべてのプラットフォームにコンパイルまたは変換されます。ただし、他の言語への変換を避けたり (つまり、HLSL プラットフォームのみを維持する)、GLSL コンピュートコードを記述することも可能です。
以下の情報は、HLSL 専用、または、GLSL 専用のコンピュートシェーダーにのみ適用され、クロスプラットフォームビルドには適用されません。これは、この情報によってコンピュートシェーダーソースが一部のプラットフォームから除外される可能性があるためです。
CGPROGRAM
キーワードと ENDCG
キーワードで囲まれたコンピュートシェーダーソースは、非 HLSL プラットフォームでは処理されません。
GLSLPROGRAM
キーワードと ENDGLSL
キーワードで囲まれたコンピュートシェーダーソースは、GLSL ソースとして扱われ、そのまま出力されます。これは、OpenGL または GLSL プラットフォームをターゲットとする場合にのみ機能します。また、自動的に変換されたシェーダーはバッファーの HLSL データレイアウトに従いますが、記述された GLSL シェーダーは GLSL レイアウトルールに従うということにも注意する必要があります。
2017–05–18 Page amended
5.6 に以下を追加: SystemInfo.supportsComputeShaders, platforms macOS, iOS (using Metal), Android, Linux, Windows (with Vulkan)