あなたのモバイルゲーム開発の最適化時間を数ヶ月節約する方法(UI+ロード篇)

みなさん、こんにちは。こちらはUWA Technologies(略称UWA)です。

今日はあなたのモバイルゲーム開発の最適化時間を数ヶ月節約する方法(レンダリング篇)の続き、次の二パート「UI」「Loading」についてご説明いたします。

前回の文章をまだ読まれていない皆様は、是非こちらへ移動してご覧ください。


UI

UIパーツの主な問題は、UIの再構築です。

UGUIの場合、再構築プロセスはBuildBatch関数SendWillRenderCanvases関数にあります。

NGUIの場合、再構築プロセスはUIPanel.LateUpdate関数にあります。

UI再構築を最適化する方法は? 一般的な答えは、「動的ウィジェットと静的ウィジェットを分離して」ということです。


静止状態

これは実際のプロジェクトのサンプルです。 プレイヤーをシーン内で静止状態にさせて、何もしません。そうすればUIのコストは非常に安いはずですが、プロファイラーから見ますと、やく2.5 msで、少し高いです。

したがって、UIキャンバスを確認すると、右に示すように、UIメッシュに多数の頂点があることがわかります。

最後に、これらの絵文字は2〜3秒ごとに移動することが発見されました。 これにより、UIメッシュ全体が再構築されます。 それが原因です。

絵文字は動的ウィジェットですので、 静的キャンバス全体から分離して、新しいキャンバスに配置する必要があります。 その後、コストが下がれます。

プロジェクト「ラグナロク マスターズ」で、プレイヤーをシーン内で静止状態にさせ、何もしません。それとも、コストは1秒ごとに高くなっています。どうして? それはヒントのせいです。ヒントは毎秒移動し、大きな静的UIキャンバスにも移動しています。それらが再構築することを引き起こし、コストも高くなります。


動く状態

また、プレイヤーが移動すると、右の画像でコストを確認できます。プレイヤーが移動しながら、緑の円もミニマップで移動していますから、ミニマップ全体を再構築することになります。したがって、全体的な静的UIキャンバスから動的ウィジェットを分離することも最適化できます。

 

そして戦う時に、

コストもとても高いです。 (平均CPUコストは約16msです。)

その原因はクールダウンマスクです。 彼らはすべてのフレームを変更し、頻度も高いですから。そこで、彼らを分離して頻度を減らしますと、パフォーマンスを非常に速くなさせます。


結果

UWA GOTを17日間使って最適化した結果、CPU コストは4msから1.7msになりました。

 


ロード

ロードも非常に重要であり、何か問題があったらゲームの実行が非常に重くなります。ロードについては、「リソース管理」「ゲームオブジェクトのインスタンス化」という二方面に注目してください。


リソース管理

リソース管理の場合、最初にはローディングAPIです。 Unityエンジンには、「Resource.LoadとLoadAsync」「AssetBundle.LoadとLoadAsync」の2つのタイプがあります。

UWAレポートには、使用されるAPIと詳しい読み込み情報が記録されています

例えば、この表には、「アセット名」、「そのタイプ」、「どのアセットバンドルから読み込まれたか」、「読み込み時間」、「詳細な読み込みCPUコスト」が表示されています。

また、グラフで詳細を確認できます。 たとえば、この2つのアセットはリソースの読み込みによって、頻繁に読み込まれています。それは問題であり、彼らをキャッシュして再利用する必要があります。そうすればCPUコストも安くなれます。

3つ目は、特別なキャッシュです。 これで、アセットの正確な読み込みコストがわかりました

デバイスメモリが不足しているため、すべてのアセットをキャッシュすることは不可能です。キャッシュできるのは、読み込みの長いアセットのみです。 例えば、PKFightwindowは毎回ロードする時に約3秒要ります。キャッシュに少量のメモリを使用すると、シーンのロードに約3秒節約できて、とても便利です。


ゲームオブジェクトのインスタンス化

ゲームオブジェクトのインスタンス化について話しましょう。 常にパフォーマンスを向上させるため、インスタンス化は非常に重要です。

UWAレポートには、Instantiateの詳細なコール情報が記載されています。

たとえば、GameObjectの詳細な関数名とインスタンス化時間を確認でき、どのゲームオブジェクトに多くのインスタンスが直接生成されているかを確認できます。

また、インスタンス化の詳細なCPUコストも顕示できます。 最適化するゲームオブジェクトを決定することは非常に役立ちます。

Common HitやCommon Binddongと同様に、何度もインスタンス化する代わりにキャッシュでき、パフォーマンスが大幅に向上できます。


結果

ロードの最適化結果は下図のように、平均FPSは16FPSから26FPSに増えました。

 


UWAおよびUWA GOTについてもっと了解したい場合には、UWA公式サイトに移動してください。
UWA GOTを使っていたnowsprintingさんも自身のブログでUWA GOTについて詳しく説明してしましたが、興味があれば「やらなイカ?」に移動してご覧ください。


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

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

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

UI共有図集合併

今回の主な話題:「UI共有図集合併」、「UGUI図集がアンロードできない」、「Profiler のOthersオプションの時間コストの最適化」、「Shader.WarmupAllShaders()コンパイル」…


メモリ

