大量描画・実装基盤

カリング

Frustum / Occlusion Culling

画面外や遮蔽物の奥を描画対象から外す。

5 / 10

インタラクティブデモ

デモを準備しています…

カリング

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

ひとことで

画面に映らない物体を、描く前に対象から外す処理です。カメラの見える範囲(視錐台)の外にある物体を外すのが視錐台カリング、壁や建物の後ろに隠れて見えない物体を外すのが遮蔽(オクルージョン)カリングです。GPU に渡す物体が減れば、頂点の処理や描画命令の準備、影の描画まで、すべての手間が減ります。

ゲームでの使いどころ

  • すべてのゲーム:視錐台カリングは、ほぼすべてのエンジンが自動で行っている。
  • 屋内・都市:壁や建物で視界がさえぎられる場面では、遮蔽カリングの効果が大きい。部屋と出入口に分けるポータルカリングも使われる。
  • 影:光源から見た視錐台で、影を落とす物体を選ぶ。
  • 大量の物体:GPU でカリングして、インダイレクト描画で残りを描く。

しくみ

視錐台カリング:視錐台は、上下左右と手前・奥の 6 枚の平面で囲まれた形です。物体を包囲体(球や AABB)で近似し、各平面の外側に完全に出ているかを調べます。球(中心 c\mathbf{c}、半径 rr)なら、平面の方程式 n⋅x+d=0\mathbf{n}\cdot\mathbf{x} + d = 0(n\mathbf{n} は内向き)に対して

n⋅c+d<−r\mathbf{n}\cdot\mathbf{c} + d < -r

となる平面が 1 枚でもあれば、見えません。物体が多い場合は、BVH などの木構造で、箱ごとまとめて外します。

遮蔽カリング:まず、大きな遮蔽物(壁や地形)だけを低い解像度で描き、画素ごとの一番手前の距離(深度バッファ)を作ります。次に、各物体の包囲体が画面上で占める範囲の深度を調べ、その範囲のどこを見ても物体の方が奥にあれば、隠れていると判断します。範囲を速く調べるために、深度バッファを縮小しながら「その範囲で一番奥の値」を持たせたピラミッド(Hi-Z)を使います。

実装のポイント

  • 前のフレームの深度を使う:遮蔽物を先に描く代わりに、前のフレームの深度バッファを再利用する方法もあります。カメラが速く動くと、一瞬物体が欠けることがあるので、もう一度確かめる工夫をします(2 段階の遮蔽カリング)。
  • 包囲体はゆるめで安全:包囲体が小さすぎると、見えている物体を消してしまいます。少し大きめの方が安全です。
  • 遮蔽物は単純な形で:遮蔽の判定用には、見た目のメッシュではなく、内側に収まる単純な形(箱など)を使います。
  • カリングの手間にも注意:小さな物体を 1 つずつ判定するより、まとめた単位で判定する方が速いことがあります。

つまずきやすい点

  • 影が消える:画面の外にある物体でも、影は画面内に落ちることがあります。影を描くときは、光源から見た範囲でカリングします。
  • 大きな物体の中心だけで判定:中心が画面外でも、端が画面に映っていることがあります。必ず大きさを含めて判定します。
  • 遮蔽カリング自体が重い:遮蔽物が少ない開けた場所では、遮蔽カリングの手間の方が大きくなることがあります。場面に応じて使い分けます。

デモで試すこと

  1. 左の青いカメラから見える範囲(扇形)と、700 個の物体があります。「視錐台 + 遮蔽カリング」では、緑が描く物体、灰色が視錐台の外、紫が壁に隠れて外した物体です。
  2. 右下のグラフは、壁だけを描いて作った「方向ごとの一番手前の距離」(深度バッファ)です。壁のある方向では距離が短くなり、その奥の物体が外されます。
  3. 「視錐台カリング」だけにすると、壁の後ろの物体も描く対象に残ります。「なし」では 700 個全部を描きます。左下の数で比べてください。
  4. 「カメラを振る速さ」を変えると、見える範囲と隠れる物体が入れ替わっていく様子を見られます。

参考資料

Unity ComputeShader ↗

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