ラージシーンの最適化とロード戦略

今回の主な話題：ラージシーンの最適化とロード戦略、Physics2D.ConvertCollision2DForScript最適化、Shaderパフォーマンスコストの検出、NGUIの物理的な衝突検出をオフする。

---
###制作
Q1: ラージシーン（SECTR + Terrain）に関して、いくつか質問があります。

1）SECTRとTerrainを使用してラージシーン問題を解決するモバイルゲーム（PUBGなど）は市場にありますか？その効果はどうですか？または、何かラージシーンに適切な他のプラグインありませんか？

2）Terrainの Draw Callに何か最適化提案はありますか？Terrain自体の木と草のコストはちょっと高いと気付いました。さらに、水平方向視角のときにより多いシーン内の内容が見えますが、何かレンダリングの負担を軽減するための一般的な戦略はありませんか？

3）SECTRの枠組みの下では、マップをブロックに分割するのは簡単ですが、表面の階層化（地面、建築、装飾など）の問題をどのように解決するのですか？ここでのレイヤーは、SECTRにあるSectorの概念と合いません、別次元みたいです。

4）ラージシーンでどちらの方法はLOD問題を解決するために適していますか？SECTRは一つ簡単なLOD案を提供しましたが、Boundに従ってコンポーネント（特にRenderer）のみの表示および非表示をコントロールします。SECTRはGC方面で注意すべき点はありませんか？

5）パフォーマンスから、AssetBundleを使ってサブシナリオを頻繁にロードおよびアンロードします（これにはSECTR_Chunkの変更が必要です）。どうすれば重い状況を減らせますか？

①
>最初に声明します。ブログでSECTRプラグインを推奨しましたが、実際にプロジェクトに使うことはありませんでした。このプラグインへの理解は「プレイしてみました」レベルでしかなく、以下の内容に経験に基づいて推測するものは多いで、ただの参照にしてください。

>1）現時点に、モバイルゲームでSECTR + Terrainを使用しているプロジェクトはあまりないようです。とにかく実際にそうしているプロジェクトは私には知ってありません。その一つ、SECTRがモバイル端末に対して特定の最適化を行っていない可能性があることです。シームレスな世界を構築するほとんどのプロジェクトでは、プラグインを直接使用する代わりに、プラグインを参照して自分で一セットを実現するかもしれません。その二、個人的な経験から言うと、Terrainのコストはモバイル端末で比較的に高いであり、特にUnityのような自分で変更し難い商用エンジンの場合、後期に最適化のプレッシャーが大きくなる可能性があり、ソースコードのない小規模なチームにとっては調整できるのは設定のみです。他のプラグインに関して、私が了解したのはワールドストリーマーです。原理はSECTRと少し違いで、これも参照のみにしてください。これらのプラグインはPCまたはホストプラットフォーム用に実現されていると思います。モバイル端末でも使用できるになりましたが、モバイル端末用にあまり最適化されていない可能性があります。

>2）Terrainの使用に対して、前に私たちのプロジェクトが設立されたときには携帯端末でTerrainを使用することはまだ推奨していませんでしたが、Pubg類ゲームの普及やハードウェアパフォーマンスの向上によって、たくさんのプロジェクトはもう大量にTerrainを使っていますだろう。Guidelineの最適化はこれらの経験豊富な友達に任せて答えましょう。前の考えは、Meshに変更し、そして面を減らすことでありました。植物はSpeed Treeで生成できますが、これのコストは、携帯端末でより高くなります。特にアーティストがコントロールしない場合。GPU Instanceなどの技術を使用してDrawCallを最適化することを試せますが、この分野での経験はあまりないため、これ以上は説明しません。

>水平方向の自由視角はプログラムにとって大事な挑戦です。もちろん、アーティストの作業も非常に多いです。一般的な方法は皆さんもう知っていると思います。より全般的なLOD、ビューイングコーン遠平面の裁断、低性能の効率を確保するために高性能と分けることなど。（LOD方面にもたくさんの巧妙な方法があり、ある状況で遠いところのオブジェクトLODは面を減らすやブランキングためだけではありません。時には遠くの景色の不足を補うために木などのカバーを作ります、近づくとこれは逆に消えます。）

>3）マルチレイヤーの概念は、上記のWorld Streamerを参照できます。これは、距離に基づいてブランキングを行います。layer/tagで地面、大きなオブジェクト、詳しいオブジェクトなどを区別でき、異なるオブジェクトのブランキング距離は異なります。私の印象では、SECTRにも距離ベースのLoaderがあります。満足できない場合は、自分で改造する必要があるかもしれません。

