BlenderとUnityで作ったものをVR(Meta Quest/Oculus Link)で動かします

ブログの女の子を作る #37 Unityの街をMesh Bakerとオクルージョンカリングで軽くする【Unity】

 
前回の記事では、風魔法でスカートをめくれるようになりました。
 
キャラクターのアクションも増えたので、今回はUnityの世界に「」部分を増やすことにしました。
 
購入したアセットで作った街をOculus Linkで歩いてみると、描画が遅くて全体的に重い感じがします。ステージが山と池だけの時はここまで遅くなかったので、街を増やしてメッシュの数が増えたのが原因なんですが、数を減らさずになんとか高速化したい。
 
ネットで調べてみると高速化の方法はいろいろありますが、オブジェクトのメッシュを一つに結合して負荷を下げる「Mesh Baker」と見えないところを描画しない「オクルージョンカリング」がすぐにできて効果が高いらしい。
 
早速試してみたところ、かなり負荷が下がりました!
もっと早くやっていればよかった。。。



(1) 街のアセット買いました

山とか池はTerrainで作れますが、街を自力で作るのはかなり大変です。アセットストアを探していると、とても良いアセットを見つけたので速攻で購入しました。
 

1つ目「Town Constructor Pack」

1つ目の街アセットです。
購入時は税込みで $5.49 でした。
 
Constructorという名前の通り、街を作るためのオブジェクトがたくさん入ってました。その部品だけでなく、組み立て後のビルや道路、サンプルの街も準備されてます。しかもクオリティがとても高い!
 
街の中には、パーティクルシステムを使った「ビル屋上の煙」や「地面の通気口から出る風」が表現されてるのも面白い。何かが動いてると楽しいですね。
 
LOD(Level of Detail)」には未対応ですが、この価格なら十分でしょう。
 

2つ目「Town Constructor 3」アセット

2つ目の街アセットです。
購入時は運良く50%セールの対象品だったので、税込みで $9.90 でした。
 
少し歴史を感じるようなレンガの街で、先ほどのアセットの続編になります。
こちらのアセットは一部のビルがLOD対応なので、オブジェクトから遠ざかった時の負荷を下げることができそうです。
 

(2) 山のステージと2つの街をつなげる

既に作っていた「山と池のステージ」に2つの街アセットをつなげて、道路や細かなところを整備していきます。
 

Terrainの土地を広くする

これまでに作ったステージです。
これに街をつなげていきましょう。
 
微妙に地面が足りなさそうなので、Terrainの「Create Neighbor Terrains」でエリアを増やしておきます。
とりあえず、3エリア分くらい増やしておきましょうか。
 

1つ目の街をつなげる

まずは1つ目の街をつなげていきます。
 
街への道を作るために、山を削っていきます。
 
通路上の木を消すと、池からもビルが見えるようになりました。
ずっと山ばっかりだったので、景色が変わるのは新鮮ですよ。
 
道路上のブロックは邪魔なので削除しておきます。
アスファルトもなかなかリアルですね。
 

もう1つの街もつなげる

左側に、もう一つの街をつなげていきます。
位置はこのあたりが良さそうです。
 
街の周りをにしてみました。
池で使ってた「VRWaterShader2」アセットを広げて、Terrrainの地面を掘っただけですが、島感が出てきましたよ。
 
街の木はTerrainの木に変えました。
この木はLOD対応なので、少しは負荷が下がることを期待してます。
 
入り江も作っておきましょう。
Fallout4のクラフトで拠点を作ってる時にも思いましたが、街を作るのはとても楽しい。
 

街ができた!

その後、更にTerrainの木を増やしたり、道路の立体交差部分を削除したりしてアレンジを加え、街ができました!
 
どちらのアセットにもサンプルシーンがあったので助かりましたよ。
サンプルの街がちょうど良いサイズでしたので、ほとんどそのまま使わせて頂きました。
 
1つ目の街には、道路近くにTerrainの木を生やしました。
緑があるだけで安心感が出る不思議。
 
こちらは2つ目の街です。
元々あった道路をすべて削除して、1つ目の街と同じ道路にしてみました。同じ道路の方が統一感がありますね。
 
これで街部分が完成です。
 


(3) 「Mesh Baker」アセットでメッシュ結合する

街はできましたが、記事の最初に書いたように街の中を歩くとやけに重い。なんとか改善していきましょう。
 
まずは、Mesh Baker を使ったメッシュ結合です。
 

改善前のパフォーマンスを調べる

いまの状態を「Statistics」で測定してみます。
画面真ん中の下にあるのは「Profiler」ですね。
 
