大量描画・実装基盤

GPUインスタンシング

GPU Instancing

同じメッシュの多数の個体をまとめて描く。

2 / 10

インタラクティブデモ

デモを準備しています…

GPUインスタンシング

ドラッグで視点を回転、Ctrl(⌘)+ スクロールでズーム。タッチ操作は 2 本指です。

ひとことで

同じ形(メッシュ)の物体をたくさん描くときに、形は 1 つだけ GPU に渡し、物体ごとに違う位置・向き・大きさ・色を配列で渡して、1 回の描画命令でまとめて描く方法です。木を 1 万本描くのに、1 本ずつ描画命令(ドローコール)を出すと、CPU が命令の準備に追われてフレームレートが落ちます。インスタンシングなら命令は 1 回で済み、同じ三角形の数でも、CPU の負担がほとんどなくなります。

ゲームでの使いどころ

  • 植生:森の木、草むら、岩(密度マスクによる散布で並べた物)。
  • 群衆・群れ:観客、兵士、鳥や魚の群れ。アニメーションは頂点アニメーションテクスチャと組み合わせる。
  • 弾・破片・粒子:同じ形の大量の物体。
  • 建物の部品:窓、柵、瓦など、同じ部品をくり返す背景。

しくみ

ドローコールが重い理由:描画命令ごとに、CPU はシェーダーやテクスチャ、行列などの状態を設定し、ドライバーが整合性を確かめてから GPU へ送ります。この準備は三角形の数にほとんど関係なく、命令の回数に比例してかかります。何千回も出すと、GPU が暇でも CPU がボトルネックになります。

インスタンシング:

  1. 形(頂点とインデックス)を 1 つだけ用意します。
  2. 物体ごとのデータ(変換行列、色など)を、インスタンスごとに進むバッファ(インスタンス属性)に並べます。
  3. 「この形を N 個描け」という 1 回の命令(drawElementsInstanced)を出します。
  4. 頂点シェーダーは、今何番目の物体か(gl_InstanceID)で、自分の行列や色を読みます。
pworld=Minstance plocal\mathbf{p}_{\text{world}} = M_{\text{instance}}\,\mathbf{p}_{\text{local}}

実装のポイント

  • 動かない物は一度だけ送る:配置が変わらない木や岩は、最初にバッファを作ったら送り直しません。
  • 形の種類ごとにまとめる:インスタンシングは同じ形・同じマテリアルでしか使えません。木の種類が 5 つなら、5 回の命令になります。色や揺れ方の違いはインスタンスごとのデータで出します。
  • カリングや LOD との組み合わせ:画面外の物体や遠くの物体まで描くと、GPU の仕事が増えます。視錐台カリングやLODで、インスタンスの列を毎フレーム作り直します。これを GPU で行うのがインダイレクト描画です。
  • 影の描画も同じ:影のためにもう一度描くとき、インスタンシングなら影も 1 回の命令で済みます。

つまずきやすい点

  • 全体でカリングされる:インスタンスをまとめた物体全体の包囲体で視錐台の判定をするので、包囲体が正しくないと、一部が見えているのに全部消えることがあります。
  • 小さすぎる形:頂点が数個しかない形を大量にインスタンシングすると、GPU の効率が落ちることがあります。数十〜数百頂点以上の形で効果が大きくなります。
  • 透明な物の順番:半透明のインスタンスは、描く順番(奥から手前)の並べ替えが必要になり、手間が増えます。

デモで試すこと

  1. 「インスタンシング」では、4000 本の木が 1 回(数回)の描画命令で描かれています。左下の「描画命令」と「描画命令を出す CPU の時間」を見てください。
  2. 「1 本ずつ別の物体」に切り替えると、描画命令が木の数だけに増え、CPU の時間が何十倍にもなります。三角形の数は同じです。
  3. 「木の数」を増やして、両方の方法で CPU の時間がどう変わるかを比べてください。1 本ずつの方は、木の数に比例して増えていきます。

参考資料

Unity ComputeShader ↗

分野全体の資料で、この項目を直接扱っているとは限りません。