シーンテクスチャのレベル割り戦略


今回の主な話題：シーンテクスチャ圧縮のテクニック、XLuaがゲーム内の配置テーブルを読み取る方式、AssetBundleがベイクシーンをロードする時のライト失効の解決策、OverDrawの最適化問題、複数のBMFontに対応するアートフォントを１つのDrawCallに最適化する方法。

---
###Texture
Q1:

1、シーンテクスチャを圧縮すると、ハイ、ミドル、ローエンドのモデルで区別できますか？

2、できない場合、どの配置に関係なく、モデルが同じメモリシーンテクスチャをロードすることを意味します。問題は、圧縮がより厳しく、効果がハイエンド設備ではあまり良くないですが、圧縮がそれほど厳しくなく、メモリがローエンド設備で非常に緊張であるということです。この場合、良い解決策はありますか？

3、次に次に不可解な質問があります。一般的に、一枚の2048×2048テクスチャがMipmapをオンにする場合、RGB24形式のメモリは16MB（12MB＋約3MBのMipmap）であるはずです。ただし、スマホにパッケージすると、実機Profileの時に見たこの画像で、占用したメモリは4MBであります。Mipmapをオフすると正常になり、16で表示します。実機Profile時に取るのは本物のメモリ占用ではなく、ビデオメモリでありますが？それとも、これはUnity ProfileのBugですか？

補足：UWAでテストしたところ、同じ状況が見つかりました。Mipmapをオンにすると、2048×2048も4MBになります。
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/3e136206-fdfe-0c36-8196-36e184e5b0bd.png)

①
>区別できます。代償はパッケージサイズが大きくなり、ハイ設置やロー設置に従って、追加に異なるアセットのコードロジックをロードする必要があります。もちろん、現在のハードウェアに応じてどのリソースが適切かを判断するために小さなパッケージを使用し、そしてダウンロードすることは一般的な方法であります。（ただし、国内では完全なパッケージのやり方を使う方が多いです。）
>
2、異なる機械で異なるリソースをダウンロードする方法、または複数のテクスチャがパッケージに含まれている方法以外に、他の良い方式はないでしょうか？UnityのQualitySettings配置にあるTextureQualityは１つの行ける可能性のあるオプションです。メモリの比較は行っていませんが、以前の理解によると、Mipmapに基づいてビデオメモリを節約すると言うことはずです。これは問題主自分でテストできますが、これは問題主が欲しい異なる圧縮形式ではありません。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/f775f918-f736-0101-11d6-a98fa077b33d.png)
3、2048×2048のメモリ占用は何ですかも分かりませんので、他のフレンドの回答を見てください。しかし、問題主がすべてRGB24の形式を使用しますから、メモリが爆発しない方がおかしいでしょう。対応する目標設備が直接サポートしている圧縮形式を使用することをお勧めします。質の高い圧縮、特に3Dシーンで、Normalなどの特殊テクスチャを除いて、明らかな違いはありません。 

②
>
現在、多くのゲームがスマホモデルに応じて適応されます。ほとんどのゲームがAndroid Top 300に適応するようになった標準ETC2は、標準の圧縮形​​式として使用できます。iOSではiPhone 5sを考慮する際にPVRTC4が必要です。スマホモデルを検討しない場合は、 ASTCを使用できます。
>
標準パッケージでは、上記の形式でのみ圧縮を実行しますが、ハイエンドモデルでは、ユーザーが高解像度のリソースをダウンロードすることを選択できるようにすることができます。この部分の高解像度リソースは、画像の圧縮形式をASTCに変更し、AssetBundleを再びパッケージします。ユーザーが自分でダウンロードし、特定のゲーム内アイテムに報酬を与えることができます。
>
上記の戦略は、MMOなどの大形ゲームに適しています。カジュアルゲームの場合は、いくつかのリソースを2つの異なる圧縮形式で保存し、モデルに応じて異なるリソースをロードすることを選択できます。

③
>
Unityバージョンは2018.3です。Texture Mipmap Steaming機能が有効になっている可能性があります。メモリBudgetが設定上の上限に達したため、エンジンはMipmap 1~nの内容だけをロードしました。元画像のメモリが12MBであるという問題に対して、第一層後のMipmapの統計は4MBくらいです。ですから、あなたの3番目の質問はこのようなものだと個人的に推測しています。

---
###Lua
Q2: 私たちがプロジェクトにLuaを使いました。主にUIロジックの記述とホットアップデートに使用したいです。UIロジックを作成するときは、Luaスクリプトにあるゲーム配置テーブルデータを読み取る必要があります。ネットでいくつの解決策を見つかりました。

1、C#レイヤーはLuaにテーブルチェックインターフェイスを提供します。このやり方のパフォーマンスは良くないと感じます。
2、ゲームExcel配置テーブルをLua Tableに転換し、Lua側で直接使用したいですが、オープンソースツールはまだ選択されていません。
3、他の方法。

①
>案2に対して、[TabtoyExcelエクスポーター]ツールをシェアします。Excel配置テーブルをLuaファイルに変換し、Luaで直接使用できます。
>
コード例：
>
```ruby:コード例
-- 検索パスを追加する
package.path = package.path .. ";../?.lua"
-- ロードする
local t = require "Config"
-- 生データへの直接アクセス
print(t.Sample[1].Name)
-- インデックスを介してアクセスする
print(t.SampleByID[103].ID)
print(t.SampleByName["Black Cat Detecti"].ID)
```

