Device.Present時間コストの最適化
今回の主な話題:「Device.Present時間コストの最適化」、「PCでアート特殊効果を検査する」、「LuaJitバイトコードのプラットフォーム相関性」、「Shaderを使用して特定色相の変換を実現する」。
パフォーマンス
Q1:Androidモバイルゲームプロジェクトが実機でProfilerを使ってパフォーマンスを分析する時、CPU消費におけるDevice.Presentインターフェイスの割合が非常に高いため、レンダリング時間が長くなり、レンダリング時間の曲線がグリッチ形状を示している。
一部の情報を確認したところ、垂直同期をオンにしたことが原因との声もあった。 このオプションはオフにすると、この現象は少し改善されましたが、まだ存在している。ある人も全画面UIが原因であると認めたが、 このプロジェクトには存在しない。これの原因と対処方法を誰かが知っている人がいるか。 どうもありがとうございました!
問題主が言った二つ共にDevice.Presentの高い時間コストを導く可能性がある。モバイルデバイス自体が垂直同期をオンにするため、実機で垂直同期をオフにしても実際には役に立たない。
このアイテムは2つの理由で高すぎ:
(1)当該フレームのCPUコストが33ms以下の場合、Device.Presentは基本的にハードウェアの垂直同期が原因だ。
(2)当該フレームのCPUコストが33msより高い場合、高すぎるDevice.Presentは、 GPUプレッシャーが高すぎるか、ある子スレッドのCPUコストが大きすぎることを示す。
問題主は自分の具体的な要求次第で確認できる。
制作
Q2:PCでアート特殊効果のパフォーマンスを確認するに良い方法はないの?以前には、不細工な方法を使う経験があった。それはシーンに特殊効果をたくさん入れてフレーム数をチェックすることだったが、効果はあまりよくなかった。
①
評価式を使っている。つまり、特定のルールに従って特殊効果全体をトラバースし、節点の属性に従ってパフォーマンススコアを計算している。アセットをスキャンしてExcelに出力してチェックできる。 コードを再利用して エディターに直接入力すると、アーティストはこのスコアを参照できる。精度上の要求は必要ではなく、この方法で90%の問題をすぐに発見できる。仕様を事前に指定し、特殊効果シーンと共に、同時に出現する特殊効果の数とパフォーマンススコアが標準を超えるかどうかを推定することもできる。
②
特殊効果がパフォーマンスに要求高いのはOverDrawの原因だ。PCで確認せず、実機で確認した。
PCでの検査はQian LaiKangさんが提供した、一つのOverDraw監視スクリプトを使った。アーティストは特殊効果を作る時にOverDrawを見ながら、状況に応じて調整できる。
次に、実機パッケージをビルドする時に特殊効果リストを作成し、Major Cityに入り、チャットプログラムでGMコマンドを入力し、特殊効果をトラバースする。各特殊効果は1回から無限回に再生でき、AdvancedFPSCounterプラグインを使って当時の FPS値をファイルに記録される。フレームレートが低い場合の特殊効果を特定し、最適化する。
例えばこのコード:
if (cmd.ToLower().StartsWith("-gm texiaoplay3")) { Toast.ShowTip("アーティストが作った特殊効果をテストします " + cmd); > prEffectTest(3); return true; } private static void prEffectTest(int efCount) { if (BilinCamera.Instance == null || BilinCamera.Instance.player == null) { Debug.LogError("ヒーローは見つからないので、特殊効果はテストできません"); return; } TextAsset conf = Resources.Load<TextAsset>("effeclist"); string[] lines = conf.text.Split('\n'); //先に一回同期ロードします for (int i = 0; i < lines.Length; ++i) { string prefabName = lines[i]; if (string.IsNullOrEmpty(prefabName)) { continue; } } BLDebug.isLog2FileEnable = true;//ファイルを書き始めます GameManager.Instance.StartCoroutine(prEffectTestAsync(lines, efCount)); GameManager.Instance.StartCoroutine(logUsedFPS(efCount)); } private static IEnumerator logUsedFPS(int efCount) { float startTime = Time.realtimeSinceStartup; float crtTime = Time.realtimeSinceStartup; while (crtEffectName.Length > 0 && (crtTime - startTime) < 6000.0f) {//100分以内 crtTime = Time.realtimeSinceStartup; CodeStage.AdvancedFPSCounter.AFPSCounter aFPSCounter = CodeStage.AdvancedFPSCounter.AFPSCounter.AddToScene(); BLDebug.Log2File(TimeUtil.currentSqlTimestamp4LongAdv() + "\tlogUsedFPS" + efCount + "\t" + crtEffectName + "\t" + aFPSCounter.fpsCounter.LastValue + "\t" + aFPSCounter.fpsCounter.LastAverageValue + "\t" + Time.frameCount + "\t" + Time.realtimeSinceStartup); yield return new WaitForSeconds(0.1f);// 0.1秒ごとにFPSをサンプリングします } yield return null; } private static string crtEffectName = "notbegin"; private static IEnumerator prEffectTestAsync(string[] lines, int efCount) { float periodTime = 5.0f; //特殊効果をを1つずつ再生します for (int i = 0; i < lines.Length; ++i) { string prefabName = lines[i]; if (string.IsNullOrEmpty(prefabName)) { continue; } crtEffectName = prefabName; GameObject[] effectGoArr = new GameObject[efCount]; for (int k = 0; k < effectGoArr.Length; k++) { GameObject effectGo = PrefabUtil.loadPrefabToGameObject(prefabName, parentGo); effectGoArr[k] = effectGo; if (effectGo != null) {//はUI特殊効果 GameObject.Destroy(effectGo, periodTime); } else { Debug.LogError("ロード失敗しました???" + prefabName); } } yield return new WaitForSeconds(periodTime); } crtEffectName = ""; BLDebug.UploadTodayLogFile();//その日のログをサーバーに送信します yield return null; }
ログをExcelにインポートして分析すればいい。
③
私たちは2つの部分に分けました:
1.特殊効果のリリースが全体的なパフォーマンスへの影響。これは結論に対する統計である。実機でリリース後のフレームレートの変動を統計する。現在のバージョンでは、シーンにフレームレートの記録を入力する機能だけがあり、主な機能は特殊効果がゲームへの最終的な影響を評価することだ。
2.特殊効果のドローコール、面の数、およびOverdraw影響。現在、この部分の統計データはPCでしか取得できないため、スタンドアロンバージョンではスキルの特殊効果を1つずつ再生するツールがある。上記の3つの指標の評価を統計して、標準を超える部分が毎週の会議にレポートで提出する。
個人的な感覚はアセットの検査はツールで定期的にやる必要があり、継続的な観察は最も効果的な最適化方法だ。
ToLua
Q3:ToLuaフレームワークでコンパイルされたLuaJit32とLuajit64を使用してLuaコードをバイトコードに変更するので、すべてのプラットフォームで2セットのバイトコードを入力する必要があるの?それとも、Androidでは32を使ったら大丈夫?PCとiOSは32と64を使用し、実行時に異なるプラットフォームを区別してから、異なる方法でロードするの?実行時にはIntPtr.Size == 4で区別されるの?
iOSでは32 + 64でなければならない、そうしないと32ビットの古いマシンをサポートできない。エディターでは通常64(ただし、私たちが使っているのはLuaファイルを直接読み取る)、PCスタンドアロンでは32を採用する(ユーザー以外の場合は64でもかまわない)、Androidでは 32のみ。
とにかく、対応関係は
x86 arm→ 32
x64 arm64→ 64
IntPtr.Size == 4が信頼できるかどうかについては、詳細なテストはまだやっていない。自分が作ったプラットフォームに対する判断コードを使っている。(実際には、上記の状況に従ったらiOSのみ判断する必要がある)
制作
Q4:画像の特定の選択範囲の色変換を実現したいと考えている。PSでは、 画像選択でエリアを簡単に選択し、元画像の色相を変更できる。ただし、Unityでも似たようなソリューションを実現したが、実際の効果はPSとかなり異なる。全体が暗くなり、個々の領域が露出オーバーになった。誰かが似たようなShaderソリューションがあったら、参照させていただけませんか。
①
Color Lookup Tableソリューションを使用することをお勧め。 簡単に言うと、一つのテクスチャをルックアップテーブルとして使う。このテクスチャに、各色が変更された後の 色を記録する。この方法は、問題主によって述べられた要求を満たすだけでなく、多くの色補正要求(さまざまなフィルター)も達成できる。
cocos2d時代に使ったから、パフォーマンス上には納得できることがわかった、大きな問題は存在しない。AssetStoreにLUTをキーワードとしてのプラグインリを検索して参考になれる。
Color Lookup Tableの作成とカスタマイズの方法については、説明するのは複雑なので、Googleするとお勧め:P。一つの簡単な方法は、Color Lookup Tableには一つの固定された標準色の元画像がある。この画像をPhotoShopにドラッグし、変更したい色相で変更したら、 変更後の各色相を保存できる。
Unity自身のColorCorrectionLookupを参照することもできるが、これは3Dテクスチャなので、2Dに適用するように変更する必要がある。https://docs.unity3d.com/550/Documentation/Manual/script-ColorCorrectionLookup.html
他のソリューション(Shaderに計算コードを直接作成するなど)については、できないではないが、パフォーマンスはあまり高くない。
②
理論的には、問題主が実現した色変更アルゴリズムはCPUでもGPUでも、アルゴリズムとコードが正しいなら、画像の色変更結果はPSと同じすべきだ。
問題主が言った「全体が暗くなり、個々の領域が露出オーバーになった。」ということは、ゲーム内にライトがある場合に見たことか?それとも、変更された画像を保存して比較された結果なの?ゲーム内の場合は、個別に染色された画像に問題があるかどうかを確認してください。ある可能性はアーティストがdiffuse画像にaoなどの別の情報を書いて、後でシェーディングした画像に問題を導く。ただ保存した画像に問題がある場合には、アルゴリズムを検索し、目的と比較してください、理論的には問題はないはずだ。染色効果を実現したい場合は、 一つのUnityプラグインをお勧め、色々なアルゴリズムが含んである:Texture Adjustments
管理
Q5:ベイクする時にはnormalとtangentをインポートする必要があるが、ベイクが完全した後にはインポートする必要はなくなって、メッシュアセットを最適化できる。しかし、アーティストが再びベイクしたい時には、もう一度開いてnormalとtangentの設定をインポートするのは非常に面倒だ。これに対して適切な処理法がないのか?私が考えられるのはパッケージする時にこのアセットたちを再インポートし、normalとtangentをインポートするオプションを削除して、パッケージして元に戻ることだけだ。
Player SettingのOther Settingsにある「Optimize Mesh Data」オプションをオンにしてみてください。オンにすると、エンジンはリリースまたはAssetBundleパッケージング中にすべてのメッシュデータをトラバースして、過剰なデータを削除する。注意すべきのは、こちらの「過剰な」データとは、レンダリング時にシェーダーが要らないデータはメッシュデータに含まれていること。つまり、メッシュデータにposition、uv、normal、color、tangentなどの頂点データが含まれているが、レンダリングに使わせるシェーダーが必要なのはposition、uv、normal三つだけ。colorとtangentは「過剰な」データとして、エンジンはゲームをリリースするまたはAssetBundleを作成する時、これらのデータを自動的に削除する。ただし、Runtime状況にシェーダーを置換する必要のあるメッシュに、開発チームに特に注意すると提案する。もしRuntimeの時、あるGameObjectにより複雑や多くの頂点属性にアクセスする必要のあるシェーダーを置き換える必要がある場合、実行時に頂点属性のmissingで問題を起こさないために、先にこれらのシェーダーを対応するプレハブにマウントしてリリースすると提案する。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com