【Unity】ComputeShaderの使い方を紹介します!
ComputeShaderはGPGPU(General-Purpose computing on Graphics Processing Units)を実現するためのシェーダーです。 高負荷な物理演算やメッシュ変形などをGPUで並列計算することができます。 このページではUnityでのComputeShaderの実装方法をシンプルに解説します。
ComputeShaderの作成
プロジェクト上で右クリックから 作成 > シェーダー > コンピュートシェーダー でコンピュートシェーダーを作成します。
作成されたコンピュートシェーダーは以下の内容になります。
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}
コードの解説をします。
#pragma kernel CSMain
CSMain関数をカーネル(エントリーポイント)として宣言します。
宣言されたカーネルはスクリプトから呼び出せるようになります。
RWTexture2D<float4> Result;
RWTexture2DはRead/Write可能な2Dテクスチャです。
float4なのでxyzwが各色成分rgbaになります。
[numthreads(8,8,1)]
1つのスレッドグループで実行されるスレッドの数を定義します。
今回のケースはX方向が8でY方向が8の8x8サイズが1つのスレッドグループです。
void CSMain (uint3 id : SV_DispatchThreadID)
SV_DispatchThreadIDセマンティクスで定義されたuint3 idは3D座標になります。
今回のシェーダーでは2Dテクスチャーを利用しているのでid.xyはテクスチャーのXY座標になります。
Result[id.xy] = float4(...);
Resultテクスチャーのxy座標に計算結果を代入します。
スクリプトの作成
先程のコンピュートシェーダーをそのまま使えるようにスクリプトを実装します。
using UnityEngine;
public class TestScript : MonoBehaviour
{
[SerializeField]
private ComputeShader computeShader;
private RenderTexture renderTexture;
public void Start()
{
renderTexture = new RenderTexture(64, 64, 0, RenderTextureFormat.ARGB32);
renderTexture.enableRandomWrite = true;
int kernel = computeShader.FindKernel("CSMain");
computeShader.SetTexture(kernel, "Result", renderTexture);
computeShader.Dispatch(kernel, 8, 8, 1);
}
void OnGUI()
{
GUI.DrawTexture(new Rect(0, 0, 64, 64), renderTexture, ScaleMode.ScaleToFit, false);
}
}
コードの解説をします。
[SerializeField]
private ComputeShader computeShader;
コンピュートシェーダーをUnityエディターで設定できるようにSerializeField属性を付加します。
インスペクター上でコンピュートシェーダーを設定して下さい。
renderTexture = new RenderTexture(64, 64, 0, RenderTextureFormat.ARGB32);
renderTexture.enableRandomWrite = true;
レンダーテクスチャーを作成しコンピュートシェーダーからの書き込みを可能にするためにenableRandomWriteをtrueにして下さい。
int kernel = computeShader.FindKernel("CSMain");
computeShader.SetTexture(kernel, "Result", renderTexture);
computeShader.Dispatch(kernel, 8, 8, 1);
CSMain関数のカーネル番号を取得してSetTexture関数で出力先のレンダーテクスチャーを設定します。Dispatch関数で各方向のスレッドグループ数を指定してカーネルを呼び出します。今回は64x64のレンダーテクスチャーを[numthreads(8,8,1)]カーネルで使用するのでX方向のスレッドグループ数は8、Y方向のスレッドグループ数も8になります。
以下のようにスレッドグループ数を計算することもできます。
uint x, y, z;
computeShader.GetKernelThreadGroupSizes(kernel, out x, out y, out z);
computeShader.Dispatch(kernel, (int)(64 / x), (int)(64 / y), 1);
GUI.DrawTexture(new Rect(0, 0, 64, 64), renderTexture, ScaleMode.ScaleToFit, false);
OnGUI関数でレンダーテクスチャーを描画します。コンピュートシェーダーでアルファ値に0が代入されているのでアルファブレンドをオフにします。
実行して確認
実行してコンピュートシェーダーの計算結果が描画されることを確認します。
今回はテクスチャーを使用したコンピュートシェーダーの実装方法を紹介しました。
次回はテクスチャーより実装しやすいバッファーを使った方法を紹介したいと思います。
関連ページ
こちらのページも合わせてご覧下さい。