Unity Lightmap混乱問題の研究

今回の主な話題：Unity Lightmap混乱問題の研究、UGUI静的および動的キャンバス、AssetBundleパッケージングゼロ冗長性の方法、AssetBundle依存パッケージングエラー。

---
###Lightmap
Q1: Unityプロジェクトのライトマップ混乱を引き起こす可能性のある問題とその対処方法をシェアしましょう。

最近のプロジェクトがUnity2017バージョンにアップグレードされた後、チームに一部の人のマシンライトマップが間違いたが、一部の人は正しいです。最初にモデルアセットの問題を疑って、アセットとエクスポートの設定を確認し、問題はありましたが、混乱の原因ではありませんでした。後で、マシンライトマップの間違うマシンとマシンライトマップの正しいマシンで、同じモデルのUVは確かに全然に違います。

最後、やっと原因を確認できし、再現もできます。Unityは、モデルをインポートすると頂点最適化は行われ、頂点数はMaxと同じではありませんが、面の数とまったく同じです。重要なのは、異なるUnityバージョンで同じモデルが最適化した頂点数も不一致です（アルゴリズムの違いは問題はずです）。頂点数が違うなら自然にライトマップのUV分布も異なるということです。たとえば、Unity 2017.3でモデルをインポートしてライトマップを生成し、エクスポートしてPackageを生成し、Unity 2017.4または他のバージョンにインポートすると、再インポートされたモデルの頂点とライトマップのUVが異なるため、ライトマップのUVが混乱になります。ですから、同じ開発チームにいるアーティストさんは必ず開発さんと同じバージョンを使用してください。

一つもっと隠された状況もあります。これは、誰もが同じUnityバージョンを使用していますが、マシンが異なれば、一部の人のライトマップが混乱するという問題です。表現の正しいマシンは、下位バージョンのUnityを使用してライトマップをベイクするか、他のユーザーがベイクしたライトマップを更新してから、直接に上位バージョンのUnityで開くと問題はありません。同じプロジェクトにLibraryを削除した後、上位バージョンUnityで再び開きますと問題が起こします。もちろん、新しいバージョンでモデルの設定を変更すると、新しいバージョンに従ってモデルを再インポートすることにより、ライトマップが乱れる原因にもなります。

以上は全部の内容でした、簡単に再現できます。結論は、
1) チーム内全員が同じバージョンのUnityを使用して開発することをお勧めします。
2) アップグレードプロセス中に、ローカルLibraryを削除して、新しいバージョンのUnityで開く必要があります。

---
###UGUI
Q2: 前に了解しました。UGUIのキャンバス上の画像またはテキストが変更する時、キャンバスはDrawCallを減らすために、UVを再計算し、アトラスを再合併します。したがって、キャンバスの再描画によって引き起こされるパフォーマンスの問題を減らすために、頻繁に変更されるUIを動的キャンバスに配置し、頻繁に変更されないUIを静的キャンバスに配置しました。ここに少し疑問があります：UIウィンドウをプリセットに作成し、UIが動的も静的も両方ある場合に、このUIをどちらのキャンバスに配置するほうは良いでしょうか？
そして、同じキャンバスの下にない場合、、UI前の階層関係をどのように処理しますか？たとえば、Canvas Aは静的で、Canvas Bは動的です。CというUIがAに配置され、別のDというUIがBに配置されます。Canvas BはCanvas Aの前にありますが、UI CをUI Dの前に置いて欲しい場合、どうすれば良いでしょうか？
>問題主の一部の問題は不明瞭かもしれませんが、以下に簡単に説明します。「UVを再計算」操作は関数Canvas.SendWillRenderCanvasesに発生しました。変更されたUI要素（画像、テキスト、アルファなど）が多いほど、コストが高くなり、「動と静を分離」でこの部分のコストを最適化できないので、変化の頻度をコントロールすることで行われます。
「動と静を分離」はCanvas.BuildBatchのコストを最適化ために行います。コストが生成する原因は、あるCanvas内の要素（画像、テキスト、アルファ、位置、ズームなど）が変更されたとき、このCanvasはMeshと合併する必要があります。Canvasがより複雑な場合、時間がかかります。
「動と静を分離」を行う場合、理論的にはCanvasの複雑さによって計画する必要があります。個人的には、キャンバスの総頂点数は簡単な指標として使用できると思います。 以下に、より直感的な例をいくつか示します。
一般的なMMOプロジェクトに対して、通常はスキルパネルとタスクパネルを別々にCanvas分離します。その中、スキルパネルがCDを読んでいるときでも、一般的には頂点の数は1000を超えず、UI要素の数も多すぎません。このようなパネルBuildBatchのコストは明らかではないため、このパネルに動的要素も静的要素もありますが、「動と静を分離」を行う必要はありません。

