レンダリングレベルの設計方法

今回の主な話題：モバイルゲーム開発におけるPBRの適用性、レンダリングレベルの設計方法（発展編）、ハードウェアのGPU Instancingサポートの判断方法、回避する必要がある25個のDrawCall成長問題。

---
###レンダリング
Q1:今はプロジェクトのレンダリングレベルを設計する方法を考えており、誰か経験のある先輩がShaderLODなどの方法を教えてください！他に何かアイデアはありますか？ ありがとうございました！
>私たちのゲームの効果レベル分けの内容を整理しました、参照できます。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/9c022cf7-9b5b-3b55-7110-c5f4e6a29453.png)

---
###レンダリング
Q2: 2017.2.0を使用して一枚のマップをレンダリングしましたが、なぜ時々にXiaomi 4のCamera.Renderは高い時間コストがあります？一つの空きシーンですが、なぜCamera.Renderの時間コストはそんなに高いですか？
>一つの簡単なテストをしてこの問題を研究しました。すなわちシーンに一つCubeのみレンダリングします。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/df9abf6c-1e72-8b30-3008-c4c98dc0bdb7.png)
設備：
（1）Huawei 6Plus
（2）Xiaomi 4

>Profilerのスクリーンショットは次のとおりです。
青枠：Huawei 6Plus
赤枠：Xiaomi 4
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/35ac1ed9-104a-72d3-63fb-f89ea27ef76e.png)
上図から見ると、Xiaomi 4のCamera.Render時間コストは不安定で、時々に10＋msのピーク値は出ます。

>Unity Profilerをチェックしてまたは他の設備と比べると、次の2点はXiaomi 4で時間コストが不安定になる原因であることは分かりました。

>1)Cullingが不安定
下図はXiaomi 4およびHuawei 6Plus設備で、Culling操作の時間コストの比較です。青枠はHuawei、赤枠はXiaomiです。Timelineからは、シーンSceneNodeの計算は原因であることが分かりました。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/75ebe94e-50db-1392-d928-c9c673c161ff.png)
2)Drawingが不安定
レンダリングの時間コストも不安定で、下図のように：Timelineで「Xiaomi 4設備では、メインスレッドのレンダリングプロセスがサブスレッドの完了を待ってから後続の操作を実行することが多いこと」がわかります。しかし、Huawei 6Plusで同じアプリを実行する時この問題はありません。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/2bcbd95c-1c64-f9c3-bfef-f381d4a56371.png)
Xiaomi 4:
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/93551e62-b156-5379-2c58-8a712effdbde.png)
Huawei 6Plus：
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/dfa25fa9-437e-9b26-871f-267ed73bdfdf.png)
上記のテストをまとめします：
●CullingにあるSceneNode計算操作は、Xiaomi 4でより多くの時間のかかるCPUコストを伴うことがよくあります。
●Xiaomi 4でメインスレッドのレンダリングが子スレッドを待つ状況はよくあります。

>上記の2点は問題の主な原因ですが、よりディープな説明は、おそらく携帯メーカーまたはチップハードウェアメーカーと連絡必要があります。ただし、これは簡単なテスト例で、複雑なシーンに適用ではない可能性がありますが、テストまたは分析方法は同じで、問題主が欲しいなら自分でテストして答えを見つけることができます。

---
###レンダリング
Q3: 使用したUnity 5.5シーンにはレベル2のLODがあります。Lightmapを使用してシーンをレンダリングして、結果第二LODモデルがレンダリングされたシャドウ面は真っ黒でした。どうすればよいですか？
>Untiy公式は、バージョン5.5ではLOD Lightmapをサポートしていません。バージョン2017.4でも、公式ドキュメントではLight Probesを使用することをお勧めします。
https://docs.unity3d.com/Manual/LODForBakedGI.html

>もちろんこれも言いました：
“When you use the Progressive Lightmapper, there is no need to place Light Probes around the LOD Group to generate baked indirect lighting. However, to make Realtime GI affect the Renderers in the LOD Group, you must include the Light Probes.”

>私たちもUnity 5.5バージョンも使用していますが、Progressive Lightmapperを試していませんでしたので、効果は分かりません。ですから、一つ目の解決策はUnity 5.6またはUnity 2017にアップグレードして、Progressive Lightmapperを試すことです。
Unity 5.5で実行したい場合は、ベイクされたscaleとoffsetを手動コピーして実現します。つまり、実行時に元モデルの照明マップ情報ををLOD低レベルモデルにコピーすることです。ただし、これには非常に強い制限があります：2つのモデルのUV2が完全に対応できることを確認する必要があります。そうしないと、UV2に混乱が生じる可能性があります。Simpylgonなどのミドルウェアを使用すると、UV2をできる限り変更しないでおくことが保証できます。