Q1:プロジェクトはUnity 5.6にアップグレードされたばかりで、テスト中にひどい重い現象が出てきた。Profiler実機テストをしたとき、CPUのOthersオプションの時間コストはとても高いと見つけた。しかし粒子コストもAnimatorコストも高くない、これはなぜだろうか?

Unityエンジンには10個以上のモジュールがあるが、Profilerにはっきり見られるのはRendering、Scripts、Physicsなどの六つのみ。他のモジュールの時間コストは全部Othersに統合されている。だからOthersが高いも正常だ。

問題主のProfilerスクリーンショットから見ると、当分のフレーム時間コストは166msであるが、BehaviorUpdateとLateBehaviorUpdateはそれぞれ36msと37msである。いわゆる、パネルの下に多くのCPU時間コストが書いている。問題主にはこのページを検査して、またどのようなコストがあるのを確認必要がある。理論的には、これらの時間を合計すると166msに相当すべきだ。


アニメーション

Q2:プロジェクト中の骨格「Weapon R」の軌跡がおかしかったので、UWAに聞きたい。

私のやり方は:

Step1:@skin.fbxの設定

順次にReset→Enforce T-Poseを実行する。

Step2:アニメーションファイルの設定

Step3:Play。骨格「Weapon R」を観察し、idle→Runに不気味な曲線がある。

上記の設定を繰り返す、@skin.fbxを設定する時にはResetをするのみ、Enforce T-Poseをしなければ、Weapon Rは正常だと観察された。

添付ファイルのプロジェクトを見ると、Weapon Rの骨格が存在するため、Enforce T−Poseの場合、手部の回転がおかしい。Idle→Runの場合、humanoidの補間が乱れ、誤った手部アニメーションが得られ、Weapon Rに影響する。configurationにPose−>BindPoseを使える、これで体の各部位が正しくマッピングでき、そして補間に問題がないことが保証されており。こうやってすればテスト時に「不気味な曲線」が現れていない。またconfigを修正した後にアニメーションfbx中のupdateを忘れないようにしてください。


UI

Q3:今使っているのはUnity 4.7、NGUIである。いくつかの小さなフォントの図集を持っているが,本来は部分機能モジュールに特有のものであり,現在多くの機能インタフェースがお互いに引用されている。ほぼ256×256と512×256のいくつかの図集であるが、これを1枚の1024×1024の大きな共通図集に統合したいと思う。使いやすいが、1024の共有図集はすでに2枚ある、それを加えると3枚の大きい図集になる。NGUIが1024の図集を使い過ぎる時に、GPU にアップロードするにも影響があるか?もしUGUIであればこのような問題も存在するの?注:図集はメモリに常駐させ,独立してパックする。

「GPU にアップロードする」はロードされた後に行われることが多いので、これらの小さな図集が確かに同時に使われることが多いのであれば、1つの1024図に合わせるのが合理的であり、DrawCallの統合にも顕著なメリットがある。小図を大図に合併 するによる影響については、UGUIとNGUIはほぼ同じであるが,UGUIはSprite Packerで確に1枚しか合成されていないかを確認する必要がある。


ロード

Q4:Shader.WarmupAllShaders();には全てのShaderを事前にコンパイルしたか?まだ通常のShaderを1つのPrefabの上に置いて、ゲーム起動時にロードする必要があるの?

Shader.WarmupAllShadersには2つの問題がある。1つはwarmupするのは現在のすべてのShaderだけであり、その後に新たなShaderがロードされていれば、再び解析する必要がある。もしwarmupの時にほとんどのShaderがメモリにあることが保証されている場合、このAPIを使えば十分である;二つ目はこのAPIの時間コストは非常に高い。プロジェクトに使うかどうかを問わず、全てのkeywordsの組み合わせをwarmupするため、Unity 5.0以降はshadervariantcollection.warmupで取り替えるとやってみられる。


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

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

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

Dalvik Heapメモリは高すぎ

今回の主な話題:「Dalvik Heapメモリは高すぎ」、「Unity 5とUnity 2017でのフレームレートが低下」、「Animator.Initialize警告をどのように処理する」…


メモリ

Q1:ゲームに入るばかりの時、Dalvik Heapメモリは異常に高いので、PSSも高く導く。バックグラウンドに一度切り替えて、ゲームに戻すとDalvik Heapメモリはかなり減少した。そして、ネットで調べられたAndroidでGCを呼び出す方法を使ってみた。System.GC、 runFinalizationとの結合、Runtime.getRuntime().gc()を使うなど、全て有効に減少することができない。これを一回有効に呼び出す方法があるかどうか?

原因がわかった。Android層に一つのSplashを書いた。このSplashはpngタイプので、解像度は1920x1080であり。前には

int splash_bg = getResources().getIdentifier(bgName, “drawable”, getPackageName());
m_BgView.setBackgroundResource(splash_bg);

この画像はHideSplashで遊離されており、JavaのGCが呼び出された後に回収される。しかし、実際の画像が100MBぐらい増えさせるはずはない。SplashとSplashVideoだけのテストプロジェクトを使った、コードは完全に同じのに、メモリはそんなに多く増えられない。解釈できるのは、JVM後のあるメモリ配分アルゴリズムは原因になるかもしれない。元々低い場合には配分が少なく、一定の数に達し、再び配分すると、さらに大きな1つのメモリが配分される(Android基層には苦手)。

以降では、まずgetResourcesからBITMAPを取得し、ImageViewに伝える。HideSplashの際に、BITMAPを呼び出すような手動解放方法に変更した。


