Unity:Compute Shader と Geometry Shader で60fps/100万個のキューブを描画!

最終更新日



はじめに

Compute Shaderの勉強中なので、簡単なサンプルとしてキューブを100万個動かしてみました。主にPositionを再計算する処理をCompute Shader で実装しております。比較用としてスクリプト(CPU)でのPositionを再計算する処理とのパフォーマンスの違いも見ます。

Unityを知らない方は、ぜひ こちらの記事 をご参照ください。

Link

環境

私のPC環境は以下となります。

  • CPU:Intel Core i7-6700
  • MEM:32GB
  • GPU:Geforce GTX1060
  • ディスク:SSD

ソースコード

Compute Shaderと描画用Shader の管理スクリプト

Compute Shaderと描画用Shaderを生成して、バッファの共有を行うソースコードになります。

  • OnEnableでComputeBufferを生成して共有
    • 描画用Shaderにバッファとして設定
    • Compute Shaderにバッファとして設定
  • Update で Compute Shader で位置の再計算
    • ここでバッファを更新すると、共有されている描画用Shader側にも反映されます。
  • OnRenderObject で 描画用Shader にて画面に描画
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;

public class ComputeShaderCube : MonoBehaviour
{
    public Shader drawShader;

    public ComputeShader computeShader;

    ComputeBuffer buffer;
    Material material;
    int CSMain;

    void OnEnable()
    {
        // 頂点を生成
        var points = new List<Vector3>();
        for (int x = Gui.start; x < Gui.end; x++)
            for (int z = Gui.start; z < Gui.end; z++)
                points.Add(new Vector3(x, 0, z));

        // バッファを生成
        buffer = new ComputeBuffer(points.Count, Marshal.SizeOf(typeof(Vector3)), ComputeBufferType.Default);
        buffer.SetData(points);

        // 描画シェーダーにバッファを設定
        material = new Material(drawShader);
        material.SetBuffer("points", buffer);

        // コンピュータシェーダにバッファを設定
        computeShader.SetBuffer(0/*CSMain*/, "bufferXYZ", buffer);
    }

    void Update()
    {
        // コンピュータシェーダで再計算
        this.computeShader.SetFloat("realtimeSinceStartup", Time.realtimeSinceStartup);
        this.computeShader.Dispatch(0/*CSMain*/, 1, 1, 1);
    }

    void OnDisable()
    {
        buffer.Release();
    }

    /// <summary>
    /// 描画シェーダーの実行
    /// </summary>
    void OnRenderObject()
    {
        material.SetPass(0);

        Graphics.DrawProcedural(MeshTopology.Points, buffer.count);
    }
}

Compute Shader

  • bufferXYZ が 描画用Shaderと共有のメモリ
  • realtimeSinceStartup が立ち上げ後の経過時間
  • CSMain 関数が並列に実行されます
#pragma kernel CSMain

RWStructuredBuffer<float3> bufferXYZ;
float realtimeSinceStartup;

[numthreads(1000, 1, 1)] // x方向をスレッド数で定義
void CSMain (uint3 groupThreadID : SV_GroupThreadID)
{
    int x = groupThreadID.x - 500;
    for (int z = -500; z < 500; z++) { // z方向をforで定義
        float y = sin(sqrt((x * x) + (z * z)) / 10 + realtimeSinceStartup) * 3;
        bufferXYZ[(z + 500) + (x + 500) * 1000].y = y;
    }
}

描画用 Shader

Geometry Shaderはこちらの記事を参照してください。

実行結果

CPUで位置計算、Compute Shader で位置計算した場合のFPSが左上に表示されていますが、これを見ると明らかにパフォーマンスに違いが出ているのがわかると思います。

CPUで位置計算
GPGPU(Compute Shader)で位置計算

最後に

体感が変わるから  Unity の Shader は良いぞ!







よければ、SNSにシェアをお願いします!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする