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

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


レンダリング

Q1:私たちはMMOゲームを開発しています。今度は、主人公(他のプレイヤーを含む)にPBR(Untiy自身の標準)を使用したいと思います。他のキャラクターやシーンでは使用しません。パフォーマンスがこの状況に耐えられるかどうかはわかりません。また、今のモバイルゲームでのPBRマテリアルの使用状況も知りたいです。

現在、モバイルゲームでPBR素材を使用するプロジェクトは、特にMMOやRPGなどのプロジェクトで大幅に増加しており、主人公、NPC、ビッグボスはすべてPBRになっていきます。

上記の状況でのみPBRを使用する場合、一般的にキャラクターが画面に占める面積は比較的小さいため、Unityエンジンに付属のPBRはパフォーマンスに大きな問題はあまりありません。ストーリーを推進する時、画面に占める面積はより大きいですが、時間は一般的に非常に短いため、全体的なパフォーマンスにほとんど影響はありません。但し、(特にローエンドデバイスで)地形などの画面に大面積を占めるオブジェクトにPBRを使用することは、UWAにはお勧めしません。これは、確かにGPUの圧力は高くなるためです。UWA Day2018でもこの問題に対して定量分析を行いました(下図のように)。開発チームが使用中にこれを注意すべきです。そして、これも自分のプロジェクト次第です、自分が設置したローエンドデバイスでのパフォーマンス表現を確認することをお勧めします。

最後に、Standard Shaderを使用する場合、パフォーマンスに重点を置くだけでなく、メモリへの影響にも注意を払う必要があります。この文章を参照できます:「レンダリングレベルの設計方法」


レンダリング

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:前回の記事「レンダリングレベルの設計方法」の続きに、更に2人の業界の有名人が彼らの見解を共有しました。

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

私の考えを共有します。

1.先ずは、テストケースを決定することです。

メインシティーや違う戦闘スタイルの最高面数シーンを例として選択します。

2.キャラクターに違う戦闘スタイルの最高面数キャラを選択します。

3.次に、テストステージを設定して、サンプリングスクリプトを書きます。

このテストデータは、スクリプトを使用してフレーム数を記録します。

テスト方法はCheatに統合されており、指定された時間のフレーム範囲と平均フレームをテストして、パフォーマンスを大まかに説明するために使用されます。

フルモンスターレンダリング:主人公は雑魚敵を一周して、テストされた雑魚敵たちを全員集まって、同一画面で全体レンダリングを保証します。

フルモンスタースキル発動:できるだけ多くの雑魚敵を攻撃して、粒子の圧力を確認します。

4.テスターさんに例の組み合わせをテストすることをお願いします。デートを収集します。

第二回のテストレポートを選択して表示します。

実際、その間にいくつかの繰り返しがありました。テーブルの最後の列は、フレームターゲットに対して、配置を繰り返し調整して作成されたデータです。

5.最後に、テストデータに従って格付け表の配置を調整します。

最終的にできた配置は次のように、赤い部分は今回のテストで調整、および新たに追加した内容です。

そして、このテストで見つかった問題。

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、シーン相関

◆ 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、キャラクター相関

◆キャラクター材質、シェーダー、テクスチャ

  • 配置表で異なる画質で異なる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、特殊効果相関

◆天気システム

  • 異なる大きさの粒子システムを作成する

◆足音効果

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

◆ドロップ効果

  • 複雑な特殊効果は簡略化バージョンを作成できます

◆スキル効果

  • 配置表を通じて、異なる画質で異なるPrefabをコールします

◆スキル特殊効果の基準

  • 階段式コントロール効果のパフォーマンスコストを生成します
  • ツールの支援で* _Low.Prefabを生成します
  • *_Low.Prefabのパフォーマンスコストを厳密に制御します

4、他のモジュール

◆レンダリングの解像度

  • 異なるレンダリング解像度を使用し、最大解像度を1080pに制限します

◆オープンパースペクティブ

  • 視点の上下左右と回転
  • カメラの最大距離と最小距離

◆スクリプトコントロール

ある状況では、4つの画質を切り替えることができる配置を作成する必要があり、スクリプトで制御します

  • Prefab切替え
  • Material切替え

5、LODに適さないシステムモジュール

◆UI

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

◆ストーリー


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

パフォーマンス最適化、歩きは止まらないーーメモリ編2

前回の記事では、プロジェクト開発中のメモリ割り当て状況を紹介しました。その以外、開発チームが注意すべきより重要なところはまだ三つあります。それは、メモリリーク、Mono無効的なヒープメモリコスト、およびアセットの冗長性であります。これは、ほとんどすべてのチームが開発中に遭遇する問題です。 今日は、これらの問題の解決策について詳しく説明します。


メモリリーク

メモリリークは、開発者がプロ​​ジェクト開発中に遭遇する最も頻繁や最も遭いたくない問題です。今から見れば、プロジェクトにメモリリークがあるかどうかを判断することについては、まだいくつかの誤解があります。

誤解1

プロジェクトのメモリ下がりは、シーンに出入りする前後に一貫ではありません。たとえば、シーンに入った後、メモリは40MB増加し、出た後は30MB減少しますが、システムに戻されないメモリが10MB残っているため、メモリリークが発生しました。

誤解2

プロジェクトがシーンに出入りする前後で、Unity Profilerのメモリ下がりは正常でしたが、AndroidのPSS値は完全に戻りませんでした(シーンを出た後のPSS値は、シーンに入る前のPSS値よりも高い)。つまり、メモリリークがあります。

上記は、開発チームが私たちにフィードバックする典型的な問題です。ほとんどの開発チームが同様の状況に遭遇すると思います。 ここで、上記の2つの状況のどちらもメモリリークを示していないことを説明する必要があります。メモリが一定期間に増加し続けても、メモリリークがあると単純に判断することはできません。メモリが完全に下がれないことを導く原因が多いです。例えば、後で使用しやすいためにロードされたアセットがメモリに駐在すること、Monoヒープメモリは上昇するだけで下降しないことなど、これらの状況がメモリの完全下がりに妨害があります。一般に、メモリがリークしているかどうかを判断するための推奨方法は次のとおりです。

1、アセット、特にテクスチャ、メッシュなどの使用状況を確認します。

UWAがやったプロジェクトのディテールな最適化の過程で、リソースリークがメモリリークの主な形式です。具体的な原因は、ユーザーがロードされたアセットを保存する(たとえば、Containerに入れる)が、シーンを切り替える時にはRemoveやClearしませんでした。そのため、エンジン自体でも、Resources.UnloadUnusedAssetsなどの関するAPIを手動的にコールしてもアンロードできず、リソースリークが発生します。プロジェクト内のリソースの量が多すぎて、リークされたリソースを見つけるのが難しいですから、この状況を確認することは非常に困難です。そのため、UWAレポートでは、プロジェクト内の各アセットの詳細なモニタリングを実施し、「ライブサイクル」指標を通じて、プロジェクト実行中における各アセットの使用範囲を明確に把握することができます。

このようにして、アセットの「ライフサイクル」属性を使用して、メモリ内に「常駐」しているアセットをすばやく確認でき、そのアセットが「プリロードする」アセットであるか「リークする」アセットであるかを判断できます。

同時に、プロジェクトで使用されるアセットの総数は多い場合、数百または数千であり、すべてのアセットを人工的に1つずつ確認するのは非常に面倒です。そこで、アセットの「シーン比較」機能をリリースしました。 次の2つの方法でアセットを比較して、「リーク」の問題があるアセットをより迅速に見つけることをお勧めします。

  • 同じシーンまたは同じタイプのシーン間の比較

一般的に、ゲームプロジェクトのメインシティシーンやメインインターフェースシーンなどの同じシーンまたは同じタイプのシーンのアセット使用量はほぼ同じです。同じシーンのアセット情報を異なる時間で比較することにより、アセット使用量の違いをすばやく見つけることができます。このように、これらの「異なる」アセットの存在が妥当であるかどうかを判断するだけでよく、リークが発生しているかどうか、およびリークされていたアセットをすばやく究明できます。

  • 異なるタイプのシーン間の比較