制作

Q2:一つのMeshRendererに二つの材質がある。他のMaterialPropertyBlocksを設定させたいのに、現在にはできる方法はまだありませんとわかった。RendererからMaterialPropertyBlockを手に入れた後に、指定してある材質に応用することはもうできないでしょうか?みなさんには良い解決策があるのか?

はい、MaterialPropertyBlocksはMaterial単位ではなくMeshRenderer単位である。Meshを分割し、一つのRendererにMaterialが一つしかないを確保すると問題主に提案する 。


パフォーマンス

Q3:最近プロジェクトをUnity4からUnity5やUnity 2017にアップグレードした後、ローエンドモデルでのフレームレートは10以上低下した。Adreno Profilerで調べた結果はGPU Boundである。

社内のゲームはフレームレートへの要求は高いので、ゲームをする時には必ずフルフレームで実行する。だからこの問題は明らかに見られる。努力して、最後に分かったのはUnity5以後、デフォルトでBlitが開いた、解像度が高いほどGPUの圧力が大きくなる。特にローエンドモデルで、私たちはAdreno405でテストした、Unity4ではフルフレームできるが、Unity5やUnity 2017では最高45くらいまで、これはひどい。幸運なのは、Unity2017.2に、公式がBlitの禁止設定を開放したが、Unity5はその運がない。公式からの情報による、当分Unity5.6にこの機能を導入する計画はない。

こちらを参照してください:https://forum.unity.com/threads/big-performance-issue-with-unity5-on-android.338847


メモリ

Q4:この「Triggers RebuildInternalState」は物体を隠す時に必ず引き起こされるか?Profilerの最後列に必ずWarningがあるので、厳重な間違いを感じた。これをどうやって避けるのか?(前にキャッシュしたことがある場合に)Animator.Initializeの時間コストを明らかになさせるか?

これはAnimationの含むGameObjectがDeactiveされたときのエンジンWarning、多くの状況には確かに高いCPU時間コストを導く。それに対して、問題主にGameObjectが要らない時に直接に画面の外に移して、GameObjectをDeactiveするではなく、掛けたComponentをDisableさせると提案する。これでInternalStateの発生をRebuildできる。


Unreal 4 レンダリング

Q5:こんにちは、UWAのグローバルイルミネーションに関する記事を見て、いくつかの質問がある。

1.UnityのLightmapベイクをする時に、なぜNormal mapからNormal情報を得られないの?UnrealのLightmassも二枚の図をベイクする、一枚は方向に一枚は色。その色はNormalMapの影響を受けるの?

2.Unrealの一つシーンには複数枚のLightmapがある。例えば昼から夜にかけて、グラデーションはどのように融合しているか?

1.LightmapにおけるDirectional情報とは、ベイクライトの方向情報である。Lightmapでは、一枚が光線のIntensity を記録し、もう一枚はDirecitonalを記録することである。このDirecitonalはShadingの方向に関する計算を参加するの為、例えば、ハイライト計算やnormal計算など。ただのDffuseでもNormalmapが要らない、このDirectional情報を削除し、メモリ占有と計算量を減らすことができる。通常、材質に見られるNormalmapとは、メッシュのNormalであり、Lightmapに記録されているDirectionalとは一つではない。

2.UnrealにおけるPrecomputed Lighting Scenariosは複数セットのLightmapやイルミネーション設定を保存している。できるのはイルミネーションと合わせてLightmapを切り替えることだけ、今には融合はまだ不可能だ。

Q6:ベイクする時イルミネーションのIntensityはbeastのようにNormalを考慮する。Lightmassベイクする時にはNormalmapを提供できるの?

Unityはベイクする時、放射度を使っている。すなわちまずモデルをブロックに分けて、そしてブロック間の反射を計算して、Normalmapは使わない。Normalmapが提供するのは詳細的な情報であり、グローバルイルミネーションに間接光の計算結果は低周波ので、,高周波の情報を入れると必ず良い効果が得られるではない。Unreal 4のLightmassには、Staticタイプの光源がベイクする時にnormalmapを使わせる設定オプションがあり、project settings->engine rendering->lightingに含まれている。


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

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

UWA公式Q&Aコミュニティ:https://answer.uwa4d.com

UnityアセットAPIアンインストールのテクニック

今回の主な話題:「UnityアセットAPIアンインストールのテクニック」、「Reserved Total Unityメモリ変化問題」、「MangedHeap.UseSizeの値は変化している」。


メモリ

Q1:私かAssetBundleをロードするのため、一つのケースを書きました。複数の特殊効果Prefabをシーンにインスタンス化します。複数回のケースを 実行し続いて、付加された特殊効果対象を全部削除し、シーンを替えますと、Profilerにのメモリ変化が次の図のように見られます:

聞きたいのは:

  1. Profiler内のReserverd UnityメモリはUsed Unityメモリよりかなり高いのが正常ですか。
  2. 正常であれば,Reserverd Unityメモリを回収する方法はありますか。
  3. 上記のようにケースを複数回実行された後、Reserverd Unityメモリは400MBに安定していますが、もう一度ケースを実行したらメモリは450MBまで上昇し、後に400MBまで下がました。このような表現も正常ですか。

