VVVVにInstance Noodlesを導入して手軽にGPGPUする


# Instance Noodlesとは

[Instance Noodles \| vvvv](https://vvvv.org/contribution/instance-noodles)

DirectX11のCompute Shaderを使ったGPGPU計算や、Geometry Shaderを使ったジオメトリ制御を、普通のVVVVのノード感覚で扱うためのContributions（ライブラリ）です。
VVVVにデフォルトで含まれているMapやGamma、Vectorなどの基本的なノードのCompute Shader版が大量に含まれているので、自分でシェーダを書かなくても手軽にGPGPUが使えます。

下に貼ったのは300000個のパーティクルをCurlノイズをかけてうねうねさせてみた感じのパッチと、その描画結果です。こんな感じで比較的シンプルなパッチで手軽にGPGPUできます。
下記のパッチで言うと`Brownian`, `Curl`, `Vector3DSplit`, `Map`, `Vector3DJoin`, `Polar`, `SpriteBuffered`はすべてInstance Noodlesに含まれるノードで、中身はシェーダを呼び出すだけのパッチになっています。

![20160819_2016.08.24-22.02.59.png](https://qiita-image-store.s3.amazonaws.com/0/26489/2aee8e76-8fa0-1cda-88b6-c8a38bbc67e0.png)

![20160819-Renderer_2016.08.24-22.02.23.png](https://qiita-image-store.s3.amazonaws.com/0/26489/381073bc-0dbf-d999-b291-1e2912297fbe.png)

# インストール

前提として、DirectX11を使ってるのでDX11 packsが必要になります。
入れてない人は [vvvvのインストールガイド\[DX11対応\] \- Qiita](http://qiita.com/AquaLamp/items/1ca0a69edcaea91eeefb) を読んでDX11 packsの導入を済ませておいてください。

Contributionsページのdownloadからzipファイルをダウンロードし、解凍したフォルダをVVVVのインストールフォルダ内のpacksフォルダに置くと使えます。

`...\packs\InstanceNoodles\girlpower\Compute\01_ComputeBasic.v4p` を開いてうまく動いていれば導入は完了です。
導入後はgirlpowerと `...\packs\InstanceNoodles\nodes\modules` フォルダ内を見て、どんなパッチが用意されてるのかと、ヘルプパッチで扱い方をひと通り確認しておくと良いです。

# パーティクルを出してみる

まずは簡単なところから。

上のパッチでも使っている`Brownian`というノードを使ってみます。これはブラウン運動をシミュレーションするノードで、指定した数分のブラウン運動する座標値が取得できます。
`Brownian`の出力は`SpriteBuffered`の`Position 3D Buffer`につなぎます。`SpriteBuffered`はパーティクルを表示するためのシェーダだと思えば良いです。
`Brownian`と`SpriteBuffered`のSpread Countインレットにはそれぞれ描画したいパーティクル数を設定します。

`SpriteBuffered`の出力はDX11 Layerなので、あとはこれをDX11用のRendererに繋げばパーティクルが表示されます。

![20160824_2016.08.24-22.59.22.png](https://qiita-image-store.s3.amazonaws.com/0/26489/4aaee1cb-825d-640c-0c8d-4d1deb694f6c.png) ![20160824-Renderer_2016.08.24-22.56.41.png](https://qiita-image-store.s3.amazonaws.com/0/26489/a96abb7f-87e1-f1c0-2b1f-0f11640face6.png)

表示できたらパーティクル数をどんどん増やしてみてください。
座標値をGPU側に転送してGPGPUで計算しているので、かなりパーティクル数を増やしてもあまり処理落ちしないはずです。
手元のGeforce 940Mだとパーティクル1000000個出しても48fpsぐらいは出る感じです。

# CPU-GPU間の値の受け渡しについて

GPUで計算する場合、計算に必要な値は基本的にGPUのStructured Bufferに転送しておく必要があります。CPU→GPUへの転送は`DynamicBuffer`というノードを使用します。
例えば、`RandomSpread`で生成した100000 * xyzの値をInstance Noodlesの`Attractor`で使用したい場合、そのままSpreadを渡すことはできないので、`DynamicBuffer`でGPUに転送したうえで渡すような使い方になります。
![20160824_2016.08.25-00.30.23.png](https://qiita-image-store.s3.amazonaws.com/0/26489/c4bfcf7e-965b-387b-7f01-6113143b7eba.png)


また、計算結果に関してもGPUに保存されているため、Spreadとして取り出す必要がある場合はGPU→CPUへの読み出しを行う必要があります。これには`ReadBack`というノードを使用します。
![0_2016.08.25-00.41.36.png](https://qiita-image-store.s3.amazonaws.com/0/26489/97874ad6-4e06-727d-1af3-484c6f7ee74c.png)

# まとめ

だいたい基本的なところはこんな感じかな……？パッチはGitHubに置いておきました。

[vvvv\-sandbox/InstanceNoodlesSample at master · clomie/vvvv\-sandbox](https://github.com/clomie/vvvv-sandbox/tree/master/InstanceNoodlesSample)

今回は触れなかったけど、他にもDX11.GeomFX系のGeometryにエフェクトかけられる感じのノードとかあって、そっちはそっちでめちゃめちゃ便利そうなやつが大量にあります。
現状でもBufferを扱えるノードはだいぶ充実しているので、たぶんInstance Noodlesを導入するだけでもかなりいろいろできるはずです。Damperがないのがちょっと痛いぐらい。
VVVVでDX11やるならpacksと一緒にとりあえずで入れておいていいぐらいだと思います。

# DX9でGPGPUしたい場合

Vertex ShaderとPixel Shaderでテクスチャの各ピクセルの色情報をただのfloat値として扱って計算することになるっぽいです。
DirectX9でもGPGPUしたいという人は以下の記事が参考になります。

[\.ore, GPGPUする](http://dot-ore.tumblr.com/post/149120374305/gpgpu%E3%81%99%E3%82%8B)