一部の常駐アセット以外、タイプが異なれば、アセットの使用量も完全に異なります。たとえば、一つゲーム内のメインシティシーンと戦闘シーンでは、部分の常駐アセット以外に両者が使っている大部分のアセットは全然違っています。したがって、2つの異なるタイプのシーンを比較することにより、比較結果で「共通アセット」を直接表示して、それが実際に事前設定された常駐アセットであるかどうかを判断できます。そうでない場合は、アセットが「漏洩」している可能性が高いため、プロジェクトのアセット管理に盲点がないかどうかをさらに確認する必要があります。

2、ProfilerでWebStreamまたはSerializedFileの使用状況から検出します

AssetBundleの不適切な管理は、ある程度のメモリリークを引き起こす可能性もあります。つまり、前のシーンで使用されたAssetBundleは、シーンの切り替え中にアンインストールされず、次のシーンに移動します。この場合、Profiler MemoryにあるTake Sampleを使用して検出することをお勧めします。WebStreamまたはSerializedFileにあるAssetBundleの名前を直接に確認したら、「リーク」状況があるかどうかを判断できます。

3、Android PSS / iOSInstrumentからフィードバックしたアプリスレッドメモリで確認します

上記の「誤解2」を続けると、「Unity Profilerのメモリ下がりは正常でしたが、AndroidのPSS値は完全に戻りませんでした。」は可能です。この原因は、Unity Profilerがフィードバックするのはエンジンが実際に割り当てる物理メモリでありますが、PSSに記録されたものには、システムキャッシュの一部が含まれます。通常の状況では、AndroidまたはiOSはすべてのアプリのアンインストールデータを適時にクリーンアップしません。次回の使用をスムーズにするために、OSは一部のデータをキャッシュに入れます。自身のメモリが不足している場合、OS KernelはLowMemoryKillerみたいなルールを採用してキャッシュを照会したり、一部のプロセスを強制終了してメモリを解放したりします。だから、一回や二回の「PSS値は完全に戻らない」状況でメモリリークの問題を説明することはできません。

UWAが推奨する方法は、メインシティシーンと戦闘シーンなどの2つのシーンを切り替えることです。理論的に、同じシーンを複数回切り替えると、Profilerに表示されるUnityメモリが正常に戻れますなら、PSS / Instrumentメモリ値の変動範囲も安定する傾向があります。しかし、PSS / Instrumentメモリが増え続けますなら、注意を払う必要があります。この原因は、2つの可能性があります:

  • Unityエンジン自体のメモリリーク問題。 この確率は非常に小さく、以前はいくつかのバージョンでしか発生していませんでした。
  • サードパーティのプラグインを使用しているときにメモリリークが発生しました。この可能性は高いです。ProfilerはUnity自身のメモリしか監視できず、サードパーティライブラリのメモリ割り当てを検出できません。上記のメモリの問題が発生した場合は、最初に使用しているサードパーティのライブラリを確認することをお勧めします。

無効なMonoヒープメモリコスト

現在、Unityで使用されているMonoバージョンには一つの大きな問題があります。メモリが割り当てられると、システムに戻されません。 これは別の問題につながりますーー無効なMonoヒープメモリ。Monoによって割り当てられたヒープメモリですが、実際には使用されていないため、「無効」と呼ばれます。では、プロジェクトに「無効なヒープメモリ」が大量にあるかどうかを確認するにはどうすればよいですか?

UWAレポートでは、次の図に示すように、プロジェクト実行中のメモリ割り当て状況を提供します。その中に、青い線と紫色の線の分離状況は、無効なヒープメモリの割り当てサイズを反映しています。たとえば、図で選択した時点で、青い線のReserved Totalは現在のプロジェクトが占有している物理メモリの合計でありますが、紫色の線のUsed Totalは現在のプロジェクトが使用している物理メモリの合計であります。つまり、現在のプロジェクトの空きメモリは57.1MBです。 (200.4-143.3)、これは主に2つの部分、空きUnityエンジンメモリと無効なMonoヒープメモリで構成されています。ぞの上、空きUnityエンジンメモリは17.1MB(92.0-74.9)であるため、現在選択されているフレームの無効なMonoヒープメモリは40.0MBです。さらに、図から、実行中に青い線と紫色の線は常に分離していることも分かりました。これは、「無効」状態になるMonoヒープメモリは常に存在していることを示します。メモリの「高価」モバイルデバイスにとって、これは非常に無駄なことです。

では、どうやって過剰な「無効なヒープメモリ」の割り当てを回避または削減できますか?UWAからの推奨方法は次のとおりです。

 

  • ヒープメモリの一次性の大き過ぎの割り当てを回避します。Monoメモリの割り当ては「要求次第」で徐々に割り当てられます。ただし、大き過ぎの割り当てを一次性に開けると(例えば、一つの比較的大きいContainerをNewすることや一つの比較的大きい配置ファイルをロードすることなど)、必然的にMonoのヒープメモリが直接上昇することを導きます。そのため、開発チームは常にヒープメモリの割り当てに注意を払う必要があります。
  • 必要のないヒープメモリのコストを回避します。UWAレポートには、プロジェクト実行中のヒープメモリ割り当てTop10の関数をリストされています。文章の長さの限りで、ここでは繰り返しません。開発チームは前回のメモリ最適化に関する記事を見てください。

アセット冗長性

メモリ管理の方に、注意すべき点はまだ一つありますーーアセット冗長性であります。私たちがテストした多くのプロジェクトでは、95%以上のプロジェクトがさまざまな程度のアセット冗長性を持っています。いわゆる「アセット冗長性」とは、特定の時間にメモリ内に同じアセットの2つ以上のコピーが存在することを指します。 この状況には、主に2つの原因があります。

1.AssetBundleのパッケージ化メカニズムが導く

一つのアセットが複数のAssetBundleファイルに入力されます。例えば、一枚のテクスチャが異なるNPCによって使用され、各NPCが個別のAssetBundleファイルに作成されている場合、テクスチャの依存関係パッケージ化しないなら、テクスチャは異なるNPCAssetBundleファイルに表示されます。これらのAssetBundleがメモリに次々にロードされると、メモリにテクスチャアセットの冗長性があります。これについて、開発チームにアセットの冗長性問題を発見した後に関するAssetBundleの作成流れを検査することをお勧めします。

同時に、UWAレポートで各アセットに一つの判断標準を導入しましたーー「ピーク数」。これは、同じフレーム内の同じアセットの最大数を指します。1より大きい場合は、アセットに「冗長アセット」がある可能性が高いです。 この列で並べ替えると、プロジェクトのアセットの冗長性をすぐに確認できます。

2.アセットのインスタンス化が導く

Unityエンジンでは、特定のGameObjectのアセット属性を変更すると、エンジンはこのGameObjectのMaterialやMeshなどのアセットを自動的にインスタンス化します。マテリアルを例にすると、開発中にこのような仕様はよくあります:キャラクターが攻撃されたら、マテリアルの属性を変更して特定の攻撃を受ける効果を取得します。この仕様により、エンジンは特定のGameObjectbに一つのMaterialを再インスタンス化し、サフィックスにinstanceの文字を付きます。それ自体は特に大きな問題ではありませんが、Material属性を変更する要求のあるGameObjectが増えていると(例えばARPG、MMORPG、MOBA等ゲーム)、メモリの冗長性が大幅に増加します。

下図のように、ゲームが進行するにつれて、インスタンス化されたMaterialアセットは333に増加します。Materialは多くのメモリを占有しませんが、過剰な冗長リソースは、Resources.UnloadUnusedAssetsAPIのコールする効率にかなりの圧力をかけています。