1.このデータはエディターでテストした結果ですか。ReserverdはUsedよりこんなに高く超えるのは確かにあまり合理的ではありません;ただし、エディターですれば、実にUnityはたくさんの補助操作を行って、これらもメモリを占用します。ですから、実機でテストをやってみますとアドバイスします。この格差は下げられますかどうかを観察してください。しかし、実機であれば、その差は確かに高すぎて、あまり合理的ではありません。

2.Reserverd Unityのメモリはエンジン自身が管理しています、一般的にその後もう使用しない時に自分から下げます。

3.このような上昇や転落は普通ですが、こんなに高いかどうかは、問題1の回答を見てください。


メモリ

Q2: Resources.UnloadUnusedAssets()が旧シーンをアンインストールした後、新シーンをロードする前にコールすればいいですか。それとも新シーンをロードしたらコールすればいいですか。メモリMaxを考えると前者の方がいいと思いますが、UWAにUWAにある文章はシーンをロードする後にコールの方がいいと肯定しました。

もし問題主はLoadLevel(Async)のような方式でシーンをロードすれば、Unity自身は最下層にResources.UnloadUnusedAssetsみたいな操作を一回行います。この時手動的にResources.UnloadUnusedAssets操作をコールすれば、時間間隔は短いです。これは実に少し重複しています。そのため、新シーンをロード後に再びコールするとアドバイスします。

しかし、もし問題主はLoadLevelAdditiveや似たようなAPIでシーンを替える場合には、UnityはResources.UnloadUnusedAssetsをコールしません。それで旧シーンをアンインストールしたからコールするのもいい選択です。


レンダリング

Q3:ShaderにのBlend OffとBlend One Zeroは完全に等価であると認められますか。UnityのStandard Shaderに見られますのは、ブレンドはBlend [_SrcBlend] [_DstBlend]のようなもので動的にコントロールされています。そしてStandardShaderGUI.csにOpaqueを設定する時、設定されたのはBlend One Zeroでした。ですからShaderにBlend One Zeroを入れったら、Blend Offと等価であると認められますか。Unityはdestbufferからデータを読み込めない為に自動的にblendstateを変えますか。

私たちはUnity 2017.1でテストしました。実にはAndroidプラットフォームのGLESコール中、UnityのStandard ShaderのOpaqueモードがdisable blendの状態でレンダリングされていますと発見しました。実験は下記のように:

設備:Red mi 2。レンダリングシーンは2つのStandard Shader Opaqueモードオブジェクト(SphereとCube)であり、間にUnlit Transparent Quadがあります。

AndroidツールでGLES APIコールを見ますと,CubeとSphereをフレームごとにレンダリングする際にBlendはオフ状態(前フレーム終了時にオフ)であり,Unlit TransparentのQuadをレンダリングする際に開きます。

この中に,36個頂点のDCはレンダリングCube, 2304個頂点のDCはレンダリングSphere, 6個頂点のDCはレンダリングquadであります。ですからStandard ShaderのOpaqueモードはglDisable(GL_BLEND)状態でレンダリングされるはずです。


メモリ

Q4:ゲームに毎回ステージをクリアしてホームに戻る時、メモリデータはいつも不一致です。Unity Profilerを通じてManagedHeap.ReservedUnuseSizeとManagedHeap.UseSizeの値はずっと変化していますと観察されました。この変化は合理的ですか。

ReservedUnuseSizeとManagedHeap.UseSizeはずっと変化していますのは正常です。いずれもMonoメモリに属しており,前者は現在のMonoメモリが使用されていない部分です,後者は現在使用されている部分であります。一般的に、ゲーム内のMonoメモリはコードで割り当てられています。ですからこの二つの値はいつも変化していますのは正常な状況です。

ここで問題主に以下の2点に注目することを提案します。

⑴総Monoメモリはずっと上昇していますか。

下記の図にはUWAパフォーマンスレポートのMonoメモリの傾向グラフです。紫色の線はプロジェクト実行中のManagedHeap.UseSizeであり、黄色の線はReservedUnuseSizeです。両者ともずっと変化していますが、最も注意すべきのは青い線のReserved Monoであります。この線が上に行くと,プロジェクトにはメモリリーク問題がある可能性が高いので,開発チームに精査すると提案します。

⑵具体的なMonoメモリの割り当ては合理ですか。

ManagedHeap.UseSizeやMono総メモリはコードのMonoメモリによって上昇していますから、コードMonoメモリの割り当ての合理性をチェックし、必要のないMonoメモリ割り当てを避けるのは大事なことです。下記のように:


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

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

UWA公式Q&Aコミュニティ:https://answer.uwa4d.com

あなたのモバイルゲーム開発の最適化時間を数ヶ月節約する方法(レンダリング篇)

みなさん、こんにちは。こちらはUWA Technologies(略称UWA)です。今日は「あなたのモバイルゲーム開発の最適化時間を数ヶ月節約する方法」について、可能の解決策を提供したいと思います。去年のCEDEC 2019にご参加した皆様にはイメージがあるかもしれませんが、知らない人々に弊社または弊社の製品を紹介したいと思います。


UWAとは

UWA Technologiesは、モバイル/VR/ARなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサル ティングサービスを提供している会社です。

UWA Technologiesが提供している「UWAローカル分析ツール」と「オンラインソ リューション」は、中国でTencent、Neteaseから始め、2,500以上の開発チーム、3,000以上のプロジェクトに採用され、実機に基づいたパフォーマンステストレポートが開発のボトルネックをより簡単に解決でき、中国のゲーム業界の急発展に大きく寄与しました。

