ShaderTips

シェーダーTips

主にUnityシェーダーについての記事を書いています。

【Unity】Compute Shaderの基礎

ComputeShaderとは

GPUで実行するプログラムです 画像処理、ポストエフェクト、物理シミュレーション、アニメーション、水面シミュレーション 、パーティクル演算などCPUよりもGPUの並列計算を使用したい時に使われます。

カーネル

カーネルとは、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);

参考

edom18.hateblo.jp

edom18.hateblo.jp

shitakami.hatenablog.com