3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UIにおいてSetActiveが大量に使用される問題

Posted at

今回の話題:
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のコストには主にいくつかの側面があります。
1.C#層からNative層へのシャトルコール速度は、C#層よりも遅くなります。
2.UI要素を変更すると、所属Canvasが変更され、関数Canvas.SendWillRenderCanvases()およびCanvas.BuildBatch()がトリガーされ、高い時間コストを引き起こします。
3.UI要素のメッシュ頂点配列を変更すると、MONOメモリの割り当てが発生し、GCがトリガーされ、高い時間コストを引き起こします。(ただし、UI要素の位置を移動したらMONOメモリの割り当ては発生しません)。
したがって、最適化は次の点からも考慮することができます。
1.C#層で変数を設定して、対応するGOがActive状態かDeactive状態かをマークし、ActiveオブジェクトではSetActive(true)を回避し、非activeオブジェクトではSetActive(false)を回避します。ActiveでSetActive(true)を実行すると、「最下層」が判断を下しますが、コールした際、最下層はすでにC#層からコールされているため、コストが高くなります。 C#層で適切に判断することで、最下層に判断させることを回避できます。
2.頻繁に変更されるUI要素とまれに変更されるUI要素を別のCanvasに配置して、UI要素の変更による時間コストを減らします。
3.UI要素の座標をCanvasの範囲外に移動して表示および非表示にし、SetActiveの時間とSendWillRenderCanvasesの時間を回避します。
4.テスト後、Componentにenabled = falseの操作を行うことは、GOにSetActive(false)の操作を行うことより時間が少なくかかりません。
5.CanvasGroupコンポーネントを追加して透明度を設定することにより、表示と非表示を表します。


A2:最近最適化を行い、この問題も気づきました。特に、ImageとTMPTextがハングアップされている時にSetActive場合、時間コストがもっと長くなります。そして、次の側面から最適化しようと思います。
1.UICanvasをハングアップものに対し、Layer層を直接変更します。
2.UICanvasをハングアップしないものに対し、CanvasGroupをハングアップしてAlphaを制御するように変更します。ここにはやや面倒なところがあります。こちらのプロジェクトは長い間開発されたため、インターフェイスの方に、制御が必要なノードにCanvasGroupをハングアップさせることは現実的ではありません。実行時にコンポーネントを動的にハングアップことには、パフォーマンスに関するいくつかの懸念があります。そのため、実行時にActiveの変更が発生するノードに見たら、対応するPrefabにCanvasGroupコントロールを追加することで、PrefabがCanvasGroupコントロールをうまく補足するようになります。正式なリリース後、欠落がない場合は、SetActiveを直接使用してください。
3.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で、修正されているはずですが、解答お願いいたします。
image.png

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 Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析最適化ソリューション及びコンサルティングサービスを提供している会社でございます。

今なら、UWA GOTローカルツールが15日間に無償試用できます!!
よければ、ぜひ!

UWA公式サイト:https://jp.uwa4d.com
UWA GOT OnlineレポートDemo:https://jp.uwa4d.com/u/got/demo.html
UWA公式ブログ:https://blog.jp.uwa4d.com

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?