テラシュールブログ

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

【Unity】Particle SystemにLODを適応してみる

何となく思いついて、LODをパーティクルに適応したところ、出来てしまいました。何の役に立つのかと思ってみましたが、これが思いの外有効そうです。

 

例えば複数の演出で成り立っているパーティクルの場合、距離に応じて演出を追加していくのもアリかもしれません。

下の場合、LOD0は7個のパーティクルから成り立っていますが、LOD1は4個、LOD2は2個のパーティクルまで削減しています。

f:id:tsubaki_t1:20180204013849g:plain

他のもいくつか使いみちがありそうですが、同時に機能しないどころかパフォーマンスを悪化させるケースもあります。

今回はソレについて紹介します。

 

目次

 

LODとパーティクル

LODは御存知の通り、距離に応じてポリゴンやモデルを切り替える仕組みです。PC上で処理出来るモデルには限界があり、10km先のモデルに対して1m先と同じデティールを使用することにそれ程意味はありません。
なので、LODを使用して距離に応じてポリゴンを削減した簡単なモデルに切り替える事で、色々と節約する訳です。。

f:id:tsubaki_t1:20180203234736g:plain

 

このLODの仕組みですが、どうやらレンダラーに対して行えるらしく、好奇心からParticle Systemに対して行った所、見事に使用できてしまいました。

 

例えば下のパーティクルでは、LOD0では毎秒1000のパーティクルが、LOD1では毎秒100のパーティクル(ただし少し大きい)で表現しています。距離が近ければ細かく表現されてて欲しいですし、離れていれば密度さえあれば良いという考えです。
また一定以上の距離がある場合は非表示にも出来ます。

f:id:tsubaki_t1:20180203235227g:plain

 

また、遠距離はビルボード、近づけばメッシュベースのパーティクルといった形で使い分ける事も面白いかもしれません。

Instancingが出来るようになりましたが、GPU上の負荷で考えるとビルボードは出来るだけ採用したい所です。

 

Particle SystemにLODを設定してみる

今回は離れたらビルボード、近づいたらメッシュのパーティクルを作ってみます。

 

まずパーティクルシステムを二つ作成します。

パーティクルは同じくらいの大きさが望ましいです。

f:id:tsubaki_t1:20180204000331j:plain

 

後は普通にLODにパーティクルを設定します。

 

適当なオブジェクトにLOD Groupを追加して、LOD0にメッシュのパーティクルを、LOD1にビルボードのパーティクルをセットします。

f:id:tsubaki_t1:20180204001945j:plain

パーティクルは必ずLOD Group以下のオブジェクトに設定、位置は出来れば同じ位置にするとやりやすいです。

 

これでゲームを再生すると、遠距離ではビルボード、近づくとメッシュのパーティクルが表示されます。(わかりやすくするため、ビルボードは赤に変更しました)

f:id:tsubaki_t1:20180204002230g:plain

なお、切り替わるのはパーティクルシステム毎であり、パーティクル毎ではない事に注意です。

 

で、パフォーマンスは?

このアプローチで気になるのはパフォーマンスでしょう。

 

描画負荷は削減される

単純な描画負荷という点では、確実に削減されます。
主にGPUと、CPU->GPUの辺りについての部分です。

 

パーティクルを105000程出した状態でLOD0とLOD1を切り替えてみた所、下のように描画負荷とレンダリングスレッドが大幅に下がりました。

f:id:tsubaki_t1:20180204003552j:plain

 

パーティクル自体のパフォーマンスはprocedural modeなら効率化

気になるパーティクルのモジュール自体の負荷ですが、これは若干条件があります。

というのも、パーティクルシステムはnon-procedural modeが入っているとカメラ外に行ってもパーティクルシステムの動作を止めないといった動作があるらしく(例えばColliderで跳ね返った位置などを毎回全パーティクルに対して精査するのは負荷が高いのでカリングしないようにした)、non-proceduralmodeが有効な場合はLODに関係なく全てのパーティクルの計算が計上されます。

 

逆を言えば、procedural modeな場合、他のLODのモジュールは動いてないですし、Cullでカリングされたパーティクルシステムはキッチリと停止します。

f:id:tsubaki_t1:20180204010758j:plain

 

procedural modeの場合、LOD cullになるとキッチリと動作が停止します。

左がパーティクルを表示している状態、右がLOD cullで非表示になった状態です。

f:id:tsubaki_t1:20180204005849j:plain

non-proceduralmodeの場合、LOD Cullで描画こそ停止しますが、パーティクルの計算や位置のアップデートが継続して行われます。
つまり場合によっては余計な負荷がかかります(全てのパーティクルがnon-proceduralmodeの場合は、非表示のエフェクトも計算されるため)

f:id:tsubaki_t1:20180204010219j:plain

どうしてもnon-proceduralmodeを使いたい場合、CullingGroupでサクッと画面外のParticleSystemを停止するのが良さそうです。

 

LODよりCullingGroupの方が良いかもしれない

パーティクルとLODですが、どうもLOD判定用のバウンディングボックスが常に更新されるらしく、かなり負荷になるみたいです。

そのため、大抵の場合はCulling Groupを用いてパーティクルを切り替えるのが良いかもしれません。

 

感想

LODを利用してパーティクルの切替を試してみたら出来たので、色々と検証してみました。

このアプローチは焚き火や滝の水ハネといった固定的な表現でも問題なく、かつステージにある…といった物に対して有効かもしれません。

単純にモデルを差し替えるとかではなく、距離に応じて段々と演出を追加していくとかもアリかも。

 

関連

non-procedural modeに関するリスクを説明している記事

blogs.unity3d.comLODについて

tsubakit1.hateblo.jpかなり有益だと思うけどあまり使われてない印象のCullingGroupという機能

tsubakit1.hateblo.jp