一般的に、アセット属性の変更状況はランダムではなく固定されています。例えば、GameObjectが攻撃されたときに、そのMaterialの属性変更は受ける攻撃タイプ次第で三つの異なるパラメータ設定があります。では、その要求に対しては、3つの異なるMaterialを直接作成し、Material属性を変更するのではなく、Runtime状況でコードを介して対応するGameObjectのマテリアルを直接置き換えることをお勧めします。こうすれば、何百何千個のinstance Materialがメモリ内で消え、代わりにこの三つのMaterialアセットがあることがわかります。この利点は、コチラまで読むあなたに、もう説明する必要はないでしょう。:)


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

UnityでのShaderLabメモリの最適化

おそらく、ShaderLabメモリの最適化に困っている開発者は多いでしょう。「価格の高い」メモリスペースに、無視できないボリュームを占めることがよくあります。他のアセットメモリと比べて、「ブラックボックス」に似ているので、最適化するのは難しいです。そのため、いくつかの実験を通じてShaderLabの占有率を分析し、この部分のメモリを最適化する方法を考えました。

一、問題を述べる

上の図(戦闘シーンに入ったときのメモリスナップショット)から、ShaderLabの占有率が42MBに達していることがわかります。なぜ、ShaderLabの占有率がそれほど高いのですか?

二、問題を分析する

現在のアイテム(ShaderLab)には詳細なShader占有情報を説明していませんので、他の方法で原因を探さなければなりません。 幸いなことに、メモリスナップショットのAssetsの下のShaderアイテムに詳細な使用情報があります。

そして、StandardのShaderが使用されているのを見ましたが、このプロジェクトにStandardのShaderを使用する場所がありませんので、なぜ存在していますか?

究明のために、一輪の調査を回しました。Standardで使用されている場所のいくつかをクリアし、もう一度テストして、別のメモリスナップショットを作成しました。

クリアした後、ShaderLabは27.6 MBに低下しました(後で、スタンダードは完全にクリアされ、21 MBに低下しました)。やっぱり、主な原因はStandardにあります。じゃあ、また問題が発生しました。Standardを使用していませんのに、なぜメモリにStandardが存在してありますか?

ここでは二点について話す必要があり、これもこの問題を排除する方法であります。

三、問題を排除する

1.モデルのインポートが導く

モデルをインポートする時、デフォルトで「Import Materials」がチェックされます。モデルがインポートされると、Unityは同じディレクトリに「Materials」ディレクトリを作成し、対応するマテリアルを作成します。このマテリアルはデフォルトでStandardを使用します。

アーティストが製造の過程にPrefabにあるモデルに他のマテリアルを添付しますので、実にはデフォルトのマテリアル(Standard)は使用されません。ただし、モデルをロードすると、デフォルトで作成されたマテリアルが再度ロードされ、シェーダーに解析され、メモリ内でStandardがあるになります。

では、ソリューションも非常に簡単です。「Import Materials」を削除し、使用されていないデフォルトのマテリアルを削除します。

注:「Import Materials」を削除しないと、他のプロジェクトにインポートしたときにマテリアルがまた自動的に作成されます。

補足:実際のプロジェクトでは、Prefabの変更回数は比較的多く、対応するモデルファイルの変更は比較的少ないため、プロジェクトのモデルと対応するPrefabは別々のAssetBundleにパッケージ化すると、非常に奇妙な状況が発生します。

「Import Materials」をチェックしないモデルファイルは、Prefabをインスタンス化すると、ShaderLabには一つの「Standard」のShaderメモリがありますが、このShaderの参照は一つの「Default-Material」ファイルに指します(しかしこのファイルは存在してありません)。

ただし、モデルとPrefabが同じAssetBundleにあり、またはResourcesを使用してロードされている場合、「Standard」と「Default-Material」は顕示されません。Unity 5.3.3のバグなのか、Unityの特殊なメカニズムなのかはまだわかりません。

一時的な解決策:モデルをPrefabとは別にパッケージ化する必要がある場合は、「Import Materials」をチェックして、デフォルトで生成された材料を直接使用および変更します。

 

2.デフォルトモデル(CubeSphere)の作成が導く

初期のシーンを構築する時、配置や視覚化しやすいのために、CubeみたいなシステムのデフォルトのMeshがアンカーポイントとして使用され、ゲームを始まる時に禁止させます。これらのCubeは有効になっていないため、パフォーマンスのコストはごくわずかであるため、無視します。

ただし、これはシステムのデフォルトのMeshであるから、作成時に指定されるマテリアルはデフォルトのマテリアル「Default-Material」であり、このマテリアルで使用されるシェーダーはたまたま「Standard」です。だから「Standard」の存在は間違いではありません。

解決策も非常に簡単です。これらのMeshを削除するか、マテリアルを交換します。 こうすれば、この部分が占める「Standard」は存在しません。

四、まとめ

Standardの変種が多すぎるため、Standardを使用しますと、複数のStandardの変種が同時に存在することがよくあり、大量のメモリを占めます。ShaderLabのメモリが大きすぎと感じっている場合は、上記の原因ですかどうかを調べてみてください。

ShaderLabのメモリ占用が大きすぎとは、完全にStandardの原因ですか?実際にはもっとあります。最適化後の27MB(完全にクリアされた後の21MB)の中に、他の原因があるはずです。しかし、最適化の過程は大きな部分から削除し始まることです。上記のように、少し最適化したら20MB以上を改善できますし、もちろんすぐにやる必要がありますが。サイズが小さいほど最適化効率は低くなるので、現時点では 「Assets」や「Texture2D」などの部分に目差して最適化します。したがって、残ったShaderLabの最適化方法は後であった時に再び補充します。

 

PS:上記の全ての内容は実機でテストしました。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

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

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


レンダリング

Q1:今はプロジェクトのレンダリングレベルを設計する方法を考えており、誰か経験のある先輩がShaderLODなどの方法を教えてください!他に何かアイデアはありますか? ありがとうございました!

私たちのゲームの効果レベル分けの内容を整理しました、参照できます。


レンダリング

Q2: 2017.2.0を使用して一枚のマップをレンダリングしましたが、なぜ時々にXiaomi 4のCamera.Renderは高い時間コストがあります?一つの空きシーンですが、なぜCamera.Renderの時間コストはそんなに高いですか?

一つの簡単なテストをしてこの問題を研究しました。すなわちシーンに一つCubeのみレンダリングします。

設備:

(1)Huawei 6Plus

(2)Xiaomi 4

Profilerのスクリーンショットは次のとおりです。

青枠:Huawei 6Plus

赤枠:Xiaomi 4

上図から見ると、Xiaomi 4のCamera.Render時間コストは不安定で、時々に10+msのピーク値は出ます。

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

1)Cullingが不安定

下図はXiaomi 4およびHuawei 6Plus設備で、Culling操作の時間コストの比較です。青枠はHuawei、赤枠はXiaomiです。Timelineからは、シーンSceneNodeの計算は原因であることが分かりました。

2)Drawingが不安定

レンダリングの時間コストも不安定で、下図のように:Timelineで「Xiaomi 4設備では、メインスレッドのレンダリングプロセスがサブスレッドの完了を待ってから後続の操作を実行することが多いこと」がわかります。しかし、Huawei 6Plusで同じアプリを実行する時この問題はありません。

Xiaomi 4:

Huawei 6Plus:

上記のテストをまとめします:

  • 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ベイク効果:

LOD1は、黒を避けるためにベイクエフェクトに参加しません。

実行時のライトマップパラメーターを変更した効果。

ライトマップパラメーターを変更するComponentコード。

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の過程中にレンダリングされますか?

Render.OpaqueGeometryとRender. TransparentGeometryの執行は、RenderQueue <2450によって区別されています。RenderQueueのサイズは、オブジェクトのレンダリングの順序を完全に制御できます。たとえば、半透明オブジェクトのレンダリング順序を不透明オブジェクトの前に調整しますこと、またはGrassをTerrainの前に調整しますこと。マルチレイヤーテクスチャを使用する一部のプロジェクトでは、 比較的良い選択です。RenderQueueを使用してオブジェクトのレンダリング順序を制御し、RQを変更して特別な目的を実現します。


2D