>4）LODは非常に重要なテクノロジーです。うまくいけば、レンダリングだけでなく、実行効率も大幅に向上させられます。うまくいかない場合は、逆最適化することもよく見られます。UnityはLODのためにデフォルトでLodGroupなどのコンポーネントを提供します。原理は君が言うSECTRの方法と同じです。単純な距離と比べて、バウンディングボックスが視野内のレンダリング比に基づいてLODを作るのはより科学的な方法です。ただ、実際な使用中に、距離ほど直感的ではなく、設定やすくない場合があります。LODをうまく実現した場合は、ラージシーンに対して、Streamと組み合わせることができれば、メモリコストやロードおよびアンロードにより適用であります。例えば、遠距離シーンに低LODモデルのみロードすることもできます。一方で、結果の良いLODはアーティストの繊細な調整または設置する必要があり、この中に多くの作業があります。

>LODに対して、技術的な方面はそれほど深くではないかもしれませんが、逆に幅の部分を最適化する時に様々の面が考えすべきです。例えば、Render、Shadow、Animation、ParticleSystem、Material、PostEffectなど、そして高、中、低性能と掛けて一つのマトリックスを生成し、このマトリックスに対してカスタマイズおよび最適化させます。これは、LOD効果が優れているほど作業量が多いことも意味します。

>5）GC方面の欠点、使うことないのでわかりません、回答は使用経験のある友達に任せ、本当に使う前に実際テストをすることを問題主にお勧めします。ただし、GCの領域では、Profile可能なものは基本的に自分で最適化できます。改善できない場合、良い方法もないため、個人的には特に重要ではありません。 （個人的な経験では、ほとんどのプラグインにはGCでの最適化余地があります。特にこのようなより多い要件にサポートしたいもの、プラグインレベルには少し最適化しにくいものがあります。）

>6）重い状況に対して、AssetBundleのロードに基づく私たちの主な最適化方法は、LRUのようなキャッシュを実行することです。メモリの多い設備は多くやりますが、少ない方は少なくやります。プリロードはないため、予測も難しいです。ここで考えすべきのはchunkのセグメンテーションを細かくするか粗くするかです。それぞれに長所と短所があり、プロジェクトの実際状況次第で選択する必要があります。

>たくさん話しましたが、一般的な方法ばかりで、多くの内容は問題主も知っていましたかもしれません。全体から言うと、問題主はSECTRによく知っていますから、プロジェクトの要件と組み合わせて改善および再実現することは大きな問題ではないはずです。原理から言うと、ラージシーンの動的ロードは非常に簡単です（Unityは自分で詳細なシーン管理を行わない場合に基づく）が、実際操作には多くの問題にあう可能性があります。3Dフリーパースペクティブの技術的な挑戦はまだ大きいですから、問題主に応援します。

②
>今までにUWAが最適化した超大地形（8kx8k）のモバイルゲームから見ると、基本的にSECTR + Terrainソリューションを使用するものはありませんが、シームレスなスプライシングのためにすべてMeshに変更します。 SECTRプラグインを使用したことがないため、その分割メカニズムと構成を理解していません。 しかし、Terrainについては、一般的に開発チームは代わりにメッシュを使用する傾向があります。

>Terrainの利点は、編集が非常に便利なことです。一部のプラグイン（Terrain Composerなど）を介して基本的な地形などをすばやく生成できますが、そのDraw Callを制御するのは簡単ではなく、少なくとも直感的ではありません。メモリも同じ複雑さのMeshよりも大きくなります。TerrainDataのロード効率も高くありません。したがって、初期段階でTerrainを使用して地形を編集したチームは、後期によくこれをMeshにエクスポートし、動的にブロックしてロードします。これは現在推奨しているソリューションです。

>シーンのロードでは、AssetBundleの内容は多いではなく、サイズも大きくないなら、今のLoadFromFile+LZ4を介してロードする方法はもう十分早いです。現在の重い状況は通常、AssetBundleのロードではなく、AB.Loadとインスタンス化に発生します。これに対して、有効的な方法は、プリロード、キャッシング、および自分で作るストリーミングロードを行うことによって問題を解決します。前の二つは、他の人はもう詳しく説明しましたから、ここで話しません。ストリーミングロードとは、各フレームでロードおよびインスタンス化されるアセットの数を制御することです。これには、具体的な内容や状況次第で、具体的に分析する必要があり、統一できる規則はありません。

