DrawMeshInstanced が Unity2018 で有効にならない問題

今回の主な話題：Unity2018 でDrawMeshInstancedのアップグレードが有効にならない問題、UnityのShaderローディング解析が重複する問題、解像度をロックする方法を使用してパフォーマンスをテストする問題、動的アトラスの作成時にエラーが発生する問題、同じShaderが同じアトラスをマージできない問題。

---
###DrawCall
Q1: Shaderのパッケージ化に対する私たちのアプローチは、通常、プロジェクトのすべてのShaderを１つのAssetBundleにパッケージします。これにより、Shaderの冗長性を回避し、Shaderもホットアップデートできるようになります。Unity 5.5.4でこうすると問題ありません、すべてのShaderは上手くレンダリングでき、Instancingやホットアップデートに使えます。
ただし、Unity 2018.3 では、シェーダーとそれが使用するShaderが同じ AssetBundle にない場合、正常にレンダリング できますが、このShaderを使ってGPUInstancingを行うと有効になれません。Unity 2018.4 を試しましたが、同じでした。
テストプロジェクトは[質問ページ](https://answer.uwa4d.com/question/5d077b23739f3b667bc57b95)で取れ、Unityを使ってPCプラットフォームで再現できます。これはUnityのBugであるかどうかを確認できますか?それとも、Shaderのパッケージ化と使用方法に何か問題がありますか?

>Unity が Shader Stripping 機能を追加した後、多くのKeywords損失の問題が発生します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/291d70fa-81a0-05aa-7a60-b644abfffeab.png)
GPU Instancingを成功に行ったShaderにはKeywords：INSTANCING_ONがあることがわかりますが、Shaderの分離パッケージ化に実行するShaderをロードしますと、Keywordsが失います。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/cc9312dc-8851-55dd-cb8f-7b545ef6fe4b.png)
ですから、解決策の１つは、Project SettingにStripping機能をキャンセルし、Keep Allを選択することです。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/4b3bfcd1-3847-0a82-8b71-9d8fe0cc5314.png)
2 番目の解決策は、GPU Instancing機能が使用されているシーンにパッケージ化することです。これで、Keywordsはstripされません。当然、解決策２は少し実用的ではありません。まだMaterialを保持し、一緒にパッケージすることをお勧めします。

---
###アトラス
Q2: 私たちのプロジェクトのShaderのローディングと解析は ShaderVariantCollectionを使用していますが、ロードする時にそのような問題が見つかりました。

Shader的Bundleをロードすると、Shaderを執行するParse方法が見つけられ、すべてのShaderを解析しました。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/b00d461d-ab2c-951b-5806-6ecdb352006b.png)
そして、WarmUpを執行する際、もう一回解析しました。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/9fbf4a2e-7981-f293-723c-48499a3efb93.png)
Unity5.X 以降のShaderのローディングと解析が分離されていると聞きましたが、混乱です。誰かが教えていただきませんか？（Unityバージョン：2018.2.19f1）
>個人的な理解は以下とおります。

1、ShaderとShadervariantが同じBundleにパッケージし、ShadervariantにShaderを編集することに対して、Shadervariantには依存性があります。ゲームが起動する時、ShaderのあるBundleをロードし、中からShadervariantをロードします。依頼しているShaderのParseが自動的にトリガーされ、対応する変体は１つの変体Shaderを生成してGPUに提出しますが、この時の変体数は完全ではありません。
2、Shadervariant.warmupを執行する時、残った変体の生成をトリガーし、GPUに提出します。
3、2ステップの操作を行います。１つ目はShader.Parseであり、部分の変体Shaderも生成します。２つ目に、Warmupが残った変体を生成します。
>
以下は私の個人的なテストのスクリーンショットです。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/daa4d43b-01c4-d2e9-6e96-2fb799848f90.png)
4、コール回数を比較します。分かりやすいのは、１回目のShader.Parseはすべての変体の生成を全部執行きっていませんでした。ShaderのあるBundleを直接にロードし、AllAssetをロードすることもテストしましたが、すべてのShader解析をトリガーし、Shadervariantと関係していますかどうかが問いません。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/e582af0d-b7ce-d504-c8e3-f37055250010.png)
すべてのShaderがコンパイルされている場合でも、Warmupはまだ変体Shaderの生成を執行することが分かりやすいです。ですから、最初のステップでロードする時に、すべての変体Shaderの生成過程を執行きりではないようです。

