モバイルゲーム開発におけるPBRの適用性

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

---
###レンダリング
Q1：私たちはMMOゲームを開発しています。今度は、主人公（他のプレイヤーを含む）にPBR（Untiy自身の標準）を使用したいと思います。他のキャラクターやシーンでは使用しません。パフォーマンスがこの状況に耐えられるかどうかはわかりません。また、今のモバイルゲームでのPBRマテリアルの使用状況も知りたいです。
>現在、モバイルゲームでPBR素材を使用するプロジェクトは、特にMMOやRPGなどのプロジェクトで大幅に増加しており、主人公、NPC、ビッグボスはすべてPBRになっていきます。

>上記の状況でのみPBRを使用する場合、一般的にキャラクターが画面に占める面積は比較的小さいため、Unityエンジンに付属のPBRはパフォーマンスに大きな問題はあまりありません。ストーリーを推進する時、画面に占める面積はより大きいですが、時間は一般的に非常に短いため、全体的なパフォーマンスにほとんど影響はありません。但し、（特にローエンドデバイスで）地形などの画面に大面積を占めるオブジェクトにPBRを使用することは、UWAにはお勧めしません。これは、確かにGPUの圧力は高くなるためです。UWA Day2018でもこの問題に対して定量分析を行いました（下図のように）。開発チームが使用中にこれを注意すべきです。そして、これも自分のプロジェクト次第です、自分が設置したローエンドデバイスでのパフォーマンス表現を確認することをお勧めします。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/39a97c7b-b814-8031-9c21-7301de94e053.png)
最後に、Standard Shaderを使用する場合、パフォーマンスに重点を置くだけでなく、メモリへの影響にも注意を払う必要があります。この文章を参照できます：[「レンダリングレベルの設計方法」](https://qiita.com/UWATechnology/items/9e356d87e490cd84aa36)

---
###レンダリング
Q2：UWA Day 2018大会に「DrawCallの上昇を導く原因は25種あります。」と紹介してくださいましたが、具体的に何かありますと知りたいです。
>バッチ処理が失敗する理由は次のとおりです。

>1.Additional Vertex Streams — 追加の頂点ストリーム—オブジェクトはadditionalVertexStreamsを使用して、追加の頂点情報ストリームを設定しました。

>2.Deferred Objects on Different Lighting Layers — オブジェクトは異なる照明レイヤーにあります。

>3.Deferred Objects Split by Shadow Distance — 2つのオブジェクトの一方はシャドウ距離内にあり、もう一方はそうではありません。

>4.Different Combined Meshes — オブジェクトは別の合併した静的メッシュに属しています。

>5.Different Custom Properties — オブジェクトは異なるMaterialProperyBlockを設定しました。

>6.Different Lights — オブジェクトは異なるフォワードライト（Forward Light）の影響を受けました。

>7.Different Materials — オブジェクトは異なるマテリアルを使用しました。

>8.Different Reflection Probes — オブジェクトは異なる反射プローブ（Reflection Probe）の影響を受けました。

>9.Different Shadow Caster Hash — オブジェクトは別のシャドウキャスティングシェーダーを使用するか、異なるシェーダーパラメーター/キーワードを設定しました。これらのパラメーター/キーワードはシャドウキャスティングパスの出力に影響します。

>10.Different Shadow Receiving Settings — オブジェクトは異なる「Receive Shadows」パラメーターを設定しましたか、一部のオブジェクトがシャドウ距離内にあり、他のオブジェクトは距離外にあります。

>11.Different Static Batching Flags — オブジェクトは異なる静的バッチ設定を使用しました。

>12.Dynamic Batching Disabled to Avoid Z-Fighting — Player Settingsに動的バッチ処理をオフにするか、現在の環境で深刻な衝突を回避するために一時的にオフにしました。

>13.Instancing Different Geometries — GPU Instancingを使用して異なるグリッドまたはサブグリッドをレンダリングしました。

>14.Lightmapped Objects — オブジェクトは異なるライトマップを使用しましたか、同じライトマップ内で異なるライトマップUV変換関係があります。

>15.Lightprobe Affected Objects — オブジェクトは他のライトプローブ（Light Probe）の影響を受けました。

>16.Mixed Sided Mode Shadow Casters — オブジェクトの「Cast Shadows」設定が異なります。

>17.Multipass — オブジェクトは複数のPassを持つシェーダーを使用しました。

>18.Multiple Forward Lights — オブジェクトは複数のフォワードライトレンダリングの影響を受けます。

>19.Non-instanceable Property Set — instancedシェーダーにnon-instancedを設定しました。

>20.Odd Negative Scaling — オブジェクトの拡大縮小は、（1、-1,1）などの変な負の値であります。

>21.Shader Disables Batching — シェーダーは「DisableBatching」タグを使用してバッチ処理を閉じます。

>22.Too Many Indices in Dynamic Batch — 動的バッチ処理のインデックスが多すぎます（32kを超える）。

>23.Too Many Indices in Static Batch — 静的バッチ処理の組み合わせメッシュインデックスが多すぎます。OpenGL ESの場合は48k、OSXの場合は32k、その他のプラットフォームの場合は64kです。

>24.Too Many Vertex Attributes for Dynamic Batching — 動的バッチ処理したいサブメッシュには900を超える頂点属性があります。

>25.Too Many Vertices for Dynamic Batching — 動的バッチ処理したいサブメッシュには300を超える頂点があります。

---
###GPU
Q3:「ES 3.0をサポートできる」と宣伝していますが、実際にはGPU Instancingをサポートしていない国産Android設備はたくさんあることを見つけました。では、ハードウェアがGPU Instancingをサポートしているかどうかをどのように判断しますか？
>SystemInfo.supportsInstancingを使うことをお勧めします。

>https://docs.unity3d.com/ScriptReference/SystemInfo-supportsInstancing.html

---
###レンダリング
Q4:前回の記事[「レンダリングレベルの設計方法」](https://qiita.com/UWATechnology/items/9e356d87e490cd84aa36)の続きに、更に2人の業界の有名人が彼らの見解を共有しました。

①
>王亮：私たちのプロジェクトはまだ開発中であり、同じプロセスを経て、最終的に同様のファイルを作成しました。私の経験では、最終的に生成するのは一つのテーブルであるように感じますが、各携帯機種はこのテーブルによってデフォルト設定を提供できます。但し、これは自分のプロジェクト次第で、ハイ/ミドル/ローエンドモデル、FPSの目標、レンダリング効果の違いにより、結果は大きく違う場合があります。

>私の考えを共有します。

>#####1.先ずは、テストケースを決定することです。
メインシティーや違う戦闘スタイルの最高面数シーンを例として選択します。
![2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/f05d63f9-c16f-2053-1103-f6caeaea7492.png)
#####2.キャラクターに違う戦闘スタイルの最高面数キャラを選択します。
![3-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/082b744b-a2b0-8156-a70d-09e4d29c9e60.png)
#####3.次に、テストステージを設定して、サンプリングスクリプトを書きます。
このテストデータは、スクリプトを使用してフレーム数を記録します。
テスト方法はCheatに統合されており、指定された時間のフレーム範囲と平均フレームをテストして、パフォーマンスを大まかに説明するために使用されます。
フルモンスターレンダリング：主人公は雑魚敵を一周して、テストされた雑魚敵たちを全員集まって、同一画面で全体レンダリングを保証します。
フルモンスタースキル発動：できるだけ多くの雑魚敵を攻撃して、粒子の圧力を確認します。

>#####4.テスターさんに例の組み合わせをテストすることをお願いします。デートを収集します。
第二回のテストレポートを選択して表示します。
実際、その間にいくつかの繰り返しがありました。テーブルの最後の列は、フレームターゲットに対して、配置を繰り返し調整して作成されたデータです。
![4-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/998c562c-83d4-38df-5a31-3ebcac45d62c.png)
![5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/7282943e-4fd4-f368-b3bd-8faff7c03e40.png)
![6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/0892af8e-f34d-cf36-0107-86a7274e67e8.png)
#####5.最後に、テストデータに従って格付け表の配置を調整します。
最終的にできた配置は次のように、赤い部分は今回のテストで調整、および新たに追加した内容です。
![7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/eb16f755-d60d-9d42-7d0f-5b39b131cbe1.png)

>#####そして、このテストで見つかった問題。
1.GPU関連の指標を収集してみて、Androidモデルに対して詳しく格付けをします。（Meizu M721Q CPU3G GPU1Gの場合、高画質を選択すれば20FPS未満になります。GPU指標は格付け標準を決定するのに十分ではありません。）
2.Unity DIを統合して、パフォーマンスの大きなデータを収集し、第1段階の格付け効果を観察して、FPSとメモリ/ GPU /画面サイズの相関関係を観察します。
3.Unity AutoTune SDKを統合して、格付けパラメータの動的配置を実現します。
4.Settingsインターフェースを追加し、王者榮耀を参照できます。PlayerPrefsはローカルに保存されており、ロジックを変更する必要があります。 ZhangWeiZhi、LvFujiaoをキャッチします。 （ロジック部分は完了しました。）
5.WP_02 / 03は01より頂点のみ多くなります。
A：「LOD格付けスクリプトで、鳥や木などのローエンドデバイスで非表示にできるオブジェクトをフィルタリングすることはできます。」をFに指示します。（完了）
B：直接にmeshbakerモデルで圧縮することを試します。（MeshBasker、頂点カラーベーキングプラグイン、SimpleLODリダクションなどのプラグインプロジェクトには適用ではありません。）
6.LODSettingテーブルで特定のAndroidモデルを削除し、iOSデバイスリストを更新します。（完了）

②
>文雅：プロジェクトのLODルールも整理しましたが、問題主が言ったレンダリングレベルに限らずかもしれません。優れたLODシステムには、アーティストがアセットに対して多くのアセット格付け作業を行う必要があり、プログラムが完全なLODフレームワークと補助ツールを作る必要もあります。毎回追加の機能モジュールごとにLODを考慮する必要があります。
####一、プロジェクトのLOD格付けとパフォーマンス基準を決定する方法
LOD（Level of Detail）、こちらの「D」は「Distance」ではなく「Detail」を代表します。つまり、距離に制限されなく、すべてのゲーム画面とゲーム機能の詳細は等級を付けられます。
#####1、パフォーマンス標準は如何やって決定しますか？
等級を付ける前に、目標（省エネルギー/正常的なゲーム体験/得意なこと）を確認する必要があります。どの型番にで実行するパフォーマンス効果と機能、およびどのパフォーマンス目標（フレームFPS、メモリ使用量、Drawcall、 同じ画面上の三角形の数など）。
◆経験のまとめ：
1）画質の表現力とパフォーマンスコストが矛盾している。
2）継続的なメンテナンスが必要であり、関する機能システムのデザインでは、異なる画質を考慮する必要があります。
3）最低画質はプレイアビリティを犠牲して、LODフレームワークの複雑さを増し、最も単純で暴力的な方法を使用して対処します。

>◆互換性の問題：
1）低画質に考慮すべき問題。
8枚以上のテクスチャを定義するShaderをサポートしていない場合があります
ETC2形式のテクスチャをサポートしない場合があります
OpenGLES3.0をサポートしない場合があります
2）高画質に考慮すべき問題
PBR、線形空間をサポートする
変なバグ
3）各画質での互換性の問題を解決し、ブラックリストとホワイトリストを確立する必要があります。

>#####2、等級づけられるディテールを見つける方法は？
◆コストの高いポイントを先に探す
後処理効果Bloom、HDR、ToneMapping、MotionBlur、DOFなど。
リアルタイムのライトとシャドウ、水面でのリアルタイム反射
PBR物理照明
Ragdoll、DynamicBonesなどの物理システム
昼と夜のサイクル、特殊効果気象システム
 
>◆ディテールモジュールのLOD機能の考え
シーン/キャラクター/特殊効果/カメラ相関/他のシステムモジュール
####二、LODモジュールの詳細化
>#####1、シーン相関
![8-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/d1745d7c-05d3-8509-616f-c194a8a4f54a.png)
◆ Shader LOD
●shader.globalMaximumLODで異なる画質のLOD値を指定します。
●Shader内に複数のSubShaderを定義して、計算とテクスチャサンプリングを1つずつ削減します。

>Shader LODの使用に一つの問題があります。Propertiesで定義されたテクスチャは、低レベルのSubShaderでサンプリングおよび計算されませんが、それでもメモリを消費します。キャラクターと同じに、LODフレームワークをデザインする時に、2つのprefabを考えて、シーンをサポートする時にローエンドモデルのためにもう一つのロープロファイルシーンファイルを準備することをお勧めします。

>◆制作する時にハイモデルとローモデルを合理的に使用する

>◆シーンオブジェクトをLevel_1、Level_2、Level_3に等級付ける
●シーン特殊効果、シーンアニメーションオブジェクトなどが含まれ、違うレベルで表示/非表示します。
最初の頃は、距離を使用してシーン特集効果の表示を制御していました。
>**欠点：**
>1.リアルタイム監視距離のコスト
2.各シーンは、適切な距離値で別々に配置する必要があり

>等級を使用して制御する方がより直接的です。LODを作成するときには、最も単純で暴力的な方法を最優先され、これでアートの仕様はそれほど複雑ではなく、後の段階で過度のメンテナンスを行う必要はありません。

>◆シーン照明スイッチ
●Light / Light_Highには、リアルタイム照明がキャラクターとシーンシャドウの描画での制御が含まれます。
●シーンライトマップの切り替え

>◆オブジェクトのLayer層がシャドウを決定する
●シーンファイルで設定されたCast ShadowsとReceive Shadowsはベイク用に設定されているため、保存に不便です。
●さまざまなLayerを設計してオブジェクトがシャドウを生成して受け入れるかどうかを判断します。

>◆キャラクターが生成したシャドウ
●高配置時にプレーヤーとNpcキャラクターのLayerをShadowに変更し、低配置時にプレーヤー/ Npcに変更します。
●中配置時にプレイヤー自身とBossキャラクターのLayerをShadowに変更し、他のプレイヤーがPlayerに変更します。
●シャドウ層はリアルタイムシャドウを描画します。Player/ Npcはディスクを使用して足の裏にあるシャドウを描画します。

>◆キャラクターがシャドウを受け取る
●高画質時のみシャドウを受け取ることをオンにする

>◆トリミング距離、霧効果距離
●数値の異常を防ぐために、トリミング距離と霧効果距離がパーセンテージに応じて減らすアルゴリズムをデザインする

>◆後処理効果
●全局後処理
全局後処理で後処理のON /OFFを管理し、カスタムオプションを制御します。

>●シーンの後処理
シーンに「ハイ」と「ロー」の二つの後処理案を配置します。低配置にColorGradingのみ使用します。
UIおよびプロットアニメーションの後処理は、高配置のみにONする
例えば、UIで使用されるBloom、プロットで使用されるRadialBlurモーションブラーなど。

>◆単一シーンの特殊効果等級
●配置表でシーンのタイプと、同じ画面に表示できる特殊効果の数やレベルを定義します。
#####2、キャラクター相関
![9-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/318cf404-08d2-4c60-291a-1d1477a8ff0e.png)
◆キャラクター材質、シェーダー、テクスチャ
●配置表で異なる画質で異なるprefabをコールします
●A.prefabとA_Low.prefabはA.matとA_Low.matを使用します
●A_Low.matがShaderを使用して計算とテクスチャサンプリングを削減します
●A_Low.matが_MainTexを使用して低精度のテクスチャを置き換えます

>◆ LODGroup
●キャラクターのモデル面数が上昇した後、ハイモデルとローモデルの2つのギアを作成し、LODGroup機能で距離次第でダウングレードします

>◆ SubShader
●高配置と中配置のライトモデルの切り替え、PBRはBlinn-Phongに切り替えます

>◆キャラクター部品
●部品は配置表に空と配置でき、低配置時にはバックペンダントを表示しません

>◆キャラクターボーンSkin Count
●Skinがサポートする骨の最大数が2-Bones 1-Bonesに下げります
●DynamicBoneが物理システムに基づく動的ボーン効果のスイッチ
●Npc死亡動作が物理システムに基づく表現のスイッチ

>◆同じ画面のキャラクター数
●異なる画質が異なる「同じ画面のキャラクター最大数」を設置します
●ロジックタスクのないクライアントNPCのスイッチ
#####3、特殊効果相関
![10-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/f8905a38-2fdf-7468-ad5a-f3e6e6275ede.png)
◆天気システム
●異なる大きさの粒子システムを作成する

>◆足音効果
●フットステップエフェクトのオンとオフを切り替え、プレーヤー自身や他のプレーヤーとは別に制御でき

>◆ドロップ効果
●複雑な特殊効果は簡略化バージョンを作成できます

>◆スキル効果
●配置表を通じて、異なる画質で異なるPrefabをコールします

>◆スキル特殊効果の基準
●階段式コントロール効果のパフォーマンスコストを生成します
●ツールの支援で* _Low.Prefabを生成します
●*_Low.Prefabのパフォーマンスコストを厳密に制御します
#####4、他のモジュール
![11-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/3c4b8203-bc64-e462-ae0c-5a947f12a6a9.png)
◆レンダリングの解像度
●異なるレンダリング解像度を使用し、最大解像度を1080pに制限します

>◆オープンパースペクティブ
●視点の上下左右と回転
●カメラの最大距離と最小距離

>◆スクリプトコントロール
ある状況では、4つの画質を切り替えることができる配置を作成する必要があり、スクリプトで制御します
●Prefab切替え
●Material切替え
#####5、LODに適さないシステムモジュール

>◆UI
●UIのピクセルと特殊効果は、表示、非表示、最適化には適していません
●UIシーンは、ベーキングやリアルタイムのライト切替えには適していません
●UIキャラクターは、インターフェイスの重要性に応じて、高レベルまたは低レベルのどちらを使用するかを選択できます
●ロードとアンロードを管理した後、高配置を低配置のUIアセットの切り替えを考えられます

>◆ストーリー

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

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