「Make it Simple」という企業理念に基づいて、弊社は今後、日本でも製 品やサービスを展開し、皆様と共に日本のゲーム業界の発展に貢献できる ように一生懸命努力してまいります。

弊社のクライアント

弊社が成立した5年間にたくさんのゲーム会社や開発チームとの合作経験があります、最適化の速さとサービスの良いさによく高評価させております。下図に中国での名作ともう日本に登録した作品をいくつ例としてあげますので、この中に皆様がご存知しているプロジェクトはありませんか。

私たちの経験

弊社が成立されたばかりの時、市場を占めているモバイルゲームはほぼカードRPGであり、シーンも小さくて、ちょっとシンプルなものでした。

その後、アクションRPG、MOBA、MMORPGなども増えてきました。

現在、もっと複雑なゲーム、例えばオープン・ワールド・シューティングやオープン・ワールド・サンドボックスは大人気になりました。

見られやすいのは、過去の4年間に、モバイルゲームは複雑になり、2Dから3D、小さなシーンから大きなシーン、プレイヤーが少ないから多くなります……最適化も重要になります。

これは弊社のデータベースにおけるモバイルゲームのパフォーマンス傾向です。上の線はRedmi Note2でのCPUコストです、ローエンドモデルの代表と認められます。下の方はSamsung S6でのデータで、ミドルローエンドモデルの代表と認められます。

約3年前のCPUコストはとても高いと見られます。ただし、2017年以降、ゲームが複雑になってきましたが、CPUコストは下がっています。これは「モバイルゲームのパフォーマンスはだんだん良くなっている」という意味です。2,000以上のゲームからこのデータを得ましたから、もしかしたら、これはモバイルゲーム史上初めての大規模な「全体的なパフォーマンス上昇」かもしれません。

そのため、市場競争から取り残されないように、質の良いゲームを作ることが重要になっています。


UWA GOT とは

GOTはGame Optimization Toolkitの略称で、Unityアプリのプロファイリングを行なう商用ツールです。UWA GOTを使って、テストプロジェクトの各種データも使っている関数も直接にグラフやリストで見られます。何処かに悪いパフォーマンスや問題を起こす可能性があれば、ヒントもさせ、可能の解決策も提供します。ゲームの開発と最適化に役に立ちます。

UWA GOTは「Rendering」、「UI」、「Loading」と「Memory」4つの方面を分析でき、全方的にプロジェクトのパフォーマンスを検査します。


レンダリング

レンダリングのパフォーマンスに対して、問題の鍵は透明レンダリング不透明レンダリングに集めています。下図のように、透明レンダリングは総体の約50パーセント(赤枠)、不透明レンダリングは約37パーセント(青枠)を占めています。二つともにUWA GOTレポートに毎フレームのCPUコストが詳しく見られます。

レンダリング最適化のボトルネック、ドローコール三角形数もレポートに顕示されます。

ドローコールを最適化する最も一般的な方法は、ドローコールのバッチ処理です。 詳細はUnityマニュアルをご覧ください、こちらには説明しません。ここでシェアしたいのは、二つの実際によく遭う「ドローコールのバッチ処理を影響する」問題です。

1つ目はMaterial instanceです。 この画像では、木と草がバッチ処理されていないことがわかります。 どうして? 右側のインスタンスマテリアルは原因になります。マテリアルは同じように認めますが、Unityはそれらを異なるものとして処理するため、バッチ処理できません。インスタンスマテリアルを生成しないために、Material Property Blockを使用してMaterialパラメータを変更する必要があります。また、大量の草、木や石のある場合、レンダリングにはGPUインスタンスを使う必要があります。 ドローコールを減らすためには非常に便利です。

2つ目は、異なるLightmapです。 ゲームオブジェクトが異なるライトマップに属している場合もバッチ処理できません。例えば、このプロジェクトには24のライトマップがあり、解像度は512 x 512です。したがって、1024 x 1024でライトマップをリベイクし、ライトマップ数は6になるため、バッチ処理が大幅に改善されます。

三角形については、単純化する必要があります。このスクリーンショットでボトルネックがすぐ見られます。こちらの三角形数は非常に多いです。 カメラがLandから遠く離れているのがわかります。ですから、カメラにはより多くのゲームオブジェクトを捕まれています。 それが原因です。ここではMeshLab、SimplygonまたはUnity LOD gourpなどのLOD(Level of Details)で三角形を単純化でき、役に立ちます。

スキンメッシュの最適化方法も同じです。ドローコールを最適化し、三角形を単純化してください。

UWA GOTレポートでは、どのスキンメッシュに頂点と三角形が多いかを表示でき、開発者が迅速に最適化できます。


プロジェクト《キワミ》では、武将たちの三角形はすべて1500未満です。だからローエンドモデルでも、レンダリングコストはとても低いです。

また、GPUスキニングとGPUインスタンス化を使って、ドローコールを最適化し、CPU計算をGPUに変えることもできます。こちらに2つの便利なオープンソースプロジェクトをお勧めします。

https://github.com/Unity-Technologies/Animation-Instancing

https://github.com/chengkehan/GPUSkinning

最後に最適化する結果を見でください。UWA GOTを使って、40日間の最適化処理後、CPUコストは8.2から6.2に減少しました。


