本日はComputeShader枠です。
〇ComputeShaderとは?
ComputeShaderはその名の通りシェーダープログラムであり、GPU上で実行されますが、一般的なShaderと異なり、描画を目的としていません。
GPGPU(General Purpose GPU)の考え方に基づき、GPUの並列演算機能を描画以外の処理に使用するという考え方です。
〇ComputeShaderでランタイムシェーダーコンパイルは可能か?
結論から先に書くとUnityでランタイムシェーダーコンパイル自体は不可能ですが、あたかもランタイムにシェーダーを構築しているように見せること自体は可能です。
UnityではCG/HLSL言語を用いてシェーダーを記述します。
しかしC#プログラム同様にランタイムにコンパイルされるわけではなく基本的にはUnityEditorからビルドする際にコンパイルされます。つまり実機内でShaderを記述することはできません。
しかしShaderを構築することは不可能であっても、シェーダーのプロパティを変更することは可能です。 最も一般的な例としてマテリアルの色を変えるといったことがあげられます。また、Textureも差し替えが可能です。
ここで、ConputeShaderを用いて計算した色情報をRenderTextureに与えることで疑似的なFragmentShaderのランタイム構築が可能です。
今回はこのアプローチがどこまで有効なのかを検証していきます。
〇ComputeShaderの計算結果をRenderTextureに描画する
まずはコア部分となるComputeShaderの計算結果をRenderTextureに描画させることを行います。
ComputeShaderは以下のようになります。
#pragma kernel CSMain
RWTexture2D<float4> Result;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
float2 uv = float2(id.x, id.y) / 512.0;
Result[id.xy] = float4(uv.x, uv.y, 0.5, 1.0);
}
ここでRWTexture2D<float4> ResultはRenderTextureを読み書き可能な状態で定義しています。
512はテクスチャサイズであり、ここではuvの色が結果として返されます。
C#側は次のようになります。
using UnityEngine;
public class ComputeRenderer : MonoBehaviour
{
public ComputeShader computeShader;
public Material material;
private RenderTexture resultTexture;
private int kernel;
void Start()
{
int resolution = 512;
resultTexture = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32);
resultTexture.enableRandomWrite = true;
resultTexture.Create();
kernel = computeShader.FindKernel("CSMain");
computeShader.SetTexture(kernel, "Result", resultTexture);
material.SetTexture("_MainTex", resultTexture);
}
void Update()
{
computeShader.Dispatch(kernel, 512 / 8, 512 / 8, 1);
}
}
このクラスは512の解像度のテクスチャとしてRenderTextureを作成し、ComputeShaderに値を渡している形になります。
なおmaterial.SetTexture("_MainTex", resultTexture);の_MainTexは使用するマテリアルのShaderのプロパティ名に合わせる必要があります。
これによってCubeの見た目がUVのグラデーションとして返されます。

本日は以上です。