Unityのシーン上に配置したモデルを結合する
以前、ステージの作り方について紹介しましたが、これには想像の通り問題が一つあります。それは、GameObjectをすごい数要求する事です。
Sample Assetsのプロトタイプアセットを並べて簡単なステージを作ってみよう[Unity] - テラシュールブログ
Unityにおいて初期化時に問題になる項目は3つ、シェーダーのコンパイル、リソースのエンジン登録、GameObjectの構築です。ゲームが本格化するとシリアライズの高速化や別スレッドに逃す事も含まれます。さらに言えば、参照の結合をランタイムで実行してるとコレも問題になりやすいのですが、それは取り敢えず置いておきます。
大量にGameObjectがあるとGameObjectの構築に時間がかかるため、以前紹介した方法でステージを作成すると少し問題となります。Unityのレンダラーは1つのモデルにつき1つのGameObjectを要求するため、ステージを作成するにつれGameObjectの数が膨大になる可能性があり、そこに高いコストの可能性が出てきます。
下の画像は約600個のGameObjectを使用したステージです。
この回避方法は2つ。一つは「動的に構築する」事、もう一つは「事前に結合してしまう事」です。
動的に生成する方法は、事前にステージ構造を取得しておき、「見える部分」を表示するために使用するGameObjectを生成する方式です。Resourcesから非同期でインスタンス化するを「段階的に全部」行う事で、初期コストを何とかします。
これを実現するには、オブジェクトを動的に構築できるエディタ拡張を事前に行っておくか、全てのオブジェクトを別途プレハブにして構築するような設計が必要になります。
Resourcesから非同期でインスタンス化する - テラシュールブログ
もう一つは、メッシュを結合してしまい1つのGameObjectでレンダリング可能にしてしまう方法です。そのためにCombineMeshesを使用します。
CombineMeshesの基本的な使い方 - Neareal
上のサイトを元に、マテリアルが複数あればその分だけメッシュを分割するコードを作成しました。メッシュの親に本コンポーネントをアタッチし、コンポーネントのコンテキストメニューから「Export」を選択すると、新しくメッシュが作成されます。
その際元のオブジェクトにEditorOnly(ビルド時シーンから削除されるタグ)が付与され、Activeがfalseになります。
CombineMeshesを使用してメッシュを結合したのが下の図です。600オブジェクトが3オブジェクトまで縮小しています。また、ドローコールも削減されます。
一度統合したメッシュを再調整したい場合は、先ほどActive=falseになったオブジェクトにチェックを入れて再表示します。そうすると結合したオブジェクトが非表示になり、編集可能となります。
この方法の一つの問題点は、モデル分のアセットが作成される事です。一つ一つのサイズはテクスチャと比べてカスみたいなサイズですが、量が増えてくると少々厄介かもしれません。なので、やはりある程度使いまわす事を前提とした設計が必要になります。
また、あまりにサイズが大きいメッシュを作るのは良くない気がします。単純に超量の多いモデルは失敗しますし、GPUのメモリを使い果たしてしまうような巨大なオブジェクトは何というか良くないです。画面外判定の事もありますし。
またBox Colliderが全て剥がれるので、MeshColliderで当たり判定を作らないと抜けます。
ドローコールを減らす!Draw Call Minimizer - テラシュールブログ
Draw Call Minimizerの使い方と問題について - テラシュールブログ
で、この機能と概ね同じ事をしているのが、以前に紹介したDraw Call Minimizerです。このアセットは、メッシュとマテリアルを結合して一つにします。最近は事前にモデルを変換(しかもOBJに)出来るようになったので、割と使い勝手が良いかもしれません。テクスチャの統合は正直今の環境では邪魔なので、切る方法を聞いてみようと思います。
車輪を再開発した後に調べたら自分のブログが見つかっちゃうってのは悲しいような嬉しいような…