②
>
GitHubでExcelをLuaにエクスポートするためのツールはたくさんありますが、本質は同じです。それらはすべて、既存のテーブルにいくつかのルールの変更と制約を加える必要があります。プロジェクトの形式に近いものを具体的に確認して、自分で適応する必要があります。
>
最初に私は2014年の初めにプロジェクトのエクスポーターを作成しましたが、継続的に改造されており、現在は[ツールXlsxToLua](https://github.com/zhangqi-ulua/XlsxToLua)になっています。

---
###Lightmap
Q3：AssetBundleを介してロードされたシーンでは、ライティング効果が見つかりませんでした。

問1、static属性が変更されていることがわかりました。これがバッチ処理に影響を与えますか？
問2、Shadowmaskが引用されていませんでした。これはLightmapLightを処理すると同じように処理したいですが、行けますか？
問3、最も重要なことは、AssetBundleを介してロードされたシーンがどのようにライト情報を込められますか？

シーン全体がAssetBundleとしてパッケージする場合に問題はありませんが、共通リソースを利用すると、ライトは失効になることはテストからわかりました。

図1はUnity内のシーン情報であり、図2はAssetBundleを介してシミュレーションしてロードされたシーン情報です。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/12923d4e-edf2-9102-9faf-9bd2c09ac6b3.png)

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/182d9dda-3874-6862-0a72-4a303e0e11c4.png)

>まとめします。
1、Shader Variantsの遺失。
2、AssetBundleパッケージするときにLightmapを最適化しました。
3、StaticはEditorでシーンに置いたオブジェクトに対してのみ有効であり、Runtime時にインスタンス化は有効ではなく、静的なバッチ処理は行いません。
>
解決案
1、Shader Variants Collectionを作成し、使用されたShaderの変種を正確に選択し、パッケージする時にShader Variants Collectionと使用されたShaderを１つのAssetBundleに込めさせます。これで、ShaderのAssetBundleはシーンを削除できるようにします。
2、Editor→Project Settings→Graphics→Shader Stripping
Lightmap ModesをCustomに変更し、Lightmapベイクモードに従って対応するモードを選択します。主な原因は、AssetBundle時に開いたシーンに基づいてAutoがこれらのオプションを設置しますから。空きシーンの場合、Lightmapはありませんので、ShaderにあるLightmapの部分を最適化します。
3、Meshを手動でマージしてDrawCallを減らすことができます。詳細については、CombineInstance関連のAPIを参照してください。

---
###Overdraw
Q4: 最近、OverDrawの最適化を行っています。私たちのUIインターフェイスはウィンドウ表示されており、全画面をカバーしていないため、メインカメラは常にレンダリングしています。DrawCallとOverDrawを減らすために、メインカメラにスクリーンショットを撮り、弾き出すUIウィンドウの後ろに配置し、メインカメラを閉じて、UIインターフェイスを開くときのDrawCallを大幅に減らしました。これは方案Aであります。
ただし、背景にスクリーンショットは１つの全体であり、UIにカバーされる部分があるため、中のUIにカバーされた部分を掘り下げたいで、見える部分のみを残します。これでOverDrawを低下できます。これは方案Bです。
では問題が発生します。方案Aは方案Bよりも3つのDrawCalls低くなっていますが、OverDrawは0.4x多くなります。私たちのプロジェクトのCPUもGPUもボトルネックは発生していません。バッテリ消費量と温度のみを考えると、どちらの方案がより良いですか？

>まず第一に、私はAとBの両方が良い解決策であると言う必要があります！さらに、方案Bまで考慮することもできます。これは、問題主チームの自己要件と実行能力が非常に高いと言う意味です。
>
次に、方案Aでも方案Bでも、CPUとGPUはボトルネックに達していないから、実際にAもBも採用でき、どちらの方法の人工消費が低いと判別すれば大丈夫です。しかし、計算力から考えると、個人的には方案Bをお勧めします。3つDrawCallの増加はほとんど無視できますが、0.4xのOverDrawは無視できないコストです。

---
###UI
Q5: ゲーム内複数の戦闘フォント効果があり、複数のBMFontアートフォントに対応します。それらを1つのDrawCallに最適化する方法は？例えば、会心一撃、中毒、回避、ヒーリングなど、各種類のダメージと原因が異なるフォント効果を対応します。前の方案はBMFontを使って複数のフォントを作成し、UGUIの生成にあるカスタムフォントに対応します。これがもたらす問題は、さまざまな文字が同時に散在しているように見えると、UIのバッチ処理が中断され、多くのDrawCallが生成されることです。
１つの最適化案は、異なるアートフォントを異なるレイヤーに配置し、何種類のフォントがあれば何個のDrawCallを生成することです。ただし、この方法の明らかな問題は、ある種類のダメージが別の種類によって完全に隠されることです。望ましい効果は、さまざまなタイプのフォント効果を互いに散在させて存在することができることです。
現在考慮している解決策は、すべてのアートフォントをBMFontフォントファイルにすることです。異なる種類のダメージナンバーに対して、グループ化されたASCIIコードを使用して、同じnumberの異なる表現をアクセスします。
皆さんが使用している方案を聞きたいです。

>私なら、「すべてのアートフォントを1つのBMFontフォントファイルにする」を選択します。異なるナンバーに対しては、他の文字を転換して使用すれば良いです。しかし、異なるアートフォントサイズが均一であるなどの問題に注意してください。これはすべて簡単に解決できます。
>
さらに、問題主に「会心一撃」や「中毒」のような単語を一つの字として処理することをお勧めします。対応する文字は特定のものを選択できます。これの利点は、後でタイ語や英語バージュンを作る時にアートフォントは連れている可能性が高いです。１つの字が１つの整体であれば、対応する文字を統合できます。

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com