>それ以外、あと何点説明します（これからは話題に離れる話）。

>（1）地形を細かく切りすぎないでください。そうしないと、Cullingとそれに続くエンジンシーンの計画（CreateSharedRenderScene）のコストが増加します。

>（2）超大地形ゲーム（Pubg、Sandboxなど）で、UIモジュールのコストは他のゲーム（MMO、ARPG、カードなど）よりも大幅に低く、これは他のモジュールにより多くの計算スペースを提供できます。

>（3）物理モジュールの時間コストが大幅に増加しています。車などを追加すると、うっかり物理コストが多く増加します。これは開発チームがラージシーンを開発する時によくある新しい問題です。

---
###物理
Q2: Physics2D.ConvertCollision2DForScriptが引き起こしたGCはどうやって最適化できますか？
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/cf8cfb65-f2e1-5bf0-ccac-bb301a165584.png)
設置は下記のようです。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/8b73c251-8f63-d810-e470-1d5141a07fb3.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/444d6b58-3232-55d6-d444-5acff12c9a53.png)
>OnCollisionEnter2Dをコールバックする時、ProfilerにPhysics2D.ConvertCollision2DForScriptのGCが見られます。コールバックする必要がない場合は、スクリプトからこの関数を削除してください。 OnCollisionEnter2Dを使用する場合、このコールバックによって生成されるGCは避けられないようです。公式フォーラムにもこれに関するいくつかの議論があります：https://forum.unity.com/threads/physics-contacts-gc-activity.369625

>もちろん、問題主は自分の衝突検出モジュールを作成することもできます。こちらにPhysics2D.GetContactsインターフェースを使用できます。https://docs.unity3d.com/ScriptReference/Physics2D.GetContacts.html

---
###UGUI
Q3: OnBecameVisibleのコールバックをUGUIで使用できますか？

①
>UGUIのレンダリング規則から見ると、Canvasを単位にして大きなMeshを合併します（異なるDrawCallは異なるSubmeshに対応します）、レンダリングする時もSubmeshに従ってDrawCallを提出します。だから、CanvasRenderコンポーネントは実際に本当のレンダリング単位を表していません。理論的には、バウンディングボックスの概念はなく、OnBecameVisibleは動かないはずです。

②
>まず、UIコントロールの4つの極限値ポイントのワールド座標を計算します。そして、次の方法でCameraのビューイングコーンにあるかどうかを判断できます。

>```ruby:
bool IsVisible(Camera camera, Vector3[] worldPositions)
{
    Matrix4x4 vp = camera.cullingMatrix;
    foreach (var wp in worldPositions)
    {
        Vector4 v = wp;
        v.w = 1;
        Vector4 p = vp * v;
        if (p.w > p.x && -p.w < p.x && p.w > p.y && -p.w < p.y && p.w > p.z && -p.w < p.z )
        {
            return true;
        }
    }
    return false;
}
```

---
###Shader
Q4: Shaderを作成した後、そのコストを正確にテストするにはどうすればよいですか？
>Shaderの消費統計に関しては、一つ方法はツールで詳細な分析を行うことです。例えば、2つのShaderのコストを水平比較しやすいために、明確な指令数を出して比較します。もう一つの考えは、実機で実際の効率の影響によってテストし、本当のシーンに対して最適化効果を検証することです。 簡単な方法は、テストしたい部分にLODを区別し、Debugボタンを配置してLODを切り替え、直接に設備でフレームレートの変化とCamera.Render関数コストの変化を統合します。ただし、実機テストでは、GPU Boundではない場合にはフレームレートの変化を確認できないため、ボトルネックでなければ最適化の優先度を下げることができます。もちろん、バッテリー消費などの方面でまだ向上できます。

---
###物理
Q5: 私のNGUI時間コストは非常に高いです。チェックしたら、NGUIはデフォルトで何か衝突検出機能がつけてあることがわかりました。これはどちらで設定できますか？感謝。
>1）Start方法にあるUIPanelはUICameraのタイプに応じてリジッドボディコンポーネントを自動的に追加するかどうかを判断します。自動追加を回避するように試みることができます。
2）UnityメニューのEdit/Project Settings/Physicsに衝突検出を実行するレイヤーを設定できます。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/b1b7df97-f660-0634-eefb-6fcb7dc6b3e1.png)

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com