UnityのOcclusion Cullingの機能を使って3D空間を効率的に描画する
- Occlusion Culling
- OccluderとOccludee
- Smallest OccluderとSmallest Hole
- Occlusion AreaとOcclusion Portal
- Occlusion Cullingがあんまり効かないケース
- 参考
Occlusion Culling
Occlusion Cullingとはオブジェクトが遮蔽物に隠れていた場合にオブジェクトを描画しない機能です。下のように、遮蔽物で隠れているオブジェクトを描画しないようにします。
Unityは基本機能として錐台カリングを行います。これにより、画面外にあるモデルの描画をスキップします。しかし、壁の向こうのオブジェクト等のような、視錐台内に含まれるオブジェクトは描画してしまいます(ピクセルは塗りません)
描画の内容はFlame Debuggerで確認する事ができます。下の図では、実際は画面は赤い壁で覆われているのですが、壁の向こうのクェリーちゃんの耳パーツが描画されている事が確認出来ます。
こういった無駄な描画をスキップする際にOcclusion Cullingは有効に機能します。OcclusionCullingで事前に見える場所・見えない場所を計算しておく事で、非常に効率的に視界内のオブジェクト一覧を引っ張りだすことが出来るみたいです。
ちなみにこのOcclusion Cullingは Umbra Softwareの提供するライブラリを使ってるとか何とか。
Occlusion Cullingを設定するには、コンポーネントに表示されるモデルは、Occlusion Cullingでどんどんカリングされます。(設定しないならチェックを外しとくと良いかもしれません)
でウィンドウを開いてベイクするだけです。そうすればOcclusion Cullingにチェックが入っているカメラファイルはシーン名と同じフォルダに配置されるので、シーンファイル(.unity)が必要です。
OccluderとOccludee
OccluderとOccludeeについてです。先日リパブリックデモを見た際、何故か殆どのオブジェクトがOccludeeが設定されており、Occlusion Cullingが設定されていたにも関わらず遮蔽物が機能していませんでした。
まずOccluderですが、これはOcclusion Cullingの遮蔽物として機能します。要するに、Occluderの設定されているオブジェクトがオブジェクトを遮る場合、その先のオブジェクトは描画されなくなります。(当然、Staticなので動かせない事が前提です)
ちなみにシェーダーにTransparent(透過)属性のあるものを選択している場合、Occluderとして機能しないっぽいです。
ではOccludeeは何かと言えば、Occlusion Cullingでカリングされる側のオブジェクトです。例えば、透明なオブジェクト等が該当します。事前計算する事で、計算回数を減らしてパフォーマンス向上させるといった感じでしょうか。
全部のオブジェクトにOccluderを設定するのが一番手っ取り早い方法ですが、実際は必要な壁のみOccluderを設定し、それ以外はOccludeeを設定するのがパフォーマンス的には一番良さそうです。
Smallest OccluderとSmallest Hole
Smallest Occluderは最小の遮蔽物単位、Smallest Holeは最小の覗き穴単位です。順を追って確認していきます。
Smallest Occluderで設定したサイズは遮蔽物の最小単位になります。例えば1と指定すると、視界判定に使用するグリッドの大きさは大体1になります。これにより、それよりずっと細かいオブジェクトは無視されるようになります。
下の画像は、Smallest Occluderが3くらいに設定した場合です。
Smallest Holeは穴の大きさです。隙間があった際に、どのくらいのサイズの隙間なら覗けるかといった事を表現します。この隙間がSmallest Hole以上なら覗きこんだ先にオブジェクトが表示されるし、以下なら非表示になります。
これらは細かければ細かい程に綺麗なモデルの抜き取りが期待出来るのですが、細かければ細かい程パフォーマンスに悪影響を与えます。またベイクするのに時間がかかります。
パフォーマンスとビジュアルを天秤にかけつつ調整するのが良さそうです。なお調整する際は大きな値から小さくしていくのが良いそうです。実際、Smallest Occluderの初期値の5は割と大きい値なんじゃないかと。
Backface Thresholdは、自分の理解ではポリゴンにカメラがめり込んだ際にもカリングするかどうかの閾値です。100ではカリングしてしまいます。
Occlusion AreaとOcclusion Portal
Occlusion Cullingはそのままだと全体に対して同じ精度でかけます。しかし実際は細かく設定すべき場所と、荒くても良い場所があります。下の画像は広い広場のようなスペースが有りますが、他と同じようにグリッドが入っています。
そういった場所はOcclusion Areaを設定します。Occlusion Areaがあると、その部分は細かく、それ以外は適当に設定してくれるようになります。
今ひとつ何の役に立つのかわからないのが、Occlusion Portalです。このコンポーネントが指定する範囲内にあるオブジェクトは、Occlusion PortalがOFFの場合に非表示になります。
推測ですが、Occluderの設定が難しい場所で一切見る必要の無い物…例えば違う部屋等を、この機能を使ってサクっとOFFにしているのではないかと思います。
Occlusion Cullingがあんまり効かないケース
割と手軽で便利なOcclusion Cullingですが、あまり効果が出ないケースが有ります。例えば以下の様なケースです。
このマップは赤い線の部分が視界の範囲なのですが、視界外…例えばカメラの後ろのモデルも残ってしまいます。
何故こうなるかと言うと、このマップは区画単位でメッシュを結合して表現しているためです。OcclusionCullingはメッシュ単位で描画のON/OFFを行うため、視界の一部にメッシュが含まれてしまっているこのケースでは上手く機能していない訳です。
モデルを結合するのはGameObjectの数を減らし描画・CPU的にも良い手法だと思いますが、それによって描画のスキップが出来なくなる可能性も出てきます。特に広大なステージではカリング出来ない事が高負荷になったりするので、状況次第で使い分けるのが良さそうです。
参考
utomate(Bake Occlusion Culling)
Occlusion Culling in Unity 4.3: The Basics – Unity Blog
Occlusion Culling In Unity3D-Pro Tutorial - YouTube
GPU Gems - Chapter 29. Efficient Occlusion Culling