Batches: 1928
・Saved by batching: 23312
・Tris: 2.4M
・Verts: 3.3M
SetPass calls: 1593
・Shadow casters: 2228
 
BatchesSetPass calls の数が小さいと負荷が低い状態、ということになるらしい。今はかなり高いようですね。
 

ビルのメッシュが多い!

今回購入したビルアセットはとても良いんですが、パーツがかなり細か作られています。
細かい分、いろんな形のビルを作れるんですが、描画負荷という面では不利になってしまいます。例えばこのビルの場合、70個のパーツでできてました。
 
これをメッシュ結合すると、描画するオブジェクトが「1個」に減ります。頂点数は同じですが、描画回数が減るので負荷も減る、という感じですね。
 

無料版が使えました

今回は無料版の「Mesh Baker Free」を使いました。
無料版は頂点数上限が64kという制限はありますが、このビルアセットでは問題なく使えました。
 
Mesh Bakerには「メッシュ結合」機能だけでなく、「テクスチャ結合(アトラス化)」の機能もありますが、街のアセットは既にテクスチャがまとまってましたので、今回は使ってません。
 

メッシュをまとめる単位を決める

メッシュをまとめるのは、「1つのビル」単位にしました。
 
もっとたくさんのビルを一つにまとめると効率が良い気がするんですが、まとめ過ぎると逆効果になります。
例えば、街内のすべてのビルを「1つのオブジェクト」にメッシュ結合してしまうと、記事の後半で説明する「オクルージョンカリング機能」でカメラで見えてるところだけを描画する際、ビルが一つでも範囲に入るとすべてのビルが描画されるので、負荷が上がってしまいます。
 
とはいえ、ビル1個ではなく2,3個まとめて結合した方が良かったかも知れませんね。2,3個まとめたとしても、カメラが見える範囲で「描画するビルの合計数」はそこまで大きくは変わらないハズですので。。。
あと、単純に1個1個結合するのが面倒だったということもありますが。
 
ちなみにですが、「Town Constructor 3」アセットには「LOD対応のビル」がありますが、今回はメッシュ結合してません。低解像度と高解像度のビルを個別に結合して再登録する必要があり、手間がかかりそうでした。
 

Mesh Bakerでメッシュ結合する

試しに、このビルをメッシュ結合してみましょう。
メッシュ数は31個。これを1個にまとめてみます。
 
hierarchy で右クリックして、「Create Other -> Mesh Baker -> Mesh Baker」を選択すると、「MeshBaker (0)」というオブジェクトができます。
 
このオブジェクトを選択し、Inspectorの「Open Tools For Adding Objects」をクリックすると、ウィンドウが開きます。
ウィンドウ内の「Search For Meshes To Add」タブを選択し、「Exclude meshes with out-of-bounds UVs」のチェックを外しておきます。
 
この状態で、hierarchy上の「メッシュ結合したいビル」のオブジェクトを選択し、先ほどのウィンドウの「Add Selected Meshes To Target」をクリックします。
 
すると「MeshBaker (0)」オブジェクトの Inspector に、結合されるメッシュが一覧表示されます。
画面右の一覧、「Custom List Of Objects To Be Combinded」部分ですね。
 
あとは「Bake」ボタンを押すだけです。
 
[2020/12/03追記]
Outputの設定は、デフォルトの「Bake Into Scene Object」を使っています。この設定の場合、シーンデータ内にMeshデータが残らないので、他のシーンにオブジェクトをコピー(移植)することができません。もちろん、シーン内だけで使う場合は問題ないですよ。
 
Bake Into Prefab」を使うとMeshデータをPrefabに出力できるのですが、試したところ、なぜかオブジェクトの位置が元の位置から変わってしまいました。今回のように「オブジェクトの位置は変えずにメッシュ結合だけしたい」場合には少し使いにくい。
結合するメッシュ数もそこまで多くないので、今回は「Bake Into Scene Object」を使ってます。
 
結合後のオブジェクトは「MeshBaker (0) Building1_3-mesh-mesh」のような名前になってます。
名前が長いので、リネームすると管理しやすいですね。
 
こんな感じでメッシュ結合していくんですが、少し操作がややこしい。。。
何個か結合してると操作は慣れるんですけどね。
 

同じMesh Baker のオブジェクトを再利用する場合

[2020/12/03追記]
ここでは、Mesh Bakerのオブジェクトを再利用してますが、良く考えてみると再利用する意味はあまりありませんでした。Mesh Bakerのオブジェクトを何個かコピーしておいて、使い終わったら削除する、で良いですね。
 
