テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

UnityのOcclusion Cullingの機能を使って3D空間を効率的に描画する

Occlusion Culling

Occlusion Cullingとはオブジェクトが遮蔽物に隠れていた場合にオブジェクトを描画しない機能です。下のように、遮蔽物で隠れているオブジェクトを描画しないようにします。

f:id:tsubaki_t1:20150422030957g:plain

Unityは基本機能として錐台カリングを行います。これにより、画面外にあるモデルの描画をスキップします。しかし、壁の向こうのオブジェクト等のような、視錐台内に含まれるオブジェクトは描画してしまいます(ピクセルは塗りません)

f:id:tsubaki_t1:20150422025921p:plain

描画の内容はFlame Debuggerで確認する事ができます。下の図では、実際は画面は赤い壁で覆われているのですが、壁の向こうのクェリーちゃんの耳パーツが描画されている事が確認出来ます。

こういった無駄な描画をスキップする際にOcclusion Cullingは有効に機能します。OcclusionCullingで事前に見える場所・見えない場所を計算しておく事で、非常に効率的に視界内のオブジェクト一覧を引っ張りだすことが出来るみたいです。

f:id:tsubaki_t1:20150422030052p:plain

ちなみにこのOcclusion Cullingは Umbra Softwareの提供するライブラリを使ってるとか何とか。

Occlusion Cullingを設定するには、Window->Occlusion Cullingでウィンドウを開いてベイクするだけです。そうすればOcclusion Cullingにチェックが入っているカメラコンポーネントに表示されるモデルは、Occlusion Cullingでどんどんカリングされます。(設定しないならチェックを外しとくと良いかもしれません)

f:id:tsubaki_t1:20150422233942p:plain

ファイルはシーン名と同じフォルダに配置されるので、シーンファイル(.unity)が必要です。

OccluderとOccludee

OccluderとOccludeeについてです。先日リパブリックデモを見た際、何故か殆どのオブジェクトがOccludeeが設定されており、Occlusion Cullingが設定されていたにも関わらず遮蔽物が機能していませんでした。

f:id:tsubaki_t1:20150422031746p:plain

まずOccluderですが、これはOcclusion Cullingの遮蔽物として機能します。要するに、Occluderの設定されているオブジェクトがオブジェクトを遮る場合、その先のオブジェクトは描画されなくなります。(当然、Staticなので動かせない事が前提です)

f:id:tsubaki_t1:20150422221816g:plain

ちなみにシェーダーにTransparent(透過)属性のあるものを選択している場合、Occluderとして機能しないっぽいです。

f:id:tsubaki_t1:20150422032449p:plain

ではOccludeeは何かと言えば、Occlusion Cullingでカリングされる側のオブジェクトです。例えば、透明なオブジェクト等が該当します。事前計算する事で、計算回数を減らしてパフォーマンス向上させるといった感じでしょうか。

f:id:tsubaki_t1:20150422221909g:plain

全部のオブジェクトにOccluderを設定するのが一番手っ取り早い方法ですが、実際は必要な壁のみOccluderを設定し、それ以外はOccludeeを設定するのがパフォーマンス的には一番良さそうです。

 Smallest OccluderとSmallest Hole

Smallest Occluderは最小の遮蔽物単位、Smallest Holeは最小の覗き穴単位です。順を追って確認していきます。

Smallest Occluderで設定したサイズは遮蔽物の最小単位になります。例えば1と指定すると、視界判定に使用するグリッドの大きさは大体1になります。これにより、それよりずっと細かいオブジェクトは無視されるようになります。

下の画像は、Smallest Occluderが3くらいに設定した場合です。

f:id:tsubaki_t1:20150422223419g:plain

Smallest Holeは穴の大きさです。隙間があった際に、どのくらいのサイズの隙間なら覗けるかといった事を表現します。この隙間がSmallest Hole以上なら覗きこんだ先にオブジェクトが表示されるし、以下なら非表示になります。

f:id:tsubaki_t1:20150422230219p:plain

これらは細かければ細かい程に綺麗なモデルの抜き取りが期待出来るのですが、細かければ細かい程パフォーマンスに悪影響を与えます。またベイクするのに時間がかかります。

パフォーマンスとビジュアルを天秤にかけつつ調整するのが良さそうです。なお調整する際は大きな値から小さくしていくのが良いそうです。実際、Smallest Occluderの初期値の5は割と大きい値なんじゃないかと。

f:id:tsubaki_t1:20150422230327p:plain

Backface Thresholdは、自分の理解ではポリゴンにカメラがめり込んだ際にもカリングするかどうかの閾値です。100ではカリングしてしまいます。

f:id:tsubaki_t1:20150422231107g:plain

Occlusion AreaとOcclusion Portal

Occlusion Cullingはそのままだと全体に対して同じ精度でかけます。しかし実際は細かく設定すべき場所と、荒くても良い場所があります。下の画像は広い広場のようなスペースが有りますが、他と同じようにグリッドが入っています。

f:id:tsubaki_t1:20150422231614p:plain

そういった場所はOcclusion Areaを設定します。Occlusion Areaがあると、その部分は細かく、それ以外は適当に設定してくれるようになります。

f:id:tsubaki_t1:20150422231708p:plain

今ひとつ何の役に立つのかわからないのが、Occlusion Portalです。このコンポーネントが指定する範囲内にあるオブジェクトは、Occlusion PortalがOFFの場合に非表示になります。

推測ですが、Occluderの設定が難しい場所で一切見る必要の無い物…例えば違う部屋等を、この機能を使ってサクっとOFFにしているのではないかと思います。

f:id:tsubaki_t1:20150422232248p:plain

f:id:tsubaki_t1:20150422232256p:plain

Occlusion Cullingがあんまり効かないケース

割と手軽で便利なOcclusion Cullingですが、あまり効果が出ないケースが有ります。例えば以下の様なケースです。

このマップは赤い線の部分が視界の範囲なのですが、視界外…例えばカメラの後ろのモデルも残ってしまいます。

f:id:tsubaki_t1:20150422235307p:plain

何故こうなるかと言うと、このマップは区画単位でメッシュを結合して表現しているためです。OcclusionCullingはメッシュ単位で描画のON/OFFを行うため、視界の一部にメッシュが含まれてしまっているこのケースでは上手く機能していない訳です。

モデルを結合するのはGameObjectの数を減らし描画・CPU的にも良い手法だと思いますが、それによって描画のスキップが出来なくなる可能性も出てきます。特に広大なステージではカリング出来ない事が高負荷になったりするので、状況次第で使い分けるのが良さそうです。

参考

utomate(Bake Occlusion Culling)

Occlusion Culling in Unity 4.3: The Basics – Unity Blog

Unity - マニュアル: オクルージョンカリング

Occlusion Culling In Unity3D-Pro Tutorial - YouTube

GPU Gems - Chapter 29. Efficient Occlusion Culling