>これには2つの問題があります。
●一つのコンポーネントの削除など、多くの面が削減されたモデルの場合、露出した面は以前にブロックされていたため、黒くなります。ただし、ほとんどの場合に削減された面が多いLODモデルは遠く離れており、一般的に納得できます。
●実行時に照明情報を設定するマテリアルは静的にバッチ処理できません。そうしないと、デバイスに問題が発生します。

>もう1つ問題は実行時に変更されるため、エディターモードで設定コンポーネントを実行できるようにしないなら、プレビュー効果が正しくない問題が発生する可能性があります。実行状態では正しいことを保証できます。

>オリジナルのLOD0ベイク効果：
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/76918046-b407-5559-1609-52455fb09c94.png)
LOD1は、黒を避けるためにベイクエフェクトに参加しません。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/39961aee-4cf2-93be-64ee-81e6e0191237.png)
実行時のライトマップパラメーターを変更した効果。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/103531f4-ef6d-36bd-a78d-c5015baf859e.png)
ライトマップパラメーターを変更するComponentコード。

>```ruby:コード
public class RendererLightMapSetting : MonoBehaviour
    {
        public int lightmapIndex;
        public Vector4 lightmapScaleOffset;
        public void SaveSettings(SceneLightMapSetting setting)
        {
            if (!IsLightMapGo(gameObject))
            {
                return;
            }
            Renderer renderer = GetComponent<Renderer>();
            if (setting)
            {
                lightmapIndex = setting.GetGlobalIndex(renderer.lightmapIndex);
            }
            else
            {
                lightmapIndex = renderer.lightmapIndex;
            }
            lightmapScaleOffset = renderer.lightmapScaleOffset;
        }
        public void SetSettings(Renderer renderer)
        {
            if (renderer != null)
            {
                lightmapIndex = renderer.lightmapIndex;
                lightmapScaleOffset = renderer.lightmapScaleOffset;
            }
        }
        public void LoadSettings()
        {
            if (!IsLightMapGo(gameObject))
            {
                return;
            }
            Renderer renderer = GetComponent<Renderer>();
            renderer.lightmapIndex = lightmapIndex;
            renderer.lightmapScaleOffset = lightmapScaleOffset;
        }
        public static bool IsLightMapGo(GameObject go)
        {
            if (go == null)
            {
                return false;
            }
            Renderer renderer = go.GetComponent<Renderer>();
            if (renderer == null)
            {
                return false;
            }
            return true;
        }
        void Awake()
        {
            if (Application.isPlaying)
            {
                LoadSettings();
            }
        }
    }

>```

>そして、アーティストにワンクリックで設定およびクリーニングできる機能を提供します。ロジックは自分で作成できます。例えば、LODコンポーネントを修復する静的照明情報、LODコンポーネントを修復する静的設置など。

---
###レンダリング
Q4: どの場合にTransparentのマテリアルがRender.OpaqueGeometryの過程中にレンダリングされますか？
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/430c3e8d-b9b6-afd5-7064-a3b7daa9bc94.png)
>Render.OpaqueGeometryとRender. TransparentGeometryの執行は、RenderQueue <2450によって区別されています。RenderQueueのサイズは、オブジェクトのレンダリングの順序を完全に制御できます。たとえば、半透明オブジェクトのレンダリング順序を不透明オブジェクトの前に調整しますこと、またはGrassをTerrainの前に調整しますこと。マルチレイヤーテクスチャを使用する一部のプロジェクトでは、 比較的良い選択です。RenderQueueを使用してオブジェクトのレンダリング順序を制御し、RQを変更して特別な目的を実現します。

---
###2D
Q5：以前、私はUWAの動画を見ましたから、このスクリプトをプリセットに掛けました。しかし、今回のテストの結果で解凍する時にこの関数がとても高いヒープメモリを占有していることがわかりました。この関数はアセットが解凍する時にもコールされますか？
![13-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/ba15d7af-320e-8427-e7ce-ab8e4113542d.png)
さらに、昨日UWA GOTを使用して解凍中のヒープメモリの問題を追跡したところ、Webサイトで報告されたPolygonImageの問題が発生していませんでした。これはどうしてですか？
>PolygonImageの実現は一つのMeshEffectとして対応するImageのジオメトリを変更します（四辺形をポリゴンに変更）。過程に一定量のヒープメモリ割り当てが発生します（ポリゴンが複雑になるほど、より多くのヒープメモリが割り当てられます）。
MeshEffectのトリガーは、対応するImageが再構築されたときにのみ発生します：アクティブ化、変更された色（透明度）、変更された長さと幅など。
ですから、大量のヒープメモリが割り当てられますから、この効果を頻繁に変更されるImageに使用することはお勧めしません。

>しかし、問題主はUWA GOTでこれを発見していません。この原因は、PolygonImageを使用する一部のインターフェイスが開かれていない（アクティブ化されていない）可能性があります。

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

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