UWAおよびUWA GOTについてもっと了解したい場合には、UWA公式サイトに移動してください。
UWA GOTを使っていたnowsprintingさんも自身のブログでUWA GOTについて詳しく説明してしましたが、興味があれば「やらなイカ?」に移動してご覧ください。


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

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

UWA公式Q&Aコミュニティ:https://answer.uwa4d.com

アセットの同期/非同期ローディング

今回の主な話題:「アセットの同期/非同期ローディング」、「Physics2D浮動小数点数衝突」、「SendWillRenderCanvasコスト」…


UI

Q1: 二つのフォントコントロールは毎フレームに異なる数字を表示し、1つ目が8文字、2つ目が6~7文字であります。認識のためにoutlineを開く必要があり、高いパフォーマンスコストを引き起こします。この2つのコントロールを別々に独立のCanvasに置いても、問題は依然としてあります。今が分かれるのは、このコストは二つのフォントコントロールの毎フレームのテキスト変更によって引き起こされます。

UIの配置は下記のように。

引き起こされたコストは下記のように。

コメントに「一つが8文字、もう一つは6〜7文字」で言いながら、二つともoutlineを開きました。最初に「この二つを禁止された後、SendWillのコストはなしになるかどうか」をもう一度確認すると提案します。この数字を見るとそんなに高いコストを引き起こす可能性は高くないです。

次に、もしこの二つは確かに原因であれば、outline効果あり静的フォントに変えるかどうかが考えられます。できなければ更新頻度を下げることができるかどうか、本当に毎フレームに変化必要はありませんかを考えてください。

もしこれ以上下げたいなら、静的フォントしか考えられません。テキストは確定なら処理しやすいが、チャットのように次の内容は分からない場合には仕方がありません。あるいはローエンドモデルにシャドウでやります。


物理

Q2:ゲームシーンに一つのboxcollider2Dがあり、位置は(0.0f,0.0f) から (1.0f,1.0f)、Physics2D.BoxCast(new Vector2(1.0f,1.702), Vector2(1.0f, 1.4f), 0, Vector2(0.0f,1.0f), 2.0f)を採用したら衝突が引き起こします。理論上衝突の境界は1.700であり、私はすでに位置を1.702に置いて、浮動小数点数の誤差を避けたはずです。もしこの値を1.706に拡大すれば衝突は発生しませんので、この誤差の範囲はどちらに調整できますか。

Unity 2017.1のPhysics2DSettingsに一つのDefault Contact Offsetがあり、二つcolliderの間の距離は彼らのContactOffsetの足し算の結果より小さいなら衝突が発生します。この値を小さく設定しますと問題主の質問が解決できはずです。下図のように:

Unity 5.xのContact Offsetは,デフォルトで0.01であります。これも1.702ではできませんが,1.706ではできる理由であります。


レンダリング

Q3:UWAにある文章がMaterialPropertyBlock方式でMaterial属性を操作するとおすすめし、効率を上昇できると説明されました。ShaderLab: Propertiesファイルを調べる時、このような文が書いてあります。

[PerRendererData] - indicates that a texture property will be coming from per-renderer data in the form of a MaterialPropertyBlock. Material inspector changes the texture slot UI for these properties.

これに質問があります。Shaderバラメータは[PerRendererData]で記述すべきかどうか、MaterialPropertyBlock操作に対して影響がありませんか。「使う」と「使わない」二つの状況を試しましたが、表示効果はいずれも正常でした。

理論的に[PerRendererData]はEditorの表示行為のみ改めません。問題主がMaterialPropertyBlockを使って、あるMaterialのTextureを変えた後に、これを加えるしかプレビュー対応のMaterialパネルにこの新しいTextureが見られません。

下記の図1はPerRendererDataのない場合に、EditorでまたRuntime時に表示された内容です。PerRendererDataを加えた後に、図2はEditorで、図3はRuntime時に表示された内容です。

図1

図2

図3


ローディング

Q4:現在、Resources.Load()でアセットをロードする時、UIアニメーションに重い現象がよく現れます。解消したいなら、非同期ロードする、Prefabを分割するや材質メッシュアニメーションを最適化するみたいな操作しか実現させませんか。それともUIアニメーションは他のスレッドで再生されませんか。非同期する速度は絶対に同期するのより遅いですか。

非同期ロードは同期ロードの重い現象を緩和することができますが、効果はあまりよくないです、こちらの文章を参考してください。アセット分割りを試し、同一時間にロードしないようにすることをおすすめします。即時表示されたUIや他のGameObjectではなければ、時間がかかる部分的なアセット(Atlas、Shadderなど)を事前にロードしようと試みることができます。即時表示されたUIであれば、非同期ロードはこの要求を満たすことができませんので、考える必要がありません。

非同期ロードの速度は絶対に同期ロードより遅いではありません。ただ、一般的にはそうであります。しかし、具体的にいくら遅いかは、ロードされたアセットの種類と量次第です。


アニメーション

