【Unity】Compute Shaderの基礎
ComputeShaderとは
GPUで実行するプログラムです 画像処理、ポストエフェクト、物理シミュレーション、アニメーション、水面シミュレーション 、パーティクル演算などCPUよりもGPUの並列計算を使用したい時に使われます。
カーネル
#pragma kernel CSMain
#pragma kernel
の後にCSMainという関数名を指定しています。
スレッド
スレッドとは、カーネルを実行する単位で、1スレッドが1カーネルを実行します。コンピュートシェーダーではカーネルを複数のスレッドで並行して同時に実行することができます。
[numthreads(10,8,3)] void CSMain () { }
スレッド数はカーネルの上に[numthreads(X,Y,Z)]
と定義します。
X * Y * Zのスレッドが生成されます。
今回の例では10 * 8 * 3 = 240スレッド生成されます。
スレッドグループ
スレッドグループとは、スレッドを実行する単位で、1スレッドグループで、指定したスレッド数のカーネルを実行します。
int kernelIndex = shader.FindKernel("CSMain"); shader.Dispatch(kernelIndex, 5, 3, 2);
スレッドグループはコンピュートシェーダーを実行する
shader.Dispatch
の引数で指定します。
第一引数はshader.FindKernel
で取得したカーネルのインデックスを指定します。
残りの引数で、スレッドグループ数を指定します。 スレッド数と同じように、5 * 3 * 2 = 30グループとなります。
これは[numthreads(10,8,3)]
(下の図)で合計240スレッドが指定されたカーネルをDispatch(5,3,2)
(上の図)で合計30グループのスレッドグループからなるスレッド群を実行している図です。(つまり合計7,200スレッド)
セマンティクス
カーネルの引数にはセマンティクスを指定できます。 上の画像を見ながら、読んでください。
SV_GroupThreadID
実行しているグループ内でのスレッドIDです。
SV_GroupID
実行しているスレッドグループのIDです。
SV_DispatchThreadID
実行しているスレッドが、どのスレッドグループのどのスレッドかを識別できるIDで、以下の式によって求められます。
SV_GroupID * numthreads + SV_GroupThreadID
SV_GroupID * numthreadsで、実行しているスレッドグループまでの合計スレッド数を求め、+ SV_GroupThreadIDで実行しているスレッドIDを加算しています。
SV_GroupIndex
SV_GroupThreadIDを数値を一つにして返します。
Compute Shaderに値を渡す
Compute Shaderで、変数を定義
float hoge;
スクリプトから、値を渡す
shader.SetFloat("hoge", 1.0f);
ComputeShaderにバッファを渡す
Compute Shaderで、バッファを定義
RW
がついている型は読み書きが可能な変数です。
ついていない型は読み込みのみです。
struct Data
{
float3 position;
floar3 rotation;
};
RWStructuredBuffer<Data> Result;
スクリプトから、バッファを渡す
public struct Data { public Vector3 Position; public Vector3 Rotation; } Data[] dataList = new Data[100]; // dataListに値を入れる //GraphicsBuffer作成 GraphicsBuffer buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured,dataList.Length, sizeof(Data))); // GraphicsBufferにデータを設定 buffer.SetData(dataList); // ComputeShaderにバッファを渡す shader.SetBuffer(kernelIndex, "dataList", buffer);
ComputeShaderからバッファを受け取る
スクリプトで、GraphicsBufferのGetData
を使えば簡単に取得できます。
buffer.GetData(dataList);