URP複数のカメラのパフォーマンスの最適化に関して

今回の話題：
1）URP複数のカメラのパフォーマンスの最適化に関して
2）Unity Addressablesがパッケージ化する時に、BuildAssetBundleOptions.DisableWriteTypeTreeを設定する方法
3）Unrealは、商用ゲームのホットアップデートプログラムとして使用できます
4）UGUI SpriteAtlas使用中にコールバックがインスタンス化され、AtlasRequestedとStartの順序が逆になります
5）AssetBundleからレンダリングパイプラインが動的にロードされ、後期のレンダリングが異常になります。

---

##Rendering

*Q1：URP7.4.3、メインカメラを除いて、撮影したモデルをゲームのメインUIにレンダリングするために使用されるサブカメラもあります。Profilerで以下の状況が見えます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/ffd034ba-9362-ff95-e4ae-337b79354246.png)*


上に示したように、LODの計算はサブカメラでも実行されますが、サブカメラのCullingMaskにはRTModelというLayerのみが有効され、このレイヤーには一つの3Dオブジェクトしかがありません。通常、サブカメラCullScriptableの部分のコストは存在しないはずですが、今は以下のような原因が考えられ
ます。つまり、URPがBase Cameraごとにこの部分の計算を実行したが、Overlayカメラを使用すると、カメラのtargetTextureを元の方法でRawImageにレンダリングできません。
この問題に当たった方はいますか？
>A：問題主の疑問点は、サブカメラのCullScriptableはそれほどコストがかからないはずです（結局のところ、1つのオブジェクトしか持っていません）。
ここには2つの問題があります。
1.Cullingは一体何をしましたか？オブジェクトは1つしか持たないのに、なぜCullingはこれほど時間がかかるのですか（まさか一つのオブジェクトだとしても、たくさんの準備が必要ですか）？
2.Profilerに表示されるデータは本当に実際のデータですか？言い換えれば、サブカメラのCullingは実際に1.68msを実行しましたか？
これらの2つの問題とは別に、より良いアプローチがあります。
メインカメラとUIカメラの合計2台のカメラがありますが、UIに表示される3Dオブジェクトはどうですか？
仮想カメラがあります。いわゆるカメラとは、実際には、VPマトリックスを作成し、RTを作成し、可視オブジェクトを描画するとできたものです。では、UnityのSRPを使用し、任意の場所にVPマトリックスを設定し、RTを設定してから、指定したオブジェクトを描画します（UIのすべての3Dオブジェクトはこのオブジェクトの下にハングします）。その後、このRTを自由に使用できます。
UIに2つの3Dオブジェクトがある場合は、それらを1つのRTに配置してみてください。そうでない場合は、2つ以上のRTに配置してください。さらにいくつかの描画コマンド、いくつかのRT（フルスクリーンである必要はありません）、およびいくつかのSwap RT操作が追加されます。私たちのプロジェクトは複数のRTを必要としないため、複数のRTが必要なこの場合、1つのRTと複数のViewporを使用して解決できると仮定します。このコードは既存したもので、Cascade Shadow Mapのメソッドを参照すると、Swap RTは必要なくなります。
要約すると、何を描きたいかがわかっているので、UnityCullingにチャンスを与えないでください。

*Q2：データは、Development Buildの実機で見たパフォーマンスデータです。現在、HLODのような方法でこのLODの大きなコストを減らしたいです。Q１に「VPマトリックスの設定とRTの設定」とおっしゃったが、このVPマトリックスは具体的にはどのように操作しますか？もっと詳しく説明いただけませんか。*

>A：すべてが可能です！しかし、これは重要ではありません。問題主が言及したHLODとLODは、上記のCullingとは何の関係もありません。VPマトリックスは、viewマトリックスとprojectionマトリックスです。カメラの機能は、これら2つのマトリックスを提供することです。
パイプラインに対応するマトリックスを設定してから、指定したオブジェクトを描画する場合、カメラを追加する必要はまったくありません。結局のところ、カメラが1つ増えると、Cullingが1つ増えることになります。
VPマトリックスに詳しくない場合は、それを実装する方法がわからなくても、簡単です。追加のカメラを使用し、このカメラのCullingをオフにしてから、レンダリングpassでcullingresult.visibleobjectを描画せず、Graphics.DrawMeshまたはCommandBuffer.DrawMeshを直接使用して表示したい3Dオブジェクトを描画します。
________________________________________

