WebGPUで反応拡散系

2023-10-10

ずっと昔にWebGLを触ってみたことがあったのだけど初期化が面倒で放置になってしまった。 近頃(というか今年の前半に)WebGPUというものが使えるようになったということを聞いたので、再挑戦を込めてようやく触ってみた。

デモ

WebGPUのざっくり理解

WebGPUを始めるにあたって、ググって出てきた初めての WebGPU アプリを参考にしてみた。 内容はライフゲームを作るチュートリアルで、世代更新の処理をコンピュートシェーダーを使ってGPUで並列に計算できるのが利点となっている。 また頂点・フラグメントシェーダーもモデルを1体描画するだけじゃなくインスタンシングで複数行えたり、 描画パスを複数設定して1回のコマンドバッファ起動で複数の処理や描画を行わせることができる (自分が知らないだけでWebGLでもできたのかもしれない)。

初期化

WebGLでもそうだったが、WebGPUもより一層初期化が面倒で多数の要素が必要なのでさらに複雑度が増している:

  • アダプターとデバイスをリクエストする
  • キャンバスを設定する
  • 頂点バッファを作成
    • 頂点バッファのレイアウトを定義
  • シェーダーモジュールを作成(コンピュート・頂点・フラグメントシェーダー)
  • パイプライン作成: ←シェーダーモジュールを指定
    • パイプラインレイアウト
  • ユニフォーム用のバッファを作成
  • バインドグループ作成
    • バインドグループレイアウト

すでに心折れかかってる…こう実行時に使うためのインスタンスを初期化で事前にあれこれ準備しておく必要があるのって管理が煩雑でわけわからなくなるんだよね…。

実行時の処理

実行も手順は多段に渡る:

  • コマンドエンコーダーを作成
    • コンピュートパスまたはレンダーパスを開始
      • パイプラインを指定
      • (レンダーパスのみ)パスに頂点バッファを設定
      • ユニフォームの値を設定
      • バインドグループを設定
      • (レンダーパス)描画コマンド、(コンピュートパス)ディスパッチワークグループ
  • エンコーダーをfinishして、デバイスキューにコマンドバッファを送る

「初めての…」のライフゲームでは計算を進める際にピンポンバッファパターンを用いるが、ストレージだけじゃなくバインドグループも2つ用意してフレームごとに切り替えて使用する必要がある。

シェーダー

シェーダーの文法はWGSLという、WebGLでのものなどとも違う、新たな書式になっている。 シェーダーではいくつかの種類のデータを扱うことができる:

  • ユニフォーム:少量のデータ(行列、マテリアル、など)
  • ストレージ:より大型のデータ(ライフゲームでのセル情報を入れる二次元配列など)
  • 自分のID(インデックス):コンピュートシェーダーで並列処理させる際に利用できる
  • テクスチャ:フラグメントシェーダーでテクスチャサンプラーを使って内容を参照できる

改変してみる

じゃあここからなにを作ろうかと思い、アイディアに欠けるが以前もやったことがある反応拡散系をWebGPU上で動かしてみることにした。 以前のプログラムではすべての計算をJavaScriptで動かしていたが、今回はWebGPUのシェーダーで並列化できるのが利点。

実際のところ大枠はライフゲームと同じでセルごとの計算が違うだけなので、最速でやるならコンピュートシェーダーの変更だけで事足りる。 それだけではなんなので、少しいじってみた:

  • ストレージからテクスチャに変換
    • 「初めての…」ではコンピュートシェーダーでストレージを更新し、描画時にフラグメントシェーダーからも参照してセル描画していたが、copyBufferToTextureでテクスチャに変換してUVによるテクスチャサンプルにしてみた
    • ただなぜかサンプラーでフィルターを使うとエラーになってしまう、nearestしか使えず補間されないので結果は変わらず
    • テクスチャ化によって描画側のバインドグループはダブルバッファにする必要はなくなる
  • マウスでセルの状態をいじれるようにする
  • 3D表示
    • テクスチャ化したことにより、3Dモデルに貼り付けることもできる
    • JS側での視点などの行列計算はglMatrixを使うものかと思ったが、WebGPU Samplesのcameraswgpu-matrixというのを使っていたのでそれに習ってみた

感想

  • コンピュートシェーダーで並列計算できるのがよい
  • シェーダー言語の文法をなぜわざわざ微妙に変えるのか…
    • fn とか f32 とか
    • switchcaseはFallthroughしない
    • いわゆる線形補間は lerp じゃなくて mix
  • 反応拡散系のパラメータを適当にあれこれ探してみた
    • まだシマウマや牛の柄はどうやったら生成できるのかわからない…
    • ヒョウみたいに崩れた丸(Cの形)みたいにするには物質が2つではうまくいかないような気がする
  • WebGPUは現状パソコンのGoogle Chrome系でしか使えないようで、スマホでも動かない…残念
    • 状態はわからないけどSafariが期待できないので、一般的に使用できるようになるにはまだ相当遠いことだろう。

参考

  • Your first WebGPU app 日本語にするとちょっとおかしい箇所があるので、英語で見るのがいいかも

反応拡散系関連