circle-loader
by
156/ 0

今回の話題:

1)ShaderLabの使用に関する質問

2)AndroidでのARM64とARMV7に関する質問

3)ILRuntime関連のパフォーマンス検出ツールについて

4)フォントの読み込みの問題

5)LZ4圧縮モードでのアセットパッケージ


 

Shader

Q:公式サイトから内蔵Shaderをダウンロードし、インターフェイスのマテルアルが内蔵Shaderを参照していないことを確認し、Standard Shaderもクリアしました。 メモリからはそのようなことはありませんが、ShaderLabの占有率はまだ少し大きく、メインシーンでは47MBになっています。

 

A1:バリアントが多すぎるので、キーワードが多いShaderをよく確認してください。

 

A2:A1の通りです。数年前に作成されたスキャンプロジェクトのShaderバリアントのコードを共有し、スキャンして、Top数個のShaderを変更して大幅に削減します。

[MenuItem("Find/GetAllShaderVariantCount", false, 20)]
    public static void GetAllShaderVariantCount()
    {
        #if UNITY_5_6
        Assembly asm = Assembly.LoadFile(@"D:\Program Files\Unity_5.6.5f1\Editor\Data\Managed\UnityEditor.dll");
        System.Type t2 = asm.GetType("UnityEditor.ShaderUtil");
        MethodInfo method = t2.GetMethod("GetComboCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        #elif UNITY_2017_1_OR_NEWER
        Assembly asm = Assembly.LoadFile(@"D:\Program Files\Unity_2018.3.0f2\Editor\Data\Managed\UnityEditor.dll");
        System.Type t2 = asm.GetType("UnityEditor.ShaderUtil");
        MethodInfo method = t2.GetMethod("GetVariantCount", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        #endif
        var shaderList = AssetDatabase.FindAssets("t:Shader");

        var output = System.Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);
        string pathF = string.Format("{0}/ShaderVariantCount.csv", output);
        FileStream fs = new FileStream(pathF, FileMode.Create, FileAccess.Write);
        StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);

        EditorUtility.DisplayProgressBar("統計ファイルの書き込み", "統計ファイルを書き込み中... ", 0f);
        int ix = 0;
        sw.WriteLine("ShaderFile,VariantCount");
        foreach (var i in shaderList)
        {
            EditorUtility.DisplayProgressBar("統計ファイルの書き込み", "統計ファイルを書き込み中... ", 1f * ix / shaderList.Length);
            var path = AssetDatabase.GUIDToAssetPath(i);
            Shader s = (Shader)AssetDatabase.LoadAssetAtPath(path,typeof(Shader));
            var variantCount = method.Invoke(null,new System.Object[]{ s,true});

            sw.WriteLine(path + ","+variantCount.ToString());
            ++ix;
        }
        EditorUtility.ClearProgressBar();   //プログレスバーをクリア
        sw.Close();
        fs.Close();
    }

A3:URPには一連のバリアントトリミングコードがあり、それを変更し、パッケージングプロセスに追加して、不要なバリアントをトリミングします(キーワードをあまり使用しないため、大幅に削減する必要があります)。

 

A4:UWAのローカルアセット検出を使用して、どのShaderにさらにバリアントがあるか、バリアントの問題であるかどうかを確認してから、Shaderに冗長性があるかどうかを確認してください。

 

Build

Q:AndroidでのARM64とARMV7の問題に関して、経験から、同じUnityゲームでこれら2つのアーキテクチャの実行効率に違いはありますか?レンダリング効率はCPUアーキテクチャの影響を受けますか?

 

A:ARM64は、メモリ割り当て中の不十分なアドレス空間とアドレスの競合によって引き起こされるメモリ割り当て障害の多くの問題を解決できます。典型的な例は、QualcommのAdrenoのビデオメモリの不足、または辞書タイプの広範な使用によって引き起こされるメモリリークの問題です。ただし、付随する問題も発生します。同じパッケージの64ビットは32ビットよりも大きいです。メモリの要件が厳しいゲームの場合、メモリの最適化はすでに面倒なことであるのに、64ビットになったらさらに面倒になってしまいました。効率の問題については、テストも比較もしていませんが、FPS、温度、エネルギー消費量などの違いを測定することをお勧めします。

 

ILRuntime

 