##Addressable

**Q：元のAssetBunldeがパッケージ化する時、BuildAssetBundleOptions.DisableWriteTypeTreeを設定して、パッケージ本体をはるかに小さくすることができます。今、はAddressablesを使用して、プロジェクトアップグレードしようとしています。BuildAssetBundleOptions.DisableWriteTypeTreeを設定するにはどうすればよいですか？**

>A1：まず、Addressableがパッケージ化したBundleのメインスクリプトはBuildScriptPackedModeです。DoBuild関数では、AddressableAssetsBundleBuildParametersクラスが使用されていることがわかります。このクラスはBuildParametersから継承され、BuildParametersにはpublic ContentBuildFlagsContentBuildFlags{get; set;}というメンバー変数があります。このContentBuildFlagsはDisableWriteTypeTreeを設定するために使用され、BuildParametersはScriptableBuildPiplineに属します。
SBPを参照したCompatibilityBuildPiplineは次の操作を行います。

```
if ((options & BuildAssetBundleOptions.DisableWriteTypeTree) != 0)
   parameters.ContentBuildFlags |= ContentBuildFlags.DisableWriteTypeTree;
IBundleBuildResults results; 
ReturnCode exitCode = ContentPipeline.BuildAssetBundles(parameters, content, out results);

```

BuildScriptPackedMode.csに追加することもできます。

```
var buildParams = new AddressableAssetsBundleBuildParameters(
                    aaContext.Settings,
                    aaContext.bundleToAssetGroup,
                    buildTarget, 
                    buildTargetGroup,
                    aaContext.Settings.buildSettings.bundleBuildPath); 
                buildParams.ContentBuildFlags = UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree;
```



>しかし、ここでテストしましたが、機能しませんでした。最下位レベルでサポートがないのか、テストケースに問題があるのか​​わかりません。同じ方法でテストすることをお勧めします。
さらに、コードを調べたところ、SBPがパッケージ化と圧縮の部分でこのパラメーターを使用していないことがわかりました。シーンの依存関係を処理する場合、このパラメーターはBuildSettings構造に結合され、C ++部分に提供されコールします。したがって、このパラメーターを有効にするには、最終的にC ++レイヤーに渡す必要があります。
 

 
>A2：Addressableはこの設定項目を直接変更する外部インターフェースを提供していないようです。自分でコードを書いてパッケージ化方法を変更する必要があります。BuildModeを作成する必要があります。この投稿の5番目の質問に対する回答を参照できます：[https：//answer.uwa4d.com/question/5e649911438f7d0db495c724#5e64a4e8438f7d0db495c725](https：//answer.uwa4d.com/question/5e649911438f7d0db495c724#5e64a4e84)
コアコードは、DoBuildでbuildParamsの設定を変更することです。buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree；
以下に示すように、
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/bf79274b-674a-b194-5cc3-86a81fe393df.png)


テストを行ったところ、効果的であることがわかりました。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/c8c2ddbc-b873-5270-e548-f290b68aad95.png)


上記はデフォルトのパッケージです。変更後、再びパッケージすると、次の結果になります。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/e6076b32-0371-26fd-5ca5-368b5971db74.png)


全体が小さくなります。さらにAssetBundleを解凍すると、内部のコンテンツが非常に簡潔になります。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/72c3ac4f-dcd6-282c-0d8a-6cc3616867f1.png)

________________________________________
##Unreal