Q5:以前、私はUWAの動画を見ましたから、このスクリプトをプリセットに掛けました。しかし、今回のテストの結果で解凍する時にこの関数がとても高いヒープメモリを占有していることがわかりました。この関数はアセットが解凍する時にもコールされますか?

さらに、昨日UWA GOTを使用して解凍中のヒープメモリの問題を追跡したところ、Webサイトで報告されたPolygonImageの問題が発生していませんでした。これはどうしてですか?

PolygonImageの実現は一つのMeshEffectとして対応するImageのジオメトリを変更します(四辺形をポリゴンに変更)。過程に一定量のヒープメモリ割り当てが発生します(ポリゴンが複雑になるほど、より多くのヒープメモリが割り当てられます)。

MeshEffectのトリガーは、対応するImageが再構築されたときにのみ発生します:アクティブ化、変更された色(透明度)、変更された長さと幅など。

ですから、大量のヒープメモリが割り当てられますから、この効果を頻繁に変更されるImageに使用することはお勧めしません。

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


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

パフォーマンス最適化、歩きは止まらないーーメモリ編

プロジェクトのパフォーマンスの最適化は、主にCPU、GPU、メモリの3つの方面を中心に行われます。ゲームであれ、VRアプリケーションであれ、メモリ管理は開発段階の最優先事項です。

ただし、私たちが評価した大量のプロジェクトでは、90%以上でさまざまな程度のメモリ使用問題が発生しています。

現在、Unityエンジンに基づくモバイルゲームとモバイルVRゲームに対して、メモリコストは次の3つの部分に集めています:1.アセットメモリ使用率; 2.エンジンモジュール自身のメモリ使用率; 3.マネージヒープメモリ使用率。

プロジェクトにメモリの問題があれば、上記の3つの状況に避けられません。今日は、これらの3つの状況を1つずつ説明します。


アセットメモリ使用率

比較的複雑な大規模および中規模のプロジェクトでは、アセットのメモリ使用量が総メモリの70%以上を占めることがよくあります。だから、アセットの使用が適切かどうかは、プロジェクトのメモリ使用量を直接決定します。一般的に、ゲームプロジェクトのアセットは、テクスチャ(Texture)、メッシュ(Mesh)、アニメーションクリップ(AnimationClip)、オーディオクリップ(AudioClip)、マテリアル(Material)、シェーダー(Shader)、フォント(Font)およびテキストアセット(Text Asset)などのタイプに分類できます。その中、テクスチャ、メッシュ、アニメーションクリップ、オーディオクリップ四つのアセットは、大きなメモリコストを引き起こす可能性が最も高いアセットです。

一、テクスチャ

テクスチャアセットは、ほとんど全てのゲームプロジェクトで最大のメモリコストを占めるアセットであります。60,000パッチのシーンの場合、最大メッシュアセットは10MBのみですが、2048x2048テクスチャは直接16MBに達する場合があります。だから、プロジェクトでテクスチャアセットを適切に使うかどうかは、プロジェクトのメモリ使用量に大きく影響します。

では、テクスチャアセットを使用する場合、何に注意すべきですか?

(1)テクスチャ形式

テクスチャ形式は、開発チームにとって最も重要なテクスチャ属性です。これは、テクスチャのメモリ使用量だけに影響するではなく、テクスチャのロード効率も決定するためです。一般的に、開発チームにハードウェアのタイプに応じて、サポートできるテクスチャ形式をできるだけ選択することをお勧めします。例えば、AndroidプラットフォームのETC、iOSプラットフォームのPVRTC、Windows PCのDXTなど。そのため、UWAレポートでは、開発チームが迅速に問題を特定できるように、テクスチャ形式を詳細にリストしています。

ハードウェアでサポートされているテクスチャフォーマットを使用すると、次の問題が発生する場合があります。

  • カラースケール問題

    ETCやPVRTCなどの形式はすべて非可逆圧縮であるため、テクスチャの色差の範囲が大きい場合、必然的にさまざまな程度の「階段」のようなカラースケールの問題が発生します。したがって、多くの開発チームはより良い結果を達成するためにRGBA32 / ARGB32形式を使用しています。ただし、この方法は大きいメモリ使用率を導きます。例えば、同じ一枚の1024x1024テクスチャそしてMipmapをオンにしない場合、PVRTC形式のメモリ使用率は512KBになり、RGBA32ビットに変換すると、おそらく4MBに上昇します。だから、開発チームがRGBA32またはARGB32形式のテクスチャを使用する場合は慎重に検討する必要があります。より賢い選択は、テクスチャの色差の範囲を最小限に抑え、ハードウェアがサポートする圧縮形式をできるだけ多く使用して保存することです。

 

  • ETC1は透過チャンネルをサポートしていない問題

    Androidプラットフォームでは、OpenGL ES 2.0を使用するデバイスに対して、テクスチャ形式はETC1形式のみをサポートできます。この形式にはより深刻な問題があります。それは、Alpha透明度チャネルをサポートしないため、透明テクスチャをETC1形式で直接保存できません。この点に関して、開発チームに透明テクスチャをできる限り2枚に分割することをお勧めします。つまり、一枚のRGB24ビットテクスチャは元のテクスチャのカラー部分を記録し、もう一枚のAlpha8テクスチャは元のテクスチャの透過チャンネル部分を記録します。そして、これらの2つのテクスチャを次々にETC1形式のテクスチャに変換し、特定のシェーダーでレンダリングして、透禍テクスチャをサポートする効果を実現します。この方法では、RGBA透禍テクスチャのレンダリング効果を大幅に近似できるだけでなく、テクスチャのメモリ使用量を減らすこともできます。

もちろん、現在OpenGL ES 3.0をサポートしているデバイスが増えているため、AndroidプラットフォームでETC2またはASTCをさらに使用できます。これらのテクスチャ形式は、透禍チャネルをサポートし、より理想的な圧縮率を持つテクスチャ形式であります。ゲームがミドルおよびハイエンドデバイスのユーザーに適している場合は、これらの2つの形式をテクスチャの主な保存形式として直接使用することもできます。

(2)テクスチャサイズ

一般的に、テクスチャサイズが大きいほど、メモリ使用量も多くなります。だから、テクスチャサイズをできるだけ小さくし、512x512テクスチャで表示効果が十分である場合は、1024x1024テクスチャを使用しないでください。後者のメモリ使用量は前者の4倍であるためです。そのため、UWAレポートでは、開発チームがすばやく検出できるように、テクスチャのサイズを詳細に表示します。

(3)Mipmap機能

Mipmapは、レンダリング帯域幅の圧力を効果的に軽減し、ゲームのレンダリング効率を向上させることを目的としていますが、Mipmapをオンにすれば、テクスチャメモリが元の1.33倍になります。より深度感のある3Dゲームに対して、通常は3DシーンモデルとキャラクターのMipmap機能をオンにすることをお勧めしますが、UWAがテストした沢山のプロジェクトでは、一部のUIテクスチャもMipmapをオンにすることがよくあります。実際にはこれは必要がないです。大多数のUIはスクリーンの最上層にレンダリングされます。Mipmapを有効にしてもレンダリング効率は向上できませんが、不要なメモリ使用量が増加します。したがって、開発チームにUWAレポートにMipmapで並べ、Mipmap機能をオンにさせるアセットはUIアセットですかどうかを確認することをお勧めします。

(4)Read&Write

一般的に、Unityエンジンで、テクスチャアセットの「Read&Write」機能がデフォルトでオフになっていますが、プロジェクトのディープな最適化に、多くのプロジェクトのテクスチャアセットがこのオプションをオンにすることに気づいてしました。これに対して、オンにするとテクスチャメモリが2倍になるため、開発チームにテクスチャアセットこのオプションの使用を厳密に注意することを提案します。


二、メッシュ

メッシュアセットは、複雑なゲームでより多くのメモリを使用する場合があります。メッシュアセットについて、使用するときに注意すべき点は何ですか?

(1)NormalColorTangent

