プロジェクトファイル.unitypackageへのリンク
彼女はマンデルブロのフラクタルを描きます。
コードの各行については説明しません。GPUで計算を実装するために必要な手順のみを示します。 したがって、Unityでプログラムコードを開き、説明されたコード行がどのように使用されるかを確認するのが最善です。
フラクタルシェーダーはHLSLで記述されています。 以下はそのテキストです。 関連する行について簡単にコメントしましたが、詳細な説明は以下になります。
// GPU : RWTexture2D<float4> textureOut; // , RWStructuredBuffer<double> rect; // , RWStructuredBuffer<float4> colors; // , CPU #pragma kernel pixelCalc // , CPU [numthreads(32,32,1)] // , void pixelCalc (uint3 id : SV_DispatchThreadID){ // . id , float k = 0.0009765625; // 10241024 22 double dx, dy; double p, q; double x, y, xnew, ynew, d = 0; // , uint itn = 0; dx = rect[2] - rect[0]; dy = rect[3] - rect[1]; p = rect[0] + ((int)id.x) * k * dx; q = rect[1] + ((int)id.y) * k * dy; x = p; y = q; while (itn < 255 && d < 4){ // : , 2x2 xnew = x * x - y * y + p; ynew = 2 * x * y + q; x = xnew; y = ynew; d = x * x + y * y; itn++; } textureOut[id.xy] = colors[itn]; // : , - }
注意深い読者は言う:著者、説明してください! テクスチャサイズは1024×1024で、スレッド数は32×32です。 id.xyパラメーターは、テクスチャ内のすべてのピクセルにどのように対処しますか?
丁寧でありながら、GPUリーダーでのコンピューティングの問題については経験の浅い人が殺します。 そして、スレッドの数が32x32であるということはどこに続きますか? そして、「id.xy」の理解方法は?
次のように2番目に答えます。ディレクティブ[numthreads(32,32,1)]は、32x32x1スレッドがあることを示しています。 同時に、idパラメーターは32x32x1空間の座標形式で値を取るため、フローは3次元グリッドを形成します。 値の範囲はid.x [0、31]、値の範囲はid.y [0、31]、id.zは0です。また、id.xyは短いレコードuint2(id.x、id.y)です。
コマンドでCPU側からこのカーネルを呼び出すと、32x32スレッドになります(この最初の注意深い読者に既に答えています)。
ComputeShader.Dispatch(kernelIndex, 1, 1, 1)
これらの3つのユニットを参照してください? これは、ディレクティブ[numthreads(32,32,1)]の番号と同じであり、互いに乗算されます。
次のパラメーターでシェーダーを開始した場合:
ComputeShader.Dispatch(kernelIndex, 2, 4, 1)
これは、x軸に沿って32 * 2 = 64、y軸に沿って32 * 4 = 128、つまり合計64x128スレッドになります。 パラメータは、各軸で単純に乗算されます。
ただし、この場合、カーネルは次のように起動されます。
ComputeShader.Dispatch(kernelIndex, 32, 32, 1)
これにより、合計1024x1024のスレッドが得られます。 そして、それはid.xyインデックスが1024x1024のテクスチャ空間全体をカバーする値を取ることを意味します
これは便宜上行われています。 データは配列に格納され、各ストリームはデータ単位で同じ操作を実行し、データ単位の数に等しいスレッド数を作成し、ストリームインデックスがそのデータ単位をアドレス指定するようにします。 とても快適です。
私たちのフラクタル化プログラムのシェーダーコードについて知る必要があるのはそれだけです。
次に、シェーダーコードを実行するためにCPU側で行ったことを見てみましょう。
変数の宣言:シェーダー、バッファー、およびテクスチャ
ComputeShader _shader RenderTexture outputTexture ComputeBuffer colorsBuffer
enableRandomWriteを有効にすることを忘れずに、テクスチャを初期化します
outputTexture = new RenderTexture(1024, 1024, 32); outputTexture.enableRandomWrite = true; outputTexture.Create();
オブジェクトの数とオブジェクトのサイズを設定して、バッファーを初期化します。 事前に入力された色の配列のデータをビデオメモリに書き込む
colorsBuffer = new ComputeBuffer(colorArray.Length, 4 * 4); colorsBuffer.SetData(colorArray);
シェーダーを初期化し、カーネルにテクスチャとバッファーを設定して、データを書き込むことができるようにします
_shader = Resources.Load<ComputeShader>("csFractal"); kiCalc = _shader.FindKernel("pixelCalc"); _shader.SetBuffer(kiCalc, "colors", colorsBuffer); _shader.SetTexture(kiCalc, "textureOut", outputTexture);
これがデータの準備です。 あとは、シェーダーカーネルを起動するだけです
_shader.Dispatch(kiCalc, 32, 32, 1);
このコマンドを実行すると、RenderTextureテクスチャがカメラが見ているImageコンポーネントのmainTextureとして使用されるため、テクスチャはすぐに見える色で塗りつぶされます。