**Q：Unrealに関して、商用ゲームに使用できるホットアップデートソリューションはありますか？**
>A1：当社は自社開発のフレームワークなので、オープンソースのUnrealホットアップデートソリューションがあるかどうかは注意していないですが、印象的にはないようです。
でも、Unityエンジンに基づくオープンソースソリューションが多くあります。Unityのオープンソースソリューションに基づいて実装できます。基本的なアイデアは、リフレクションを使用してエンジンのエクスポートLuaインターフェイスを事前に生成することです。
どのようにリフレクションを利用しますか。簡単に言えば、リフレクションによってエンジンインターフェースの関数名、戻り値タイプ、パラメーター名、パラメータータイプを取得し、ルールで解析パラメーターのタイプとその個数や順序を生成して、結果が正しいLuaエクスポート関数int xxx(lua_State *L)関数に戻ります。クラスメンバー関数をTableにエクスポートする必要があります。C++クラス階層に従って、Metatableを使用して、親クラスのLuaエクスポートメンバー関数を見つけることができます。
これはUnityオープンソースソリューションですが、Unrealも同様です。違いは、UnrealはUClass UPropertyを使用するのに対し、UnityはC＃を使用することです。その方法でやってみてください。
 

 

>A2：次のリンクを参照してください。
https://github.com/Tencent/puerts


 
>A3：Tencentには2つのLuaホットアップデートフレームワークがあります。
1.[sLuaUnreal](https://github.com/Tencent/sluaunreal
モバイルゲーム「PeaceElite」で採用されているフレームワークと言われています。
2.[UnLua](https://github.com/Tencent/UnLua
sLuaの後に導入されたフレームワーク。
________________________________________
##Script

**Q：UGUI SpriteAtlasを使用すると、次の図に示すように、AtlasRequestedとStartの順序が逆になります。**
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/b9e31fe3-6743-e8e8-5eef-c14cc171fb97.png)


テストプロジェクトは、
[https://answer.uwa4d.com/question/5f743b739424416784ef24d6（中国語注意）](https://answer.uwa4d.com/question/5f743b739424416784ef24d6)
を参照ください。テスト環境はUnity2019.4です
>A：Timelineで特定の実行タイミングを確認できます。Main.Updateでインスタンス化すると（テスト時にMain.Updateのintervalを削除しました）、Atlasのコールバックが2番目のフレームに実行され、TestAtlasSpriteの Awake、OnEnable、およびStartが１番目のフレームに実行されました。Main.Startでインスタンス化する場合、これらのプリントは最初のフレームにあります。これは、AtlasのコールバックがEarlyUpdate.SpriteAtlasManagerUpdateにあり、
インスタンス化された
TestSpriteAtlas.StartがFixedUpdate.ScriptRunDelayedFixedFrameRateの下にあるため、Atlasコールバックの背後に戻ったからです。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/5613e6ef-7bd7-6b61-6b5b-9b92b24dc495.png)


この画像はUpdateで実行される状況です。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/ab741703-82c1-bcee-e5b8-a05e42db48c6.png)


これはStartで実行される状況です。すべて最初のフレームにプリントされていることがわかります。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/8db0e45b-50c6-f6bb-0366-3db76a452e35.png)

これはMain.Startでインスタンス化を実行しているTimelineです。TestSpriteAtlas.StartはAtlasのコールバックの後に実行されることがわかります。


これはMain.Startでインスタンス化を実行しているTimelineです。
EarlyUpdate，FixedUpdateのようなコールバックの実行順はを参考できます。[https://medium.com/@thebeardphantom/unity-2018-and-playerloop-5c46a12a677](https://medium.com/@thebeardphantom/unity-2018-and-playerloop-5c46a12a677)
________________________________________
##Rendering

*Q：パイプラインを動的に切り替えてエラーが発生する問題に当たったことがありますか。
既存のUBPプロジェクトは、新しいシーンに入った後、指定されたレンダリングパイプラインに切り替える必要があります。シーンをパッケージ化する時、レンダリングパイプラインと一緒にシーンにパッケージ化され、次のコードによってレンダリングパイプラインを切り替えます。*

```
GraphicsSettings.renderPipelineAsset = targetAsset;
   QualitySettings.renderPipeline = targetAsset;
Copy
 ```
しかし、AssetBundleを介して読み込まれるレンダリングプロセス：後処理では、UberPostに2つのキーワードが欠けています。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/32cdc4dc-9757-ac94-7e92-e35125f0a853.png)