こんな感じでメッシュ結合していくんですが、同じMesh Bakerのオブジェクトを使いまわそうとすると、変なエラーが出たり、前回作業したビルの「結合済みオブジェクト」が上書きされてしまうことがありました。一つのMesh Bakerオブジェクトで結合できるのは一回だけ、という可能性もありますが、Mesh Bakerのオブジェクト数が大変なことになるので、そういうわけでも無さそうです。
 
とりあえず、これを回避する方法です。
 
メッシュ結合した後で、「Output -> Mesh (-xxxxx)」を選択します。
いまは空になってますね。
 
「None」を選択します。
 
Mesh欄が「None (Mesh)」に変わりました。
これで、同じMesh Bakerオブジェクトで再度ベイクできるようになったはずです。
 
そもそも使い方が間違っているのか、私の環境がおかしいのかはわかりませんが、あとから購入したた有料版のMesh Bakerでも同じ現象がおきたので、Free版だからというわけではなさそうです。
 
とりあえずこの方法で回避できるのでOKとしましょう。ベイクするたびにこの操作が必要なのは面倒ですが。。。
 

描画の負荷が下がった!

ほぼすべてのビルをメッシュ結合した状態で、パフォーマンスを確認してみます。
 
・Batches: 1928 → 1443(25%減)
・Saved by batching: 23312 → 13707
・Tris: 2.4M → 2.5M
・Verts: 3.3M → 3.5M
・SetPass calls: 1593 → 931(42%減)
・Shadow casters: 2228 → 1359
 
Statisticsの数値を見てみると、Batchesが25%、SetPass callsが42% 減りました
見た目は何も変わらず、負荷だけが下がるのはうれしい。ただ、Tris(三角形ポリゴン)とVerts(頂点数)は増えないと思ってましたが、若干増えてますね。謎です。
 

(4) オクルージョンカリングで余分な描写を止める

次は、オクルージョンカリングです。
 
この機能を使うと、カメラが見えていない個所を描画しくなるので、単純に負荷を下げることができます。
 
そう言えばUnityを始めて間もない頃、オクルージョンカリングという設定を見た記憶があります。UnityEditorの Inspectorタブの近くにある「Occlusion」ですね。当時はどういう機能か良く分からずに、何も設定せず放置していたのでした。やっと使う日が来ましたよ。
 

「occluder static」と「occludee static」にチェックを入れる

設定は簡単です。
 
まず、止まっていて動かないオブジェクトの「occluder static」と「occludee static」にチェックを入れます。
ビルや道路・ベンチなどオブジェクトですね。
 
ここで、「occluder static」はカメラの視界を遮ることができる大き目のオブジェクト、「occludee static」は遮られた時に描画されなくなるオブジェクト、に設定するようですが、面倒なので両方にチェックを入れてます。
 
ついでに「Batching Static」にもチェックを入れておきました。オクルージョンカリングの設定とは別ですが、これをオンにすると、画面を描画する際にまとめて処理してくれるので、負荷が下がるらしい。
 

「Occlusion Area」で島を囲む

次に「Occlusion Area」を設定していきます。
オクルージョンカリングを実行するエリアを決める設定ですね。
 
hierarchy の適当な場所で右クリックして、「Create Empty」を選択し、空の GameObject を作成します。これを「Occlusion Area」などの名前に変更しておくと、後から見た時に分かりやすいですね。
 
あとは、「Add Component」で「Occlusion Area」を追加して、オクルージョンカリングしたいエリアを「薄い緑の立方体」で囲みます。
 
島全体を囲むと、こんな感じになりました。
 
立方体のそれぞれの面に、小さな「緑色の円柱」が付いてるのでそれをつかんで移動するのが楽ですね。
 

「Bake」ボタンを押す

これで準備ができました。
 
Occlusionタブ」のすぐ下にある「Bake」を選択し、画面右下の「Bake」ボタンをクリックします。
パラメータはデフォルトでも良いですが、オクルージョンの最小サイズを決める「Smallest Occluder」は「3」に変更してます。
 
ベイクが始まりました。
この青いフレームが少しずつ増えていく感じが面白い。
 
ベイク完了です!
 
この状態で「Visualization」を選択すると、「カメラから見えていて、描画されたオブジェクト」だけ表示されてることが分かります。
Terrainで作った山部分も、カメラから見えてない部分は描画されてません。ちゃんと機能しているようですよ。
 

「Occlusion Area」を設定しない場合

実は「Occlusion Area」設定は必須ではありません。
 
設定しなくてもベイクできるのですが、設定しない場合、オブジェクトが無い場所を細かく青いフレームで区切ろうとしたり、逆にビルなどがたくさんあるのに粗いフレームで区切ってしまったりする場合があるようです。
 
