
今回の話題:
1)UIにおいてSetActiveが大量に使用されるなら、どのように最適化するか
2)ASTC圧縮とETC2圧縮によって生成されたAPKパッケージの問題
3)PNG画像形式とTGA画像形式の問題
4)ゲーム実行のクラッシュの問題
5)AssetBundleの読み込み方法に適用できる環境
UI
Q:UIの日常開発では、特定のGOを表示または非表示にするために、多くのSetActive(true)/(false)コードが使用されます。しかし、SetActiveのコストが大きすぎるので、SetActiveを使用したくありません。他の解決策はありますか?
A1:この状況には、Active/Deactiveのコストには主にいくつかの側面があります。
- C#層からNative層へのシャトルコール速度は、C#層よりも遅くなります。
- UI要素を変更すると、所属Canvasが変更され、関数Canvas.SendWillRenderCanvases()およびCanvas.BuildBatch()がトリガーされ、高い時間コストを引き起こします。
- UI要素のメッシュ頂点配列を変更すると、MONOメモリの割り当てが発生し、GCがトリガーされ、高い時間コストを引き起こします。(ただし、UI要素の位置を移動したらMONOメモリの割り当ては発生しません)。
したがって、最適化は次の点からも考慮することができます。
- C#層で変数を設定して、対応するGOがActive状態かDeactive状態かをマークし、ActiveオブジェクトではSetActive(true)を回避し、非activeオブジェクトではSetActive(false)を回避します。ActiveでSetActive(true)を実行すると、「最下層」が判断を下しますが、コールした際、最下層はすでにC#層からコールされているため、コストが高くなります。 C#層で適切に判断することで、最下層に判断させることを回避できます。
- 頻繁に変更されるUI要素とまれに変更されるUI要素を別のCanvasに配置して、UI要素の変更による時間コストを減らします。
- UI要素の座標をCanvasの範囲外に移動して表示および非表示にし、SetActiveの時間とSendWillRenderCanvasesの時間を回避します。
- テスト後、Componentにenabled = falseの操作を行うことは、GOにSetActive(false)の操作を行うことより時間が少なくかかりません。
- CanvasGroupコンポーネントを追加して透明度を設定することにより、表示と非表示を表します。
A2:最近最適化を行い、この問題も気づきました。特に、ImageとTMPTextがハングアップされている時にSetActive場合、時間コストがもっと長くなります。そして、次の側面から最適化しようと思います。
- UICanvasをハングアップものに対し、Layer層を直接変更します。
- UICanvasをハングアップしないものに対し、CanvasGroupをハングアップしてAlphaを制御するように変更します。ここにはやや面倒なところがあります。こちらのプロジェクトは長い間開発されたため、インターフェイスの方に、制御が必要なノードにCanvasGroupをハングアップさせることは現実的ではありません。実行時にコンポーネントを動的にハングアップことには、パフォーマンスに関するいくつかの懸念があります。そのため、実行時にActiveの変更が発生するノードに見たら、対応するPrefabにCanvasGroupコントロールを追加することで、PrefabがCanvasGroupコントロールをうまく補足するようになります。正式なリリース後、欠落がない場合は、SetActiveを直接使用してください。
- CanvasGroup方法は欠点があります。つまり、Alphaだけが変更され、レイアウトは引き続き使用されるため、親インターフェイスはLayoutであり、CanvasGroupは使用できません。最初の計画は、SetScale0とSetActiveの時間コストを比較することです。どちらも、再描画を引き起こすはずです。
Texture
Q:空のプロジェクトで、2048 * 2048の大きな画像をいくつか入れました。ETC24bitsで圧縮した場合、1枚のシートのサイズは2MBで、ASTC6X6で圧縮した場合、1枚のシートのサイズは1.8MBです。
個人的な理解によると、ASTC圧縮形式で生成されたAPKは小さいはずですが、まさか予想と正反対とは思いませんでした。ETC2圧縮で作成されたAPKは21.1MB、ASTC圧縮で作成されたAPKは25.7MBです。
ETC2で圧縮されたパッケージが小さいのはなぜでしょう、ASTCによって作成されたAPKは大きいのはなぜでしょうか?
A:占有されているパッケージのサイズと、EditorのPreviewインターフェイスに表示されるサイズは異なるものです。
Previewインターフェイスに表示されるサイズは、ASTCまたはETC2のアセットのサイズであり、パッケージ化後、そのアセットはさらに圧縮されます(LZ4またはLZMA)。 LZ4に圧縮されたETC2が占めるパケットのサイズは、LZ4に圧縮されたASTCが占めるサイズよりも実際に小さいとしか説明できません。理由は、特定の圧縮アルゴリズムの実装によって異なります。
AssetBundleを使用して確認できます。AssetBundleパッケージ化時にNoCompressionが選択されている場合、確かにASTC形式はETC2形式のAssetBundleパッケージよりも小さくなります。 LZ4またはLZMA圧縮を選択した場合、ETC2形式のAssetBundleはASTC形式のAssetBundleよりも小さくなります。
Texture
Q:アーテイストによると、透過なチャンネルの画像があり、TGA形式である必要がありますが、透過なチャンネルがないため、PNG形式にすることはできません。Unityで透過なチャネルがあるPNG形式があるのは、なぜですか?どのようにしてアーテイストにPhotoShopでPNG形式の画像を作成させ、それでも効果を満足させますか? Unityの2つの図の違いの原理について詳しく説明していただけますか?
A1:PhotoShopにはPNG用の透過なチャンネルはありません。エクスポートしても、RGB3チャネルのみをエクスポートできます。PNGピクセルの透過度情報を変更するには、マスクを使用する必要があります。
アーテイストに、「この情報はマスクに描かれています。黒――透過、白――不透過であるように」のように伝えたら、理解してくれたと思います。
A2:TGAアーテイストを選んだ方が容易く処理もらえます。PNG形式の違いを気にする必要はありませんから。PhotoShopでAlphaを扱う必要もありません。結局のところ、エンジンはさまざまなプラットフォームに従って圧縮する必要があります。プロジェクトの規模に気にならない場合、より便利なプロセスが鍵となります。
Android
Q:ゲームを一定時間実行すると、以下のように一部のマシンがクラッシュします。皆もこのような状況に置かれることがありますか。
JNI ERROR (app bug): global reference table overflow (max=51200)
Unity 2018.3には関連するコンテンツがあると気付いたのです。今使用しているバージョンは2019.4.10で、修正されているはずですが、解答お願いいたします。
A1:JNIのコール回数が多すぎませんか?以前に試しましたが、Tencent Voice のAPI JNIを呼び出し続け、一定時間実行するとクラッシュします。問題主のおっしゃったのと同じようです。
A2:AndroidJavaClassとAndroidJavaObjectが頻繁にNewだけで、Disposeを呼び出さずにが発生するはずです。
A3:次の情報を参照してください。
2019.4.21f1 Release Notes
Fixes
- Android: Fixed Java local reference leaking when using AndroidJavaClass/Object. (1283209)
https://unity3d.com/unity/whats-new/2019.4.21 のFixesに載っています。
AssetBundle
Q:AssetBundleロード方式の適用可能な環境に関して、AssetBundle.LoadFromMemoryおよびAssetBundle.LoadFromStreamの適用可能な環境は何ですか?
A1:AssetBundle.LoadFromMemory
- UnityWebRequestによってダウンロードされたAssetBundleアセットを使用し、使用後にローカルに保存しないでください。
- 暗号化要件のあるAssetBundleアセット。
AssetBundle.LoadFromStream
- 暗号化要件のあるAssetBundleアセット(メモリ値は理論的にはAssetBundle.LoadFromMemoryよりも小さいです)。
- Androidでは、StreamingAssetsディレクトリからコピーしてストリームを作成する必要があります。
A2:アセットを暗号化する必要がある場合は、最初にAssetBundleをメモリに読み込み、復号化してから、AssetBundle.LoadFromMemoryを呼び出してロードすることができます。この方法のメモリの最大使用量は、少なくともAssetBundleの2倍になります。「AssetBundleの原則とベストプラクティス」(中国語注意)を参照してください。
AssetBundle.LoadFromStreamはストリーミングモードでロードできます。すべてのAssetBundleをメモリに読み込んでから復号化してロードする必要はありません。代わりに、Bufferのようにその中で一部を読み取り、復号化することでロードできます。その方法はあまり大きなメモリを使用しませんから。このインターフェイスを使用する場合は、継承されたFileStreamクラスをカスタマイズしてから、ReadとWriteの方法でByte配列に対して、暗号化および復号化処理を実行する必要があります。
具体的な使用法については、https://www.xuanyusong.com/archives/4607を参照してください。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com
これも興味あるかも
-
原理から応用まで ゲームでの動的解像度
January 4, 2023 -
Unityゲームの使用メモリを最適化しよう
December 21, 2022 -
ASTC テクスチャ圧縮形式の紹介
December 14, 2022