>但し、タスクパネルでは、エントリ数が多いため、通常、生成される頂点数は非常に多く、2000を超えることもよくあります。したがって、このパネルに動的UI要素（ハイライト効果のあるシーケンスフレームアニメーションなど）があったら、時間のかかるBuildBatch操作を引き起こしやすいため、このパネルには「動と静を分離」必要があります。

>具体に操作する時、「動と静を分離」も妙な問題にあう可能性があります。断片化された動的UIをCanvasに分解すると、DrawCallが大幅に上昇しやすく、前後のオクルージョンを制御することも困難になります。ですから、Shaderを使用してUIアニメーションを作って、Canvas.SendWillとCanvas.BuildBatchのコストを直接回避することをお勧めします。

---
###アセット管理
Q3: AssetBundleを使用してUnity4.xバージョンで冗長性をゼロにしたいのですが、実現中に問題が発生し、それを解決する方法がわかりません。 例えば：

``BuildPipeline.PushAssetDependencies()
BuildPipeline.BuildAssetBundle Texture Aをパッケージする
BuildPipeline.PushAssetDependencies()
BuildPipeline.BuildAssetBundle Asset Aをパッケージする
BuildPipeline.PopAssetDependencies()``

このとき、一つのAsset Bをパッケージする必要があります。Asset BにTexture AとTexture Bは引用され、Texutre BはAsset Cに引用され、Asset CはTexutre Aが要りません。この時、ロジックをどのように調整すれば、「Asset AとAsset BがTexture Aに依存し、Asset BがTexture AとTexture Bに依存し、Asset CがTexture Bと他のアセットに依存する」目的を実現できますか？
>確かに、Unity4.xのAssetBundleパッケージにはそのような欠点がありますが、それに対して、段階化パッケージする方法はあります。

>つまり、下記のようにAsset AとAsset BをTexture Aに依存させます。
``Push
Build Texture A
Push
Build Asset AとAsset B
Pop
Pop``
そして、下記のようにAsset BとTexture Aを再パッケージ化し、TextureBを初めてパッケージ化します。
``Push
Build Texture AとTexture B
Push
Build Asset B
Pop
Pop``
その後のAsset Cに対しても同じです。この時、あなたは絶対に「こうすればTexture Aを二つパッケージしたの？」と言う疑問が抱いています。

>そうです。ここで注意すべき点があります。それは、Unity 4.xで、必ずDeterministic Optionを開くことです。そうすれば上記の方法は有効にさせられます。つまり、2回目にパッケージしたTexture AのAssetBundleが1回目のTexture A AssetBundleを直接にカバーします。Deterministicであるため、彼らのHashidは同じです。これて、Asset AのAssetBundleと新しいTexture AのAssetBundleに依存関係があることも保証でき、同時にAsset BがTexture AとTexture B間の依存関係も確認できます。

>上記の方法により、問題主が冗長性のないAssetBundleファイルをパッケージできます。：）頑張ってください。

---
###アセット管理
Q4: Unity 5.5.4p5バージョンがAssetBundleを採用してアセットをロードしたら（依存有り）、次のエラーが発生する可能性が高いですが、どのように対処しますか？

“The referenced script on this Behavior is missing!”, “The referenced script on this Behavior (Game Object ‘Prefab 1’) is missing!” and “GameObject (named ‘Prefab 1’) references runtime script in scene file. Fixing!”

>「The referenced script on this Behavior is missing!」、Unity 5.0以降のパッケージ化方法である場合、その原因はおそらく次のとおりです。スクリプトのシリアル化情報が変更されており、この問題を修正するためにはAssetBundleを再パッケージする必要があります。

>また、Unity 4.xの古いパッケージング方法の場合、上記の原因以外に、もう一つ可能性があります。それは、スクリプトが依存AssetBundleにあり、後続のAssetBundleがロードされたときに、依存AssetBundleが正常にロードされていないか、アンロードされている可能性があります。これも問題を起こします。

---
###UGUI
Q5: Unity 5.5.6バージョンで、Texture import SettingsにSpriteタイプを選択し、Sprite modeにMesh Typeを選択すると、UIアトラスとして使用したい場合にどのモードを選択するほうがいいですか？
>Full Rect。MeshTypeはSpriteRendererによって使用され、画像の形に応じて近似Meshを生成します。しかし、UGUIに対しては同じであり、すべてImageTypeに従ってMeshを描画しますが、Tightを使用する場合には追加のメモリが必要になる可能性があるため、FullRectを使用することをお勧めします。

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

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