一度、「Occlusion Area」をClearしてベイクしてみました。
島があるのは「画面右上部分」だけなんですが、もっと広い範囲が細かく設定されてしまいました。ちょっともったいないですね。
 
島部分だけを「Occlusion Area」設定すると、良い感じの結果になりました。
オブジェクトが無い個所は、かなりフレーム粗くなってますね。これなら余分な処理は発生しなさそうです。
 

描画の負荷が更に下がった!!

再度、パフォーマンスを確認してみます。オクルージョンカリングは、カメラの位置や角度で描画負荷が変わるので、これまでと同じ場所で計ります。
 
オクルージョンカリング機能でカメラが見えている範囲を「緑色の線」で表示するとこんな感じ。
カメラの視野角は意外に広いことが分かりました。
 
早速、Statisticsの値を確認してみましょう。
 
・Batches: 1928 → 1443 → 1073(最初の値から45%減)
・Saved by batching: 23312 → 13707 → 7504
・Tris: 2.4M → 2.5M → 2.0M
・Verts: 3.3M → 3.5M → 2.7M
・SetPass calls: 1593 → 931 → 716(最初の値から55%減)
・Shadow casters: 2228 → 1359 → 1490
 
更に描画負荷が下がりました!
 
メッシュ結合による負荷低下分を合わせると、Batches と SetPass calls の値が半分にまで下がりました。オクルージョンカリングではカメラが見えない部分を描画しないので、Tris と Verts の値が減ってるのもうれしいですね。Shadow casters は増えてますが、誤差範囲ということにしておきます。
 
しかも、FPSが上がってきてるような気がします。これまでは40FPS前後だったんですが、タイミングによっては50FPS前後出てますね。FPSはなかなか上がらなかったのでかなりありがたい。
 

ビルの前では負荷が超低い

カメラを移動して、ビルの前に立ってみました。
 
・Batches: 1928 → 1443 → 1073 → 198
・Saved by batching: 23312 → 13707 → 7504 → 706
・Tris: 2.4M → 2.5M → 2.0M → 456.6k
・Verts: 3.3M → 3.5M → 2.7M → 516.8k
・SetPass calls: 1593 → 931 → 716 → 83
・Shadow casters: 2228 → 1359 → 1490 → 785
 
ビルしか見えてない状態ですが、負荷が非常に低くなりました!
FPSも数字上では 142.8FPS とかなり高い。
 
これなら、例えば室内にカメラがある状態であれば、室内で見えているオブジェクトだけの負荷で済みそうですよ。
 


(5) 動画で見てみる

Statisticsの値だけでは分かりにくいので、実際に Oculus Link で街を歩いてみましょう。
 
最近、長い距離を移動するために「ワープ機能」を追加しました。まだ、Time.deltaTimeを使った時間制御(一定時間で動く距離を一定にする)は実装してないので、純粋に「処理が速ければ速く動ける」ということになります。
 
9回分ワープするのにかかった時間を計ってみました。
 

#1 何も設定しない状態

まずは、何も設定しない(Mesh Bakerとオクルージョンカリングを設定する前)の状態です。
 
10.3秒」かかりました。描画が遅すぎて、一瞬ビルや道路がブレてるようにも見えますね。これではワープ機能があっても街の中を移動するのはつらい。
 

#2 Mesh Bakerとオクルージョンカリングを設定した場合

Mesh Bakerとオクルージョンカリングの両方を設定した状態です。
 
5.1秒」とほぼ半分の時間になりました!描画時のブレも減ってます。
 

#3 Mesh Bakerとオクルージョンカリングを設定した場合(ビルドしてexe実行)

ついでに、ビルドした時の速度が知りたくなったので試してみました。
 
2.5秒」と更に半分の時間になりました。UnityEditor上で実行するのとは違い、ビルドするとかなり速くなりますね。
 

まとめ

Unityで作った街が重かったので、メッシュ結合とオクルージョンカリングで軽くしてみました。
手間がかからない割には効果が高かった良かったですよ。
 
これで街の負荷が下がりました。
次は、キャラクターの描画負荷を下げたいですね。
 
スポンサーリンク

コメント

  • トラックバックは利用できません。

  • コメント (0)

  1. この記事へのコメントはありません。

ブログの女の子を作る #36 パーティクルとコライダーの風魔法を当てる【後編】【Unity】

ブログの女の子を作る #38 テクスチャベイクとマテリアル共有でUnityの負荷を下げる【Unity】


最近のコメント

だーしゅ
IT関係のお仕事してます。
3Dモデルの女の子は「ブログノ・スージー」。VRは楽しいですね。

[当ブログについて]