【vvvv】VL.FuseのNeighborGridで近傍探索の高速化
vvvvのVL.Fuseに近傍探索を高速化するSpatial Hash + NeighborGridという機能を見つけたのですが、使い方の資料があまり見当たらなかったので、ここに残したいと思います。
要件
- vvvv gamma 6.6
- VL.Fuse 1.0.3 beta6
今回サンプルとして使うプロジェクトデータはこちらになります。
近傍探索とは
近傍探索(パーティクルシステムの)とは、ある点とそれに近い距離の点を探すアルゴリズムのことです。
一番素直な実装は全数検索で、自分以外の点すべての距離を計算する方法です。例として10000パーティクルの近傍探索を行う場合は、10000x10000=1億回の距離計算を行わなければならず、PCのリソース的にも現実的ではありません。
それを解決するために、あらかじめデータを加工して最適化しておき、近くにある点を素早く見つけられるようにするのが、近傍探索アルゴリズムです。
VL.Fuseでは近傍探索アルゴリズムに**Spatial Hash(空間ハッシュ)**を用いているようです。GPUの並列処理に向いたアルゴリズムで、いくつかの制約はありますがとても高速に動作します。
SpatialHash(空間ハッシュ)アルゴリズムを手順に沿って簡単に説明すると、
- 空間をグリッド状に分割して、空間に番号を割り当てる。
- パーティクルに今いるグリッドの番号を登録しておく。
- パーティクルを整理して、グリッドの番号だけでパーティクルたちを呼び出せるようにしておく。
- 自分が今いるグリッドからパーティクルたちを検索する
という流れになります。
実際に探索するときには、パーティクルがあるグリッド番号から、同じグリッドにあるパーティクルを読んできたり、近くのグリッドを探すだけでよくなり、計算効率がとても良くなります。
以下、より詳細な解説と資料になります。
NeighborGridの使い方
VL.FuseにはFuse.Compute.NeighborGrid
に近傍探索アルゴリズムの機能が置いてあります。
Helpも無くノードも最低限しか無いので、一見すると使い方が分かりづらいのですが、基本的にはFor(fuse)
と似たような感覚で使っていくことができます。
Grid内のIndexノードはIndex (Neighbor)
で、SpatialHashによって最適化されたIndexにアクセスすることができます。
シンプルにパーティクル間の距離を測るノードを組んでみました。
まずはFor (Fuse)
を使った例です。
全数検索になるので_、各コアで1000回のループが走ってしまい_、処理が重くなる原因になります。
こちらはNeighborGridを使った例です。
- GridCellに現在いるGridのHashが入っています
- 今いるグリッドに近いパーティクルだけを集めた配列でForループを回しているイメージです。
- Indexノードが近くにあるパーティクルの番号を返してくれるので、計算量が少なく済みます。
実装例
近いパーティクル同士を線で繋ぐビジュアル(通称Plexus)を実装してみました。
3万パーティクルほどの近傍探索を120FPSほどで処理できている様子がわかります。グリッドは16分割四方で行っているので、各グリッドごとのパーティクル数は抑えられて、安定したフレームレートが実現できています。
実装のコアはこんな感じです。
- 距離計算をして、検索範囲内のパーティクルに線分を追加するコードになります。
- AppendBufferにて、線の分のBufferを追加していく実装になっています。
注意点
4分割四方で区切ると見るからにパフォーマンスが下がります。
これはグリッドごとのパーティクルの数が多いため、各パーティクルごとの探索するパーティクル数が多くなるためです。
また、パーティクルの分布に偏りが出ると、グリッド分割の効率が悪くなり、パフォーマンスが下がります。
また、範囲外については無視されます。
また、分割グリッド数が多くても、CPU側に負荷がかかりハッシュ化に時間がかかったり、正常に探索できなくなるので、これもよくありません。
まとめ
この近傍探索はコンピューターグラフィックスによく出てくるアルゴリズムで、高速な近傍探索が実現できれば、表現の幅が大きく広がります。ボロノイ、Boidsシュミレーション、粒子法の流体シュミレーションなど、近傍探索を使う例は挙げればキリがないです。
しかし、vvvv界隈に近傍探索の資料が乏しく、実装に苦労した思い出があります。特にVL.Fuseにはドキュメントが無く、Example等を探して使い方を探っていくほかなく、下のVL.Fuseリポジトリ内のR&DフォルダにあるExampleを見つけるまでは、使い方が全くわかりませんでした(汗
しかし、大量のパーティクルを効率よく捌いていければ、圧巻の表現(頂点数の暴力)をリアルタイムで生み出すことも可能なので、引き続き勉強していこうかと思います。
Discussion