私たちが深く最適化した多数のプロジェクトでは、メッシュアセットのデータに、大量のColorデータ、Normalデータ、Tangentデータが含まれていることがよくあります。これらのデータの存在は、メッシュアセットのファイルサイズとメモリ使用量が大幅に増加させます。このうち、ColorデータとNormalデータは、主に3DMaxやMayaなどのモデリングソフトウェアをエクスポートするときに生成されますが、Tangentは一般的にエンジンにインポートするときに生成されます。

さらに面倒くさいのは、プロジェクトがメッシュにDraw Call Batching操作を行いと、全体的なメモリ使用量がさらに増える可能性があることです。たとえば、100個のメッシュが合併する場合、そのうち99個にはColor、Tangent、や他の属性がなく、残り1つにはColor、Normal、およびTangent属性が含まれます。このため、UWAレポートで各メッシュのNormal、Color、およびTangent属性の具体的な使用状況を示しています。開発チームは、各属性によって並べ替えて表示でき、冗長データを持つアセットを直接特定することができます。

一般的に、これらのデータは主にShaderがよりカッコいい効果を生成するために使用されます。だから、開発チームにプロジェクトのメッシュアセットを詳細なチェックをし、モデルのレンダリングシェーダーにこれらのデータをレンダリングする必要はあるかどうかを確認しますことをお勧めします。

記事の長さのせいで、本日はテクスチャアセットとメッシュアセットのみをご紹介しますが、アニメーションクリップやオーディオクリップなどの他のアセットについては、UWAパフォーマンスレポートで直接確認することをお勧めします。同時に、次のアセットトピックで詳しく説明するので、しばらくお待ちください。

エンジンモジュール自身のメモリ使用率

エンジン自体のメモリコストは複雑で、大量の「小さな」メモリによって蓄積されていると認められます。例えば、GameObjectまたは他の各種Component(最大量なComponentはTransformはずです)、ParticleSystem、MonoScriptおよびさまざまなManager(SceneManager、CanvasManager、PersistentManagerなど)。

通常の状況では、上記のエンジンの各コンポーネントのメモリコストは比較的小さく、実際にメモリコストが大きいのは、WebStreamとSerializedFileの2つです。そのメモリ割り当てのほとんどは、AssetBundleのアセットローディングが原因です。簡単に言えば、new WWWまたはCreateFromMemoryでAssetBundleをロードする時に、Unityエンジンは元のデータをメモリにロードして解凍しますが、WebStreamのサイズは元のAssetBundleファイルサイズ+解凍されたデータのサイズ+ DecompressionBuffer(0.5MB)。同時に、Unityバージョン5.3以前のAssetBundleファイルはLZMAで圧縮されています。その圧縮率はZipに似ている(20%-25%)ため、1MBの元のAssetBundleファイルの場合、ロード後のWebStreamのサイズは5〜6MBになる場合があります。そのため、プロジェクトがnew WWWで複数のAssetBundleファイルをロードし、またAssetBundleをすぐに解放できない場合、WebStreamのメモリが非常に大きくなる可能性があります。これは、開発チームが注意すべき点であります。

SerializedFileの場合は、LoadFromCacheOrDownload、CreateFromFile、またはnew WWWローカルAssetBundleファイルを使用するときに生成されるシリアル化ファイルです。

WebStreamおよびSerializedFileの場合、次の2つの点に注意する必要があります。

  • AssetBundleが完全にクリーンアップされていない状況があるかどうか。 開発チームは、Unityプロファイラーで具体的な使用状況を直接チェックし、Take Sample時のAssetBundleの存在が合理的かどうかを判断できます。
  • 大きなWebStreamを占めるAssetBundleファイル(例えばUI Atlas関連のAssetBundleファイルなど)に対しで、LoadFromCacheOrDownLoadまたはCreateFromFileを使用して置き換える、つまり、解凍されたAssetBundleデータをローカルCacheに格納して使用することをお勧めします。このアプローチ、つまりメモリスペースをローカルディスクスペースに変えることは、メモリが特に限られているプロジェクトに非常に適しています。

 

マネージヒープメモリ使用量

Unityエンジンに基づくほとんどの現在のプロジェクトでは、マネージヒープメモリはMonoによって割り当てられ、管理されます。「マネージ」の本来の目的は、Monoが必要なメモリに適応するようにヒープのサイズを自動的に変更し、不要なメモリを解放するためにガベージコレクション(Garbage Collection)操作を行いことです。それてコードメモリ管理における開発者への技術要求を削減します。

ただし、これは、開発チームがコードに好きにマネージヒープメモリを添加することができるという意味ではありません。これは、現在Unityで使用されているMonoバージョンには重大な問題があるためです。Monoヒープメモリが割り当てられると、システムに返されません。 つまり、Monoのヒープメモリが増加するだけで減少しません。例を挙げます。プロジェクトが実行する時、シーンAに60MBのマネージヒープメモリを開きました、次のシーンBでは20 MBのマネージヒープメモリのみが必要な場合、Monoには40 MBの空きヒープメモリがあり、 システムには戻されません。これは私たちに対して非常に見えたくない状況です。ゲーム(特にモバイルゲーム)に対してメモリ使用率はとても高価のものであり、Monoに大量の不必要なメモリをロックさせるのは非常に無駄なことです。したがって、UWAレポートでは、開発チームのテスト中に累積された関数ヒープメモリ割り当てを統計しました。ヒープメモリ割り当てTop10の関数をチェックしたら、迅速に基礎コードの実現をチェックでき、不要なヒープメモリを割り当てるコードがあるかどうかを特定できます。

ここを読んで、あなたはそのような質問をするかもしれません:どの関数が大きなヒープメモリ割り当てを持っているか知っていますが、どうすれば不要なヒープメモリをさらに見つけることができますか?

これは私たちがよくあった問題です。そのため、プロジェクトディープ最適化サービスに、プロジェクトチームに直接入って、現場でプロジェクトコードをチェックして問題コードを特定します。たくさんのディープテストをした後、ユーザーの不要なヒープメモリの割り当ては、主に下記の方面から起こします。

  • 高频率のNew Class/Container/Arrayなど。開発チームは、UpdateFixUpdate、またはコール頻度の高い関数でヒープメモリを開かないように注意する必要があります。これにより、プロジェクトのメモリとパフォーマンスが大幅に低下します。簡単に計算します。プロジェクトのある関数がフレームごとに100Bのヒープメモリを割り当て、フレームレートが1秒あたり30フレームであると仮定します。そして1秒のゲームのヒープメモリ割り当ては3KB、1分のヒープメモリ割り当ては180KBで、10分後に1.8MBが割り当てられています。そのような関数が10個あれば、10分後にヒープメモリの割り当ては18MBになります。この期間中に、Monoのヒープメモリのピーク値の上昇やGCの複数コールを導く可能性が高いです。私たちがテストしたプロジェクトでは、関数が10分以内に数百MBを割り当てるのがたくさんあって、時々にGB当たりのメモリ割り当て状況もあります。
  • Log出力。多くのプロジェクトで、まだたくさんのLog出力があることがわかりました。開発チームに自身のログの出力を厳密に制御し、不要なヒープメモリ割り当てを回避するためにキーログのみを保持することをお勧めします。これに関して、UWAレポートにLogの出力を詳しく検査します。詳細なパフォーマンスコストだけではなく、同時にLog出力のコールパスも表示します。そうすれば開発チームはレポートで直接にLogの出力を特定や制御できます。

  • UIPanel.LateUpdate。これは、NGUIでCPUとヒープメモリのコストが最も高い関数です。自身はただ一つの関数でありますが、NGUIの大量の使用がそれを無視できないルールに徐々になされています。この関数のヒープメモリ割り当てと自身のCPUコストは、根本としては同じで、UIメッシュの再構築であります。

コードヒープメモリの割り当てについて注意すべき点はまだたくさんあります。例えば、Stringリンク、一部のエンジンAPI(GetComponent)の使用など、これらは常に検討しまして、ここには記事の長さの原因で紹介しません。興味があれば、Googleで検索できます。以後にはコード効率に関する特別トピックもありますので、しばらくお待ちください。