Q5:ゲーム内対戦時には頻繁に武器を変わるやスキルを使う時(主にネットワークプレイヤー)、違う動作を取り替えます。ただし、毎回animatorOverride[name]=clip(3〜6個)を設定しますと、CPU占有は50-180msであり、これはどうしてですか。 公式の指導により一つのリストを保存しました(https://docs.unity3d.com/scriptreference/animatoroverridecontroller.applyoverrides.html)、毎回LateUpdateをする時ApplyOverridesを使って、占有はより高くなる(400ms)と発見されました、これはどうやって解決できますか。現在各ネットワークプレーヤのプレイヤOverRidesCountは73であり,Clipが多すぎるの原因ではありませんか。

実機で実行する時、animatorOverride[name]=clipの時間コストはanimatorcotrollor中のclipに影響され、数が多くなるにつれて時間コストが著しく増え、70個以上のclipがあれば時間コストは確かに50ms(Redmi note2)以上になれます。しかし,applyOverrides法に変えても時間コストは高いです。またMonoメモリの割当ても現れますが、400ms程度にはなれません。

一方、AnimatorOverrideControllerを全体的に変えることも試しました。すなわち、現用使っているAnimatorOverrideControllerにclipを取り替えるではなく、別のoverridecontrollerでclipを取り替えた後、全体的にruntimeAnimatorControllerに取り替えます。これでコストを低くなされます。


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

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

UWA公式Q&Aコミュニティ:https://answer.uwa4d.com

アートアセット導入管理

今回の主な話題:「アートアセット導入管理」、「Camera Layer MaskでUGUIを最適化する」、「ベイク効果エラー」など。


ロード

Q1:毎回アートアセットを大量に導入する時、構築されたバージョンは「材質リファレンスが失う」、「Animator Controllerリファレンスエラー」、「スタンプリファレンスエラー」などのアセットリファレンスエラーがよく出てきます。ローカルでのアートアセットは正しいです、別人のパソコンのエディターで見るのも正しいです、ビルドエディターから見るのも正しいですが、構築されたBundleは壊れました。時々Bundleを削除して再編しますと解決できますが、時にはできません。今、この状況にあったら、解決策はプログラム同僚がビルド機でMetaを削除してもう一度Prefabを作るしかありません。

これはUnityのBugですか、何か避けるまたは最適化する方法ありませんか。今、私たちはPerforceを使ってUnityプロジェクトを管理していますが、アートアセットを管理する時、もっといい流れはありませんか。

私たちのプロジェクトがあった問題について推測します。プロジェクトアセット導入のあるところに問題がある可能性は高いと思います。以下の問題があるかどうかをチェックしてくださいい。

⑴難読化コードを使っていますか。Prefabのスクリプトを難読化しないリストに添付することを忘れたしまい。直列化されたフィールドが難読化された、BundleしたPrefabアセットがロードする時、スクリプトにリファレンスエラーが出てきます。

⑵すべてのアセット導入はOnPostProcessをリロードしてアセット設定を処理します。この一環には何か不合理なところを改めましたか。例えばリファレンス関係を破壊しました。

⑶AssetBundleをパッケージする時、Bundleを構築前にファイルでAPI(UnityのAssetDatabaseのAPIではありません)を操作して直接にあるフォルダを改めたや他のリファレンス関係を破壊可能性のある操作をやって、Bundleを構築し、フォルダ名を復元しました(またはアセットを初期状態に還元しました)。これで、リファレンス関係を失う確率が高いです。

⑷パブリッシュでみては正常ですが、Perforceに改めたMetaファイルもういっぱいあります;このような問題はローカルでA1A2二つの同じアートアセットが違うフォルダにあります。A1はバージョンに制御されていますが、ある操作でローカル臨時アセットA2は元A1のGuidを使いました。本来正確なA1は間違えた新生成したguidを使用させられた(両者交換のように)。そしてA1のMetaは他人とリファレンスを失います。あるいはアップデートして、ローカルで新しいGuidを配分します。アートディレクターはよくこのmissを犯します。

⑸私たちが使ったのは使ったのは5.3.8p2、先週bugみたいな問題に会いました。アーティストが一組の重複なアセットをアップロードしました。アップロードしたら、全て再びGuidを生成します。しかし、たくさんのMetaをUnityにもう一度導入した後、バージョンコントロールに消えましたが、修正効果はまた残ってあります。

⑹もし全部なければ、最小排出法を試すしかありません。プロジェクトの大部分のアセットを削除し、少しずつ増加し、パッケージし、再現し、原因を排除します。出来ないならコードを削除し、少しずつ追加し、パッケージし、再現し…時々愚かな方法もう良い方法です。


UI

Q2:私はUGUIで一つのUIRootを使いました、タイプはScreen Space –Camera、カメラのCulling Maskを使います。もしUIRootが可視であれば、下のUIサブジェクトに不可視Layerを設定しても、削除されないではないですか。何か解決策がありませんか。

UGUIのメッシュ合併はCanvasを単位にするため、CancasのLayerを変更するだけで有効になれます。個別UI要素だけの隠しや現れを速くしたいなら、Scale=0でやると考えられます。Scaleは0の時UIの頂点情報は空になります。そのために隠す時にはメッシュ再構築に参加しません。


レンダリング

Q3:Unity 5.5.4で建物をベイクします(Windowsプラットフォームの下)と、中央の階は黒くなりました。これはどうしてですか。一つの方向ライトしか使いませんでしたが、ベイクする時環境色は白を使いました。

私はある解決策を見つけました。一つのLightmapParametersを生成して、中のBackfaceやToleranceを小さな値を替えればいいです。こちらに使ったのは0.2です。


UI

Q4:NGUI(3.11.1)、Unity5.6.4バージョンに二つのPanelコントロールが出現した後、RenderQで特殊効果階層の失効状況を制御します。具体的な操作は:

一つのUIRootに二つのPanelがあります。Panel AにあるスクリプトparticleLayerControl.csでRenderQをコントロールして、UIの効果階層問題を解決します。もう一つのPanel B(一つの空のPanel、Layer<Panel)があるの場合には、効果は永遠に最初に描かれた問題は起こる。

Panel Bのない場合には正常です。FrameDebugで発見したのは、Panel Bをオンされる時、特殊効果は永遠に最初に描かれます。しかし、RenderQの値を読み込みますと、特殊効果はUIより大きく成りました。原因は分わかりません。

これは新版NGUIの原因です。UI PanelにもSorting Order概念を入れました。Panel Bをオンしますと、Panel AのSorting Orderが0から1に変化し(Panel BのDepthはPanel AのDepthより小さい)、この際に粒子のSorting Orderは0のままなので、取り替えられました。Panel Bを禁止させ、またはPanel BのDepthを40(Panel Aのより大きい)に変えれば、粒子を現されます。

そのために、particleLayerControlの中にSortingOrder処理を入れ、すなわち粒子のSortingOrderと所在するUI PanelのSortingOrderを常に同じように保持する必要はあります。


Unreal 4 レンダリング

Q5: Unreal 4のMovable光源のShadow Map Cacheについて質問があります、具体的な更新策はどのようなものですか。動的な物体と静的な物体の関係をどうやって処理しますか。Shadow MapをCascadeする必要がありませんか。

Cry Engineのドキュメントも参考にしました:http://docs.cryengine.com/display/SDKDOC2/Cached+Shadows

Unityに移植する可能性はありませんか。あるいは,大面積リアルタイムシャドウの問題(光源の方向が変われ,大部分の物体は動的な物体ですが、頻度はあまり高くない)に対して、解決策はありませんか。光源Spaceで事前にデータをベイクして光源方向を変化させ、一つのShadow Mapで出来ますか。Directional Light Mapのような空間を作れませんか。

Unreal 4のMovable LightのShadow Map CacheはStatic、Stationaryのみ使えます。ですから、実はMovableに照らされるStaticのシャドウの計算を最適化させたいです。しかし、モバイル端末ではMovableを使う必要はありません、Stationaryで良いです。Staticオブジェクトのシャドウは事前に計算されました。

Unreal 4の動的オブジェクトはシャドウを計算する時には二回計算します。一回は静的シーンから動的オブジェクトに投影され、もう一回は動的オブジェクトから静的シーンに投影される時です。静的シーンから動的オブジェクトに投影されるシャドウを計算するために、エンジンは一枚の静的シーンのShadow Mapをキャッシュします。そして、動的オブジェクトに対しても静的シーンからの正確なシャドウイングを受けられますが、この方式は時間がかかり、mobileもサポートしていません。

Unreal4にもUnityの静的シーンが動的オブジェクト投影されるシャドウみたいな解決策を提供しました。同じようにshadowの予想結果を間接光情報(もうSH)のある点群(UnityにはLight probe)に貯めます。そして動的オブジェクトの位置によって点群からシャドウシャドウイングを計算されますが、この方式でオブジェクト全体的な輝度変化のみ取得できます、シャドウを正確に計算できません。Unreal 4にはモバイルで後者をお勧めします。

なお、Unityで動的オブジェクトが静的オブジェクトからのシャドウベイクを受けることを解決するのもLight Probeを採用しています。問題主が言いましたのは動的光源と動的オブジェクト、一番良いのはリアルタイムシャドウ計算であります。Shadow Map Cacheを採用して最適化するの場合には、具体的なシーンや要求を考え必要があります。複数のShadow Mapをベイクすることを事前計算するために、二つの要素を考えなければなりませんー光源の変化と動的オブジェクトの変化。もし動的オブジェクトや光源の変化頻度は高くなければ、サンプリングしてShadow Mapを事前計算することはできませんが、このようなShadow Mapのサイズやメモリコストは不明であり、試してみなければ分からないかもしれません。

 

Unreal 4の実現について、他の人もう詳しく分析しました。Unreal 4のソースコードShadowSetup.cpp/ShadowDepthRendering.cppを参考し、SDCM_StaticPrimitivesOnlyに関するコードを検査すれば良いです。ここに他の問題を答えます。

1 移動している静的オブジェクトにどうする

携帯で完璧にするのは難しいので、可能の方式は静的なオブジェクトに一枚のSMをレンダリングします、動的オブジェクトにはplanar shadowを使用できます。

2 Shadow Map Cascade

キャッシュなら、Shadow Mapは同時に更新することができません。もしカメラが頻繁に長距離移動しますが、cascadeはカメラに追従して同時に更新できませんと、過度は不自然になるかもしれません。これはプロジェクトの特性により考えすべきことです。

3 光源は動けるかどうか、一枚のShadow Mapでできるかどうか

これは動き次第です。日光を模擬する場合には、角度は小さいのにシャドウの精密計算を放棄しかできません。ある空間にシャドウの存在を判断する時偏角を加えて、シャドウを平行四辺形に変形のようにします。360度回転をしたい場合に、今はまだcacheと回す時を両立する方法はありません。結局、オブジェクトの四つの面は違うので、一枚のshadow mapで平行四辺形に変形するのは不可能です。


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

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

UWA公式Q&Aコミュニティ:https://answer.uwa4d.com