unity compute shader

Unity Compute Shader: GPU の並列処理能力を活用する

Unity Compute Shader は、グラフィックス処理ユニット (GPU) の並列処理能力を活用して、高度な計算タスクを高速に実行するための強力なツールです。通常のレンダリングパイプラインとは異なり、GPU 上で直接実行されるプログラムを作成できます。この機能により、複雑なアルゴリズム、シミュレーション、画像処理などを効率的に実行し、ゲームのパフォーマンスを向上させることが可能です。本稿では、Unity Compute Shader の概要、作成方法、実行方法、そしてクロスプラットフォーム対応について解説します。

Unity Compute Shader の基礎: GPU で並列計算を実行

Unity Compute Shader は、DirectCompute や OpenCL のような GPGPU (General-Purpose computing on Graphics Processing Units) 技術に基づいています。GPU の多数のコアを並列に動作させることで、CPU では処理が難しい大規模な計算タスクを高速に実行できます。

1. サポートプラットフォーム:

Unity Compute Shader は、DirectX 11/12、Metal、Vulkan、OpenGL 4.3、OpenGL ES 3.1 など、様々なグラフィックス API をサポートしています。対応プラットフォームは、SystemInfo.supportsComputeShaders で確認できます。このプロパティがtrueを返す場合、Compute Shaderがサポートされています。

2. Compute Shader アセット:

Compute Shader は、.compute 拡張子を持つアセットファイルとして作成します。Projectビューで右クリックし、「Create」->「Shader」->「Compute Shader」を選択することで作成できます。コードは DirectX 11 スタイルの HLSL で記述し、#pragma kernel ディレクティブでカーネル関数を定義します。

3. カーネル関数:

カーネル関数は、GPU 上で実行される計算処理の本体です。#pragma kernel KernelName のように記述し、KernelName が C# スクリプトから呼び出す際の関数名となります。 numthreads 属性でスレッドグループのサイズを指定します。

4. スレッドグループとスレッド:

GPU 上での計算は、スレッドグループ単位で実行されます。各スレッドグループは、複数スレッドで構成され、[numthreads(x,y,z)] 属性で指定した x * y * z の数のスレッドが並列に実行されます。各スレッドは、SV_DispatchThreadIDSV_GroupThreadIDSV_GroupID などの組み込み変数を使って自身のIDや所属するグループのIDを取得できます。

Unity Compute Shader の作成と実行: スクリプトから GPU を制御

1. Compute Shader の作成:

.compute ファイルを作成し、HLSL でカーネル関数を記述します。以下の例では、テクスチャのすべてのピクセルを赤色に設定する Compute Shader を示します。

#pragma kernel MyKernel

RWTexture2D<float4> Result;

[numthreads(8,8,1)]
void MyKernel (uint3 id : SV_DispatchThreadID)
{
    Result[id.xy] = float4(1, 0, 0, 1);
}

2. Compute Shader の実行:

C# スクリプトで ComputeShader オブジェクトを作成し、Dispatch 関数でカーネル関数を呼び出します。

using UnityEngine;

public class ComputeShaderExample : MonoBehaviour
{
    public ComputeShader computeShader;
    public RenderTexture result;

    void Start()
    {
        int kernelHandle = computeShader.FindKernel("MyKernel");

        result = new RenderTexture(256, 256, 0);
        result.enableRandomWrite = true;
        result.Create();

        computeShader.SetTexture(kernelHandle, "Result", result);
        computeShader.Dispatch(kernelHandle, result.width / 8, result.height / 8, 1);
    }
}

3. ComputeBuffer:

ComputeBuffer を使用することで、CPU と GPU 間でデータをやり取りできます。構造化バッファとして使用し、任意のデータを GPU に渡すことが可能です。SetDataメソッドでCPU側のデータをGPUに送り、GetDataメソッドでGPU側のデータを取得します。

4. RenderTexture:

RenderTexture を使用することで、Compute Shader でテクスチャを操作できます。enableRandomWrite を true に設定することで、Compute Shader からテクスチャへの書き込みが可能になります。

Unity Compute Shader とクロスプラットフォーム対応: HLSL からの変換

Unity は、HLSL で記述された Compute Shader を、各プラットフォームのシェーダー言語 (Metal Shading Language, GLSL など) に自動的に変換します。これにより、クロスプラットフォーム対応の Compute Shader を容易に作成できます。

1. クロスプラットフォームの注意点:

プラットフォーム間で Compute Shader の動作に違いがある場合があるため、注意が必要です。特に、メモリへのアクセス方法や、リソースのバインド方法などには、プラットフォーム固有の制約があります。#pragma target 3.5のようなプラグマディレクティブでシェーダーモデルを指定することで、特定の機能の利用可否を制御できます。

2. HLSL 専用または GLSL 専用の Compute Shader:

通常はクロスプラットフォーム対応のHLSLで記述しますが、パフォーマンスを追求する場合など、プラットフォーム固有の機能を使いたい場合は、CGPROGRAM  ENDCG で囲むことで HLSL 専用の Compute Shader を、GLSLPROGRAM  ENDGLSL で囲むことで GLSL 専用の Compute Shader を作成できます。ただし、プラットフォームごとにシェーダーを管理する必要があるため、保守性は低下します。

Unity Compute Shader の活用: パフォーマンス向上のための強力なツール

Unity Compute Shader は、GPU の並列処理能力を活用することで、ゲームのパフォーマンスを向上させるための強力なツールです。複雑な計算、シミュレーション、画像処理など、様々な用途で活用できます。

  • 物理シミュレーション: パーティクルシステム、布シミュレーション、流体シミュレーションなどを高速に実行できます。大量のパーティクルの挙動計算などに最適です。

  • 画像処理: ポストエフェクト、画像フィルター、画像認識などを GPU で処理できます。リアルタイムな画像処理が求められる場合に効果的です。

  • AI: 機械学習の推論処理などを高速化できます。特に、行列演算など並列処理に適した計算を高速に実行できます。

Unity Compute Shader を使いこなすことで、より高度でパフォーマンスの高いゲーム開発が可能になります。

さらなる詳細については、次のリソースを参照してください。

質問と回答

Q1: Compute Shaderはどのような場合に使用するべきですか?
A1: 大量のデータを並列に処理する必要がある場合、例えば物理シミュレーションや画像処理などで使用します。
Q2: Compute Shaderと通常のシェーダーの違いは何ですか?
A2: Compute Shaderは、グラフィックスだけでなく、一般的なデータ計算にも使用できるため、より幅広い用途に適しています。
Q3: Compute Shaderをデバッグする方法はありますか?
A3: Compute Shaderのデバッグは難しいですが、出力をテクスチャに書き込む事で結果を確認することができます。