---
###パフォーマンステスト
Q3: 現在、プロジェクトがパフォーマンス テストを行う時に、SoC（System on a Chip）によって分割し、同時に固定的な解像度（例えば1024*768）にロックします。この方法で取ったデータは正しいかどうかを知りたいです。
たとえば、2 つのスマホの配置は同じで、１つは4K 画面であり、も１つは1080P画面です。1024*768解像度にロックすると、パフォーマンス上は同じですか？
>このような画面の拡大縮小方法はたくさんのプロジェクトによく見えます。レンダリング 内容が同じ場合に、4K画面も1K画面もGPUの計算圧力は同じです。唯一の違いは最終的な拡張RTサイズが違いますが、この部分のコストは低いです。ただし、設備のGPU能力の違う（一般的に、4K画面の持つ設備は、GPUパフォーマンス も強い）次第で、最終的にGPUでの時間コストが異なります。
>
Overdrawに対しては、同じように画面解像度の違いによっても異なります。UWA のパフォーマンス レポートでは、本物のOverDrawはただ画面の１ピースということが見られます。

---
###Unreal
Q4: 動的アトラスの作成中にエラーが発生しました。Unsupported texture format – needs to be ARGB32, RGBA32, RGB24, Alpha8 or one of float formats.

本来なら、動的アトラスを利用してDrawCallとメモリを最適化したいですが、上記の形式のTexture2Dしか作成できないようです。他の形式を使用すればtexture.SetPixels時に上記のエラーが出てしまいます。しかし、上記の形式のメモリ占用は高すぎですが、何か他の形式のテクスチャを生成する方法ありませんか？

コード、

```ruby:code
Texture2D texture = new Texture2D(textureSize, textureSize, TextureFormat.DXT5, false);
Color[] fillColor = texture.GetPixels();
for (int i = 0; i < fillColor.Length; ++i)
fillColor[i] = Color.clear;
texture.SetPixels(fillColor);
```
>まず、問題を区別する必要があります。これはオフラインで生成するものですか、それともRuntimeで生成しますか？オフラインの場合、生成する方法が多すぎるのため、ここで問題主はRuntime生成と仮定します。SetPixelsに対して、Unityドキュメントには「This function works only on RGBA32, ARGB32, RGB24 and Alpha8 texture formats. For other formats SetPixels is ignored. The texture also has to have Is Readable flag set in the import settings.」と明確に書いてあります。そして、問題主New Texture2Dが使うのはDXT5形式です、これは一般的にPCでのみ使用されます。
>
1 つの方法は、RGBA32 を使用して生成し、圧縮後にインポートすることです。しかし、私の知る限り、Unity ネイティブは実行時に画面圧縮することをサポートしていません。したがって、個人的には、もう１つの方法を使うことをお勧めします。つまり、RenderTextureを使用してピクセルをコピーすることです。CPUのSetPixelsに比べて、この方式はより早いです。フォーマットに関する、RenderTextureにはたくさんのフォーマットが選択できます。例えば、RGB565やARGB4444など、メモリ上はRGB32より小さいです。

---
###Mesh
Q5: マップノードのDrawCall を処理する時に、アトラスもShaderも同じ２つのアトラスがマージできません。「Objects have different materials.」と表示します。
次に、メモリによって確認すると、この引用がたくさんあることが分かりました。それぞれの中には具体的に引用するアセットです。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/05c42a27-1821-2c04-a603-cc6a74a3a774.png)

①
>
この原因は現在見つかりました。その原因は、組み込みのシェーダーがさまざまなプレハブで使用されているため、１つずつにシェーダー情報があります。異なるMaterialsを導きます。これを解決するために、これらのプレハブを同じアセットに引用する必要があります。
>
しかし問題があります。アセットが組み込みのShaderとTextureを引用するため、組み込んだ内容をファイルにインポートしてから引用をリセットする必要ありますか？そしてインポートした内容をAssetBundleパッケージにしますか？では、AssetBundleにパッケージ化するはずなのに、なぜEditor目次に置きますか？最後に、引用も設置きりましたが、なぜ復元する必要がありますか？

②
>
復元する方法は、最初バージョンが採用した方法です、もう廃棄しました。現在は、直接プロジェクトに置くことをお勧めします。これにより、新たに創建したオブジェクトは抽出されたShaderとマテリアルを直接使用します。抽出されたアセットの名前と組み込みアセットを同じように保持すれば、新しく作成されたアセットがAssetsのほうを優先に使用します。

---
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