UWAテストのメモリ標準

みなさんがUWAを使用した後、UWAが推奨するメモリ標準値について多くの疑問があります。 ここでは、UWAメモリ標準を作成するためのルールも紹介します。

(1)150MBの全体的なメモリ標準は、主に次の2つの要因から導き出されます。

  • たくさんのプロジェクト最適化の後にまとめて得ました。実際、現在市場である主流のUnityゲームでは、メモリ使用量は主に120〜200MBに集中しています。同時に、iPhone4や512MB / 768MBなどのローエンドのAndroidモデルを考慮に入れると、そのアプリケーションの総メモリ使用量は200MBを超えることはできません(iPhone4の安全線は約180MBになるはずです)。ですから、UWAはReserved Totalを150MBに設定しました、これはUnityエンジン自身のメモリの割り当てです。目的はアプリがシステムライブラリを使用した後、OSの総なメモリも200MB未満になるためです。
  • 一部のチャネルは、AndroidゲームのPSSメモリに厳しい制限を課しています。通常、ゲームのPSSメモリは200MB未満である必要があります。これは、UWAがReserved Totalメモリを150MBに設定するもう1つの重要な理由です。

(2)総メモリが150MBに設定されると、さらに具体的な割り当てに設定をしました。ただし、説明したいのは、ここでのメモリ割り当ては実際には厳密な式を示せるものではなく、ただたくさんのプロジェクト最適化作業で私たちが得た経験であります。現在、プロジェクトの適切なメモリ割り当ては次のとおりです。

  • テクスチャアセット:50 MB
  • グリッドアセット:20 MB
  • アニメーションクリップ:15 MB
  • オーディオクリップ:15 MB
  • Monoヒープメモリ:40 MB
  • その他:10 MB

より複雑なフォントファイル(Microsoft Yaheiなど)とテキストアセットは150MBで含まれていないことに注意してください。これらはゲームの要求次第で決定する必要があります。

 

(3)現在のUWAメモリ標準要求は少し厳しく、ミッドからハイエンドのデバイスに対して、許容量は実際には150MBをはるかに超えています。しかし、厳密な基準は、開発プロセスにおけるプロジェクトにとって良いものであると私たちは主張しています。少なくとも、それは誰にでも思い出させることができ、誰もが常に自分の問題に注意を払うことができます。私たちの了解により、現在のローエンド携帯電話のカバレッジ率は依然として非常に高いです。同時に、ミッドからハイエンドのモバイルデバイスに対しても、UWAもう実験と研究を行っています。遠くない将来に、さまざまなレベルのさまざまな設備に対してより合理的な推奨値を提供できるようになり、誰もがメモリをより簡単に管理できるようになれることを心から期待しています。

 

上記はゲームプロジェクトにある主なメモリ割り当て状況であります。ここを読んだみなさんに、Unityプロジェクトのメモリコストと潜在的な問題をよりよく理解し、自分のプロジェクトに対してより適切な最適化方法を見つけることを祈っています。

それ以外、開発チームに注意すべき点はまだ2点あり、これはメモリリークとアセットの冗長性です。次のメモリ最適化記事に関する内容を紹介します。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

LuaとC#間のシャトル問題

今回の主な話題:Luaコール回数統計、Unity人形の手首の反転アニメーションの具体的な制作方法、Find()で要素を検索するときに生成されるGC、パーティクルシステムの最適化、アニメーションクリップの数がパフォーマンスコストへの影響。


スクリプト

Q1: LuaとC#間のコール頻度はLuaのパフォーマンスに影響を与える非常に重要な要素ですが、最近、私たちのプロジェクトでもこのような問題を分析しています。LuaとC#間のコール回数を数える方法は?挿入すべきコードの量がたくさんあると感じしています。warpコードをたくさん作成しましたが、それぞれ追加するのは少し非現実的で、warpコードは自動的に生成されます。 何か良い提案はありますか?

私たちのプロジェクトはToLuaを使用しており、Unityのバージョンは5.6.1p1です。

Luaはdebug.sethookでC#をコールします。

Yunfengさんがこの方法に基づいて一つのツールcloudwu / luaprofilerを作成しましたが、直接使用することはできず、自分でライブラリをコンパイルする必要があります。

これ以外、Luaで直接ハングすることも可能ですが、パフォーマンスに影響があります。

C#はLuaFunctionでLuaをコールします。

 

LuaとC#間のコール回数をカウントするためのツールは、ToLuaがwarpインターフェースをエクスポートする場所を変更し、コードを再生成し、マクロまたは条件付きコンパイルのコントロールを追加するだけで、簡単にエディターモードで回数統計を行いながら、デバイスへの公開プロセスに影響を与えないこともできます。

統計のために生成されたコードにタグを追加して、例えば私たちプロジェクトの一つのコールコード:

[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
    static int GetBattery(IntPtr L)
    {
        try
        {
            ToLua.CheckArgsCount(L, 0);
#if STATISTICS_LUACALLOUNT
            CallMethodInfo cpf = new CallMethodInfo();
            cpf.FuncName = "UnityEngine.HardwareInformation.GetBattery";
            if(CallCountPerFrameDataManager._instance!=null)
                CallCountPerFrameDataManager._instance.AddNewMethodNameDic(cpf);
#endif
            int o = UnityEngine.HardwareInformation.GetBattery();
            LuaDLL.lua_pushinteger(L, o);
            return 1;
        }
        catch(Exception e)
        {
            return LuaDLL.toluaL_exception(L, e);
        }
    }

UWAがUWA DAYで紹介した方法はより簡単で、関数に直接カプセル化され、[Conditional( "XXX")]によって制御されます。

C#がLuaを逆にコールする場所を数えたい場合、LuaFunctionのいくつかのCall関数がキーポイントです。


アニメーション

Q2: アニメーションを再利用し、アセットの重複問題を軽減するために、ヒューマノイドアニメーション形式を使用して制作しています。一人称視点があるため、手のひらと手首は常に見えます、何か欠点があればすぐバレでしまいます。手首の歪みを避けるや問題を解決するために、ボーンを追加しました。ボーンの位置と構造は次のとおりです。

Unityに追加ボーンの手首回転効果を添付していません場合:

Unityに前腕追加ボーンの手首回転効果を添付しています場合:

問題1:手首と腕の接合部に転位があります

Maxに前腕追加ボーンの手首回転効果を添付しています場合(手首の歪みは完全に解決されていることがわかりますが、Unityでの効果は理想的ではありません)。

問題2:ヒューマノイドアニメーション形式の親指動画は再現できません、いつも伸ばしています。ボーンマッチング問題を確認しましたが、下図のように正常であります、親指のみ曲げることはできません。

Unityのヒューマノイドボーンをここで使用すると、小さな問題がたくさん存在しています。公式ドキュメントも多くの場所が非常に不明瞭です。私たちのプロジェクトはヒューマノイドボーンを使用しており、Retargetingを使用する際のさまざまなアクションに小さな問題があります。

先に私たちが得たいくつかの結論を教えます。

  • キャラクター自身の動画に自分のAvatarを使用したら、ヒューマノイドボーンはMaxおよびGenericのアニメーションとまったく同じ効果を達成できるはずです。
  • 他のボーンの場合、高さ、肩の幅などのボディシェイプに違いがあります。Retargetingエフェクトの後、全体的な効果は正しくなりますが、累積された誤差により、足や指などのルートボーンから遠く離れたボーンは小さな差がある可能性があります。例えば、足と地面の接触距離が足りない、足のidle動きにわずかな揺れがあるなど。

Retargetingの原理について私が「アニメーションリダイレクト技術の分析とUnityでの応用」(中国語注意)と言う記事が書いてありましたが、興味があればご覧ください。ここのその後の自分が使用した時に発見したいくつかのポイントを述べます。

  • Avatarファイル、いわゆるボーンファイルは、Retargetingに使用される基本的なT-pos情報を記録されています。Unityに定義されたのは一つの大きなTポーズですが、Maxで一般的に使用されるのは小さなTポーズであります。だからこちらに少し調整の必要があります。詳細は後で話します。
  • アニメーションファイル、アニメーションの差分情報を記録します。インポートされたアニメーションファイルがヒューマノイドボーンを使用する場合、対応するファイルへのAvatarを使用する必要があります。Avatarが変更された場合、アニメーションファイルをUpdateする必要があり、これは、差異を再計算するためのプロセスです。このアニメーションファイルの内容は、アニメーションファイルにインポートされたMaxファイルのT-posと強い相関があることがわかりました。

前の記事を読んだ方がわかりやすいでしょう。 AとBの2つのスケルトンセットがあります。BのアクションをAに適用する必要があります。これには4つのデータが必要です。

  • AのT-pos情報。
  • B のT-pos情報。
  • Bのアニメ情報。
  • Aのアニメ情報=Bのアニメ情報- B のT-pos情報+ AのT-pos情報。

ですから、上記のアニメーションファイルの情報は、実際にはBのアニメーションファイルとBのT-posとの違いとして理解されるべきです。

だから我がプロジェクトがアーティストに伝えた提案は、AvatarをエクスポートするT-posとアニメーションをエクスポートするMaxファイルにあるT-pos情報は出来る限り一貫にします。そうすればアクションを可能な限り復元できます。(同じMaxファイルを使用してエクスポートされたアニメーションとAvatarは、UnityとMaxで同じかどうかをテストすることをお勧めします。)

原理についてたくさん話しました。つまり上記の問題のいくつかは、問題主自分が原理に基づいてテストして解決する必要はあります。

 

もちろん、これら2つの問題に対しての私の考えも述べます。

一つ目の「手首と腕接合部の転位」問題は、正直私も遭いましたはずですが、遠く昔の話で、具体的なディテールもう忘れてしまいました。下記の方面を確認することを提案します。

  • 非ヒューマノイドのボーンにもこの問題がありますか?
  • スキンの問題であり可能性はありませんか?それともスキンを修正することで解決できますか?
  • ヒューマノイドボーンAvatarの手首のボーンマッピング関係に問題はありますか?Avatarの姿勢を調整することでこの問題を緩和することは可能ですか?

二つ目の「指が動かない」問題は、Avatarでの指の姿勢が予想と異なるかどうかを確認する必要があるかもしれません。この状況では、動作中の指に一つの非常に誇張した姿勢を与えてテストできます。完全に行動がない場合、動作のmaskの設定に何か遺漏があるかどうかを確認することを提案します。

アクション方面はエンジニアとアーティストの協力でテストし続き、一つのバランス点を見つけることは必要です。私自身ではMaxによく知らないので、問題を見るときはアーティストと一緒にする必要があります。


アニメーション

Q3: アニメーションクリップの数はパフォーマンスのコストに影響しますか? もしそうなら、同じアニメーションクリップに対して、異なるレベルでの多重化再利用も影響がありますか?(アニメーションコントローラゲーム中はアクティブ化と隠す操作はありませんが、なぜアニメーションクリップデータのサンプリングと読み取りのコストが高い理由は明らかではありません。)

簡単に言えば、アニメーションはただ移動、回転、スケーリングなど簡単な変換であります。各フレームは各頂点に変換行列を乗算し、この部分は純粋なCPU計算です。

じゃあ、パフォーマンスコストに関するのは頂点の数、ボーンの数、レ​​イヤーの数に集めています。

もう1つのはBoneWeightで、0以外のweight(n)の数が多いほど、各フレーム頂点の変換計算が多くなります。

では、最適化できるポイントは:

  • 面を減らすこと;
  • 骨を減らすこと;
  • 層を減らすこと;
  • 骨格blendの量を減らすこと;

また、アニメーションのメモリ占有の最適化に関して、この記事「Unity動画ファイル最適化について」を参照できます。

 

process animation以外に、アニメーションクリップの数もanimatorcontorllerのメンテナンスにコストを導きます。(writejobに反映されます)。"When using the Animator, all the properties of all the clips currently connected are written, whether the clips are playing or not. "


パーティクルシステム

Q4: シーンに沢山の環境パーティクルシステムがあり、パーティクルシステムに裁断最適化を行いましたが、カメラから遠く離れているパーティクルシステムはどうやって正確にスリープできますか?パーティクルシステムをstopにすればいいですか?レンダリングやCPUに余分なコストを与えませんか?または、パーティクルシステムのルートノードのgameobjectのactiveをFalseに設定しなければならないですか?

ActiveとDeactiveで制御することをお勧めします。DeactiveしていないParticle Systemも、レンダリングモジュールのCullingなどの計算に参加します。同時に、パーティクルシステムに対して、Active/Deactiveの処理は一般的に時間がかかりません。


コード

Q5: Deep Profileでコードパフォーマンスをチェックしますとき、一つのリスト検索Find()は毎回行うと2.5KB GC Allocを生成しますことを発見しました。そして書き方を変更し、Find()を使わずにforループを直接たどって、GC Allocがなくなっていることを発見しました。時間コストもほぼ同じです。その後、Find()のILを探しに行きましたが、GCがどこに生成されるのか理解していませんでした。ぜひ、教えてください!

Profiler.BeginSample("===========Find2======");
for (int i = 0; i < 2000; ++i)
{
    result = lst.Find(t => t != null && t.Num < 200);
}
Profiler.EndSample();

Profiler.BeginSample("===========Find1======");
for (int i = 0; i < 2000; ++i)
{
    result = lst.Find(t => t != null && t.Num < i);
}
Profiler.EndSample();

問題主のコードは次のロジックに似ていると推測します。一つのループにFind操作が複数回実行され、Findのパラメーター(クロージャー関数含む)は、毎回ループごとに変化するnon-local変数を使用するため、より多くのGCが生成されました。この原因は、毎回ループすると一つの委託対象をnewしますことです。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com

RTSゲームの経路探索システム

今回の主な話題:RTSゲームの経路探索システム、AssetBundleがパッケージ化された後のmd5は異なる、UGUIの3D  HPバー最適化の問題、シーン内の一部のオブジェクトの外観を早く変更する方法。


経路探索システム

Q1: RTSゲームを作っています。UnityのNavMesh経路探索から始めましたが、ブロックとフラッシュの問題が常に発生するため、これはRTSマルチプレーヤー経路探索には適していません。Asset StoreのA *経路探索のコメントに、「衝突に問題があります」というコメントは書いてあります。比較的に通じるソリューションはありませんか?

前のプロジェクトはRTSプロジェクトでした。最初に経路探索の問題を解決する過程で同じような疑問に遭いました。長い時間の変更、調査、調整の後、参照用にいくつかのポイントを共有します。

まずは結論:A Start Pathfinding Project Pro + Unity NavMesh2層構造を採用しました。

1)主な経路探索スキームは、A Start Pathfinding Project Proプラグインの従来のメッシュ形式を使用し、ディープな変更と拡張しました。主に経路探索過程中の通過性は単位半径を考慮する必要があります。そうすると経路探索の精度を高くなされます。

2)Unity NavMeshシステムを経路探索過程中の衝突システムとして使用します。あなたが言う通りに、この経路探索プラグインの衝突に問題があります。これについては後で説明します。

上記の2つの部分は、「経路探索アルゴリズム、正確な衝突」を構成します。次に、上記のスキームの理由と詳細について説明します。

1NavMeshの経路探索速度は速いですが、十分に正確ではありません。RTSは従来の正方形のNavGrid経路探索に適しています。既存の経路探索アルゴリズムは、デフォルトで経路探索プロセスにおける経路探索ユニットの半径の影響を考慮することをサポートしていません。弊社のプランナーは「1メートル幅のギャップに2メートル幅のデブが通じる」のようなことに絶対許しませんから、Navmeshを使用して動的にブロッキングを生成すると、経路探索結果はありますが、衝突の問題で単位は大きいギャップに「シェイクする」可能性が高いです。これは自分でしか変更できないため、プラグインを購入して裏から外へ変更し、具体的にアルゴリズムの規則と変更された概略図を変更しました。こちらを参考できます:http://www.cnblogs.com/yaukey/p/rts_unit_traverse_size_based_path_finding.html。変更後、毎回経路探索しますとユニットの直径はパラメータの1つとして導入されます。

