だらけ者だらけ

だらけ者だらけの遊び場

UE4のOcclusion Cullingで良く聞かれる質問2 Occlusion Cullingによりオブジェクトが1フレーム消失することがある

この記事は UE4 Advent Calender 2018 その2 の4日目の記事にあたります。

今回のアドカレではOcclusion Cullingについて説明していますが、長くなったため2つに分割しました。こちらはその後半になります。

  1. 前半: Occlusion Culling自身の処理負荷を減らしたい
  2. 後半: Occlusion Cullingによりオブジェクトが1フレーム消失することがある(本記事)

前半でもお伝えしましたが、Occlusion Cullingがどのような仕組みかご存じない方は、まずオフィシャルドキュメントVisibility and Occlusion Cullingを参考にしてみたください。以下の説明では上記ドキュメントを読んだという前提で話を進めてまいります。

Occlusion Cullingによりオブジェクトが1フレーム消えて
パカツク

タイトルの通りなのですが、Occlusion Cullingが原因でオブジェクトが1フレーム消えてパカツいてしまうと、毎月各所からお問い合わせを頂くのですが、そのいずれも以下の二つのどちらかの問題となっていました。

  1. カットシーンなどカメラ切替時にオブジェクトの表示が1フレーム遅れる
  2. 新しくカメラに入ってきたオブジェクトの表示が1フレーム遅れる

これらの根本の原因は、オクルージョンカリングが参照するデプスが1フレーム前のものだからなのですが、今回は原因の詳細は追わず、修正方法をお伝えしていこうと思います。

原因1. カメラ切替時にオブジェクトの表示が1フレーム遅れる

例えばシーケンサーでカメラのカットが切り替わる以下の様なシーンを考えます。壁のアップから広い場面にカットが切り替わった際、キューブが1フレーム遅れて出現するのがわかるかと思います。

f:id:tempkinder:20181202233751g:plain
カメラのカット切替時にパカつく

こちらを修正したのが下のものです。上と比べるとパカ付きがなくなっているのがわかるかと思います。(モーションブラーでわかりにくくなってしまっていてごめんなさい!!)

f:id:tempkinder:20181202233833g:plain
カメラのカット切替時にパカつかない

それでは、具体的な直し方について説明します。

対策1: カメラのカットを切り替える

シーケンサーでカットを分割せずに一つのカメラを1フレームでテレポートさせたりすると、この様にパカついてしまう可能性があります。

f:id:tempkinder:20181202233944p:plain
一つのカメラを1フレームでテレポートさせる例(パカつく)

UE4では、カットが切り替わる瞬間は自動的にOcclusion CullingをOffにします。なので、明示的にカメラのカットを切り替える事でカットをなくすことができます。
(※2022年4月7日追記: 正確には、カメラカットでその前のカメラカットが使うカメラとは別のカメラを指定する必要があります。同じカメラを連続したカメラカットで使っても、ただ高速にカメラが移動しただけというような作りとなってしまうようです。)

f:id:tempkinder:20181202234054p:plain
カットを別々につくりそれらをつなげている(パカつかない)

対策2: カメラが大きく移動したとき、
自動的にOcclusion CullingがOffになるようにする

どうしても同一のカメラでやりたい場合、または単純にカメラの移動量が多くてこの様なパカつきが起きてしまう場合、以下のパラメータが有益かもしれません。この2つの閾値よりもカメラが1フレームで移動した場合、自動的にその瞬間のフレームのOcclusion CullingをOffとしてくれます。

  • CameraRotationThreshold (Default 45.0)
  • CameraTranslationThreshold (Default 1000)

※この2つもCVar化されていないので、動的変更はできませんが、CVar化しても問題はないかと思います。試して頂ければ。

これでも、うまくいかない場合、r.AllowOcclusionQueriesのOn/Offを手動で切り替えるしか道はないかもしれません。

原因2. 画面端から入ってきたオブジェクトがパカつく

以下の様に画面端のオブジェクトがカメラに入ってくる際に、パカパカと1フレーム遅れて出現してしまうことがあります。

f:id:tempkinder:20181202235716g:plain
画面端からオブジェクトが視野に入る際にパカつく
これは本来Occlusion Cullingされないはずのオブジェクトが誤って遮蔽されたと判定されてCullingされてしまうために起こるのですが、こちらもUE4の設定を変更することで修正することができます。
f:id:tempkinder:20181203000157g:plain
画面端からオブジェクトが視野に入ってもパカつかない
こちらの修正方法を見ていきたいと思います。
対策1: 画面に入ってきた瞬間のみオブジェクトのバウンスを一時的に大きくする

UE4は、画面視野の外から中に入ってきたオブジェクトに対して、その入った瞬間のみOcclusionのバウンスを拡大するオプションがあります。

r.ExpandNewlyOcclusionTestedBBoxesAmount (Default =0.0f)

このパラメータはDefaultで0のため無効なのですが、この値を上げることで瞬間的にオクルージョンカリング用のバウンスを大きくしてくれます。このバウンスはフラスタムカリングなどで使われるバウンスとは別で、あくまでオクルージョンカリング時にしか使わないバウンスなので他に影響を与えません。

試しに、ExpandNewlyOcclusionTestedBBoxesAmountを100(1m)に設定し、Occlusion Cullingで使われるバウンスを視覚化してみました。カメラから入ったオブジェクトのバウンスが大きくなっているのがわかるかと思います。(大きくなっているのがわかりやすい様に、拡大する時間を指定するr.FramesToExpandNewlyOcclusionTestedBBoxesも上げています)

f:id:tempkinder:20181203000438g:plain
オクルージョン用バウンスの視覚化
(エンジンに手を入れています。)

このパラメータを上げることにより、誤ってCullingされる可能性を軽減することができます。

おまけ: 常にOcclusion のバウンスを大きくする方法

上記設定は、オブジェクトがカメラに入ってきたタイミングのみBoundsを拡大するものですが、常に拡大させるオプションもあります。

  • ソースコード内部、OCCLUSION_SLOPの値を大きくする
  • r.ExpandAllOcclusionTestedBBoxesAmountの値を大きくする

もしも、前のオプションで効果がうまく出ない場合、最終手段としてこちらを設定するのもありかと思います。実際、処理負荷を注意深く確認して問題ないことがわかったので、このOCCLUSION_SLOPの値を500などに設定してリリースしたタイトルがあると伺っています。


以上です。Occlusion Cullingでパカついていそうな場合、上記を試して見ていだければ幸いです。
ありがとうございました!