Q:UWAはすでにLuaのパフォーマンス分析をリリースしています。新しいプロジェクトでは、代わりにILRuntimeを使用し、AwaitとAsyncでネットワーク通信の「同期」コードを実現します。バトルパートのロジックコードもILRuntimeでの実装を計画しています(強CPU計算は可能な限りC#で実装されます)が、パフォーマンスについては少し懸念があります。パフォーマンス分析ツール、特にC#との対話型の部分がある場合は、初期段階で技術的なフレームワークを設定することができれば安心です。

 

さらに、ILRuntimeによってオンラインで正常に適用されたプロジェクトはありますか?それに、安定性の観点から、Luaを引き継ぐことができますか?

 

A1:日常使用にすれば十分だと思います。実際、基本的なメカニズムはLuaに似ており、開発の習慣と言語ははるかに快適になります。汎用モジュールの補足として使用すると便利だと思います、またはホットアップデート機能も非常に優れています。ただし、パフォーマンスの面では、ターゲットを絞ったテストはなく、現在、プロジェクトのニーズを満たしているとしか言えません。大量処理の観点から、ILRuntimeで多くのことを行うことはまだ推奨されていません。基本的な理由は、実際にはLuaの問題と非常によく似ています。

使用に関しては、Adapterの定義に注意してください。ホットアップデートに関しては、異なるコードノードがILRuntimeのホットアップデートパッケージを分離する必要がある場合があります。これはパッケージ管理の観点からは面倒ですが、統合開発言語にはまだ多くの利点があります。

 

A2:実際、パフォーマンスについてあまり心配する必要はありません。私の経験を共有しましょう。

1、必ずReleaseメソッドを使用してDLLをコンパイルし、DISABLE_ILRUNTIME_DEBUGマクロを開いてください。

2、解訳の実行のために、実行効率と直接実行の間には自然に20〜100倍のギャップがあり、複雑すぎる計算は間違いなく機能しません。

3、実行時も純粋なC#であるため、いくつかのパフォーマンスの問題はUWAツールで検出できます。

4、私たちのプロジェクトで使用されているネイティブDLLはLuaよりも確実に高速で、iOSでテストしたらLuaよりも低速ですが、AppleデバイスとIL2CPPのパフォーマンスは良好であるため、フルフレームで実行することもできます。

5、オブジェクト内の構造体への割り当てには必然的なGCがあります。最初にローカル変数に変換するか、V3をXYZに直接格納することをお勧めします。

6、ForeachはGCを生成します。書き込み時には使用しないでください。

 

A3:計算集約型はLuaを使用できます。

1、コアコードはC#を使用します。

2、バトルライブラリのロジックレイヤーは、Luaを使用します。

3、ビジネスロジックはILRuntimeを使用します。

4、Injectfixの別のレイヤーを配置し、非BurstのC#を修復します。

 

A4:ILRuntimeはC#で実装されているため、Profilerを見るとパフォーマンスの消費を直接確認できます。

 

Resource

Q:現在、実機でテストしていますが、メモリに2つのフォントがロードされていることがわかりました。1つはログインインターフェイス、またはフォント自体を含む他のシーンでは、元のFontを参照しています。もう1つはプレハブがシーンに読み込まれると、フォントのコピーが参照されます。これを解決する方法は?

 

A:プレハブがAssetBundleからロードされているが、シーンがAssetBundleからロードされていない場合、通常のシーンパッケージとAssetBundleは異なるパスを取り、同じフォントアセットを参照できません。1つはシーンのSharedassetsからのもので、もう1つはAssetBundleからのものです。したがって、シーンもAssetBundleによってパッケージ化されるか、フォントを使用するシーンのUI部分がAssetBundleから動的にロードされるかになっています。

 

Addressable

Q:LZ4圧縮モードでは、AddressablesがBundleをロードするにはHeadersのみをメモリにロードするので、すべてのアセットをBundleにパッケージ化できますか?このようにして、アセットの粒度とアセットの繰り返しのパッケージ化の問題を回避できますか?

 

A1:ファイルレベルのアセット更新で、しかもAssetBundleが非常に大きい場合、パッケージ全体を再ダウンロードすることと大差ありません。アセットの粒度は、主に更新アセット量を減らすことです。

 

A2:全体的な考え方を共有します。

AddressableですべてのアセットをBundleにパッケージ化し、固定の読み取りパスはUnityEngine.Application.persistentDataPathです。つまり、ローカルは常に読み取られます。実際の経験では、プレイ中にダウンロードするとフリーズが頻繁に発生します。

最初のパッケージは小さなパッケージをリリースします。ゲームが起動されると、アセットの更新がチェックされ、アセットBundle(後続のインクリメンタルパッケージを含む)がC#のHttpWebRequest(ダウンロードを単独で管理)を介してダウンロードされます。、persistentDataPathに一律にダウンロードされます。終了後にゲームのプロセスに入ります。

利点:

1、アセット管理は簡単です。

2、アセット分割の粒度に関係なく。

3、アセットの繰り返しのパッケージ化を考慮する必要はありません。

4、最初の起動時にダウンロードするBundleが多すぎるためにダウンロード速度が遅くなることを心配する必要はありません。

欠点:

まだ考えられず、皆様の指摘をお願いします。

 

A3:アセットのアンインストールの観点からは不合理です。Addressableは、参照カウントによるアンロードを処理します。これは、AssetBundleの参照カウントが0になった場合にのみトリガーされます。トリガーされると、AssetBundle.Unload(true)がコールされます。したがって、この大きなAssetBundleに常駐メモリが必要なアセットの場合、AssetBundleも常駐メモリが必要であることを意味します。そうすれば、短時間の使用後にアンインストールできるテクスチャなどのような未使用のアセットは、アンインストールできません。もちろん、Addressableのロード・アンロードインターフェイスでアセットをロードおよびアンロードすることを前提にしています。

 


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

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

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