このプラグインを使用してスレッドを2つくらい開いて経路探索を行うことは私が調整した理想的な結果であります。次のは、マップ内のさまざまなユニットの出産と死亡です。ユニットが静止している場合は、ブロックを生成する必要があります。移動しますとブロックを削除して通過性を保証すべきです。プラグインのDynamicObsculeコンポーネントを変更することにより(元の機能シンプルすぎ)達成します。具体的には、各ユニットに対応するサイズのCapsuleCollider空オブジェクトにこのプラグインを添付して、ユニットが立つ時このオブジェクトをユニットの位置に置いてアクティブさせます。ユニットが移動しますとこの空オブジェクトを隠します。注意すべきのは、このプラグインはマップ通過性のアップデートを導き、このアップデートはマルチスレッドであります。即時性は保証されていないため、同じフレームまたは次のフレームでは、コールバックイベントを使用して応答することを実行しないでください。こうすれば、マップ全体の通過性はユニットによりアップデートします。

2.経路探索の通過性は保証できになり、次は衝突の問題を解決します。このプラグインはrvoアルゴリズムである衝突アルゴリズムが付属していますが、調整実験によると、その衝突は私たちの要求に満たしていません。ユニットの数が多く、混雑している場合、いくつかのユニットは立った後に常にオーバーラップします。最も許容できないのは、2つのユニットが完全にオーバーラップしていることです。私はここで多くの時間を費やしましたが、満足できる結果は修正してでられませんでした。後でrecastnavigationの作者が言ったことを思い出した。UnityのNavMeshはこれに基づいていますが、Detourシステムが大幅に書き換えられました、 Detourに巡航と衝突を含みます。実際の使用時に、NavMeshAgent間の衝突は非常に正確であることがわかりました。考えましたと、巧妙な方法は出てきました。地面にAStarプラグインの経路探索面積と同じサイズのNavMeshを配置します。ブロックはありません(純粋な青として理解できます)。同時に経路探索単位に一つのNavMeshAgentを添付します。しかし、このものは衝突のみを使用し、経路探索を使用しない(ブロックなくて、経路探索は2点直線であり、ほとんどコストがないと見なすことができる)ため、最後に実際の衝突効果は私たちの要求に大体満足できます。

以上は私が言った「2層構造」でした、そして問題を述べます。

1)開発時に使ったUnityバージョンはUnity 5.3.7-5.3.8で、プラグインバージョンはxでした。経路探索プラグインの基層にPhysics.CheckCapsuleコールはあるはずですが、マルチスレッドの多くのコール操作は、基層のPhysX物理エンジンの崩壊、ゲームの突然終了を導きます。必然ではありませんが、回数が増加しますと崩れやすくなります。プラグインの公式BBSにもこのバグに関する議論があります。後でこれを2つのPhysics.CheckSphereコールに置き換えました。2017バージョンはまだテストしていません。

2)1で使用した方法は、UWAパフォーマンスレポートで、Dynamic Colliderは毎回標準を超えました。これは自分で選択する必要がありますが、全体的に私たちのゲームのボトルネックは経路探索に集まることではなく、これらのテストでコストは比較的に理想であります。

3)プラグインのマルチスレッド更新により、たくさんの完了イベントコールバックがあり、基本的にこれを利用してゲームシステムとリンクします。足りない場合は自分で追加します、そうしないと更新が完了しない時にまだ間違い結果は出やすいです。

4)できれば内部のMonoメモリの割り当てを最適化し、ゲームシステムと組み合わせた後に採用の解放と切断することに注意してください。そうしないと、メモリリークが発生しやすくなり、経路探索プラグインが採用した後、多くのオブジェクトが解放できない状況を導きやすいです。

5)経路探索精度と衝突精度がゲーム内の表現、パラメーターを調整するためにより多くの時間を必要とします。たまたまに表現が悪いが、方法が悪いと言う意味ではありません。そして、リアルタイム同期に対する高い要求がある場合、このソリューションをさらに改善する必要があります。


レンダリング

Q2: シーン内の一部のオブジェクトの外観をすばやく変更したいのですが、DrawCallへの影響、材質変更の時間コストなどを考慮すると、最も効率的な方法は何ですか。

材質のみを変更する場合は、Colorの変更など、MaterialPropertyBlockを使用できます。

MaterialPropertyBlock mpb = new MaterialPropertyBlock();
    mpb.SetColor("_FillColor", Color.red); 
    GetComponent<MeshRenderer>().SetPropertyBlock(mpb);

MaterialPropertyBlockの変更効率は高いため、GPU Instacingと連携してDrawCallをマージすることもできます。 この記事を参照できます:Material Property BlockでMaterial属性操作を差し替え


アセット管理

Q3: Unity 5.6.5でAssetBundleパッケージツールを作成しました。Manifestを付属する最新のPipeline APIを使用しました。たとえば、Perfabをパッケージ化します。このPrefabにはTexture、Shader、スクリプトが含まれます。これで問題が発生します。Androidプラットフォームで、異なるコンピューターができたAssetBundleは異なります。UnityStudioで分析して、Shaderのmd5が異なることが原因です。何かいい方法はありますか?

Unityはいつもこの問題があります。同じコンピューターであっても、Libraryを削除してから再生すると異なります。パッチ適用ツールの比較プロセスを共有しましょう。

  • 最初に、SVNに基づいて2つのバージョンの違いがあるAssetBundlesを見つけ、範囲を絞り込みます。
  • 次に、ABに対応するmanifestファイルを比較して、AssetHashが実際に変更されたかどうかを確認し、変更されていないファイルを除外します。同時にTypeTreeHashもチェックし、変更がある場合は警告を出します。

ところで、このAPIにちょっと文句を言います。

https://docs.unity3d.com/ScriptReference/BuildPipeline.GetHashForAssetBundle.html

このAPIの原理は同じ名前のmanifest内のAssetHash値を直接読み取ることであり、このAPIがHashを計算するためのものであると誤解しやすいです。

 

MD5の問題は常に存在しており、AssetBundleのHasidで直接判断することをお勧めします。

こちらを参照してください:https://docs.unity3d.com/ScriptReference/BuildAssetBundleOptions.AppendHashToAssetBundleName.html


UI

Q4: UGUI WorldSpace Canvasを使用して、クリープ(クリープは頻繁に移動し、数は数十個くらい)3D UI HPバーを作成しました。HPバーUIは、カメラからの距離に応じて適切なレンダリング順序を自動的に形成します。しかし、このようにすれば、各HPバーにはCanvasが必要であり、一つのCanvasは一つのDrawCallであります。だからすべてのHPバーを同じWorldSpace Canvasに統合し、すべてのHPバーUIに対してDrawCallが1つだけになるようにしますが、これは合理なオクルージョン関係を形成しません。

だから数フレームごとにすべてのHPバーUIとカメラ間の距離を計算して並び、transform.SetSiblingIndexを変更してオクルージョン順序の問題を模擬しますが、これによりCPU計算が増加します。では、数量の少し多い3D UI HPバーの最適化はどうせればいいですか?

まず、UGUIでオクルージョンを変更したい場合、変更できるのはSiblingIndexのみです。並べ替えや変更が必要なHPバーの量が比較的多い場合は、かなりのオーバーヘッドが発生しやすくなります。 ただし、「数十」が大きすぎるかどうかを判断するのは困難です。このアプローチのパフォーマンスをローエンドマシンでテストすることをお勧めします。主な焦点は、距離、並べ替え、変更の総コストを計算することです。数フレームごとに行いますから、結果は1〜3msなら納得できます。


UWA公式サイト:https://jp.uwa4d.com

UWA公式ブログ:https://blog.jp.uwa4d.com

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com