次のような画像になりました。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/58797fc7-444b-8578-06e4-5767152a2e7c.png)

 
**Project Setting -》 Qualitでプロジェクトに手動で設定されたhero_showパイプラインが正常に表示されます。**
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/1610da69-7754-7efd-f424-684c5921864c.png)
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/0c5af386-594c-a766-6730-fd4e855b4448.png)




**ブレークポイントのデバッグにより、Renderプロセスで、Keywordsが実際に割り振られていることがわかります。両方のプロセスは同じです。**
PostProcessPass.csファイルには：

```
void Render(CommandBuffer cmd, ref RenderingData renderingData)
```

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/3522da89-4c94-1ba0-208f-feab292a0c46.png)

**ただし、Frame ProfilerのフレームにはKeywordsがないことが示されています。簡単なプロジェクトテストを添付します。
デフォルトはWindowsプラットフォームです。 defaultSceneを直接実行します。
そうでない場合は、以下の手順に従ってください。
1.AssetBundle-> build
2.defaultSceneを実行します。
リンク：[https：//pan.baidu.com/s/1q3s6mAUwE723wTJ3VmS81g](https：//pan.baidu.com/s/1q3s6mAUwE723wTJ3VmS81g)
パスワード：8kwn**

>A1：その問題に当たったことがないが、その原因は推測できます。
まず問題をまとめてみてください。
Project Setting -》 Qualityでレンダリングパイプラインを手動で設定します。表示は正常です。
AssetBundleの形式でレンダリングパイプラインをロードすると、キーワードが失われたために表示が異常になります。
そうすれば、答えは非常に簡単になります。
これらの2つのモードでは、Unityがレンダリングパイプラインのアセットを異なる方法で処理するからです。
一番目の方法では、Unityはレンダリングパイプラインをデフォルトのアセットと見なし、すべてをパッケージ本体にパックして使用します。
二番目の方法では、Unityはレンダリングパイプライン、特にレンダリングパイプラインに関連したShaderによって、そのKeywordが使用されているかどうかを判断します。使用されていない場合は、最適化します。
プロジェクトはまだ見ていません。問題主がコードでオンにしたこの2つのKeywordからだと思います。このようにコードがKeywordをオンにした方法は、Unityが検出できないため、失われます。
解決策も簡単です。Keywordに対する常用なソリューションは、一般的に使えるソリューションは、役に立たない材質球を作成し、対応するShaderを使用し、材質球でKeywordの使用をオンにしてからAssetBundleにパッケージ化します。これにより、UnityはこのShaderのこれらのKeywordは役に立つものだと知るようになり、Skipしないにします。（実際、この方法は、instance_onというKeywordの損失のを防ぐためによく使用されます）。
 
 
>A2：A１の方法を試したいのですが、このシェーダーはPackageディレクトリに配置されているため、材質球がUberPostをShaderに直接参照できないことが発見した。そのため、https://answer.uwa4d.com/question/5f3d10b19424416784ef1c82（中国語注意）
にある方法でパッケージ化してみます。には、エディターのSVC収集方法で、SVCを収集しました。SVCのUberPostには、その2つのKeywordがあります。UberPostとこのSVCを一緒にパッケージ化します。解凍した後、ubqSceneシーンがこのSVCのShaderを参照していることがわかります。シーンを切り替えた後、AwakeにSVCをロードし、Warmupしますが、問題はまだ解決されていません。最後に、問題主の元のプロジェクトをexeパッケージ化したところ、Keywordの損失の問題はなく、レンダリングはすべて正常になります。さらに、APKテストにパッケージ化されており、Xiaomi9でのテストも正常にレンダリングされます。
おそらくUnityエディターの問題です。以下を参照してください。
https://answer.uwa4d.com/question/5ee0883e50fb7c2938d1f265#5ef5b06d1bd523380210b86d
 
---
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