異なるMeshのDrawCall最適化戦略


今回の主な話題：異なるMeshのDrawCall最適化戦略、AnimationClipメモリの最適化、レンダリング効果エラー、Unityコンパイル後のエラーをコールバックする可能性、UGUIアトラスの並べる問題。

---
###DrawCall
Q1: Voxelゲームを作成しています。現在、ゲーム内では、すべてのモデルが同じMaterialを共有し、各モデルパーツ（モンスター）は個別のMeshであり、Animatorで作成したアニメーションにはボーンがなく、キーフレームアニメーションであり、GPUインスタンスが有効になっています。

発生した問題：
例えば、一人のキャラクターには10以上のパーツがあり、マップに10種類のモンスターが同時に表示されると、モデルパーツのDrawCallは100以上に急上昇します。現在、特殊効果はあまり追加されていないため、実機（Mi8 Lite）でテストしてもスタッター効果はなく、GPUインスタンスも開いております。種類が少ない、数量が多い場合でも動作が悪くないです。
しかし、私はまだ皆にお聞きたいです。この高いDrawCall問題のための良い最適化方法はありますか？それとも最適化する必要がありますか？ 感謝します！
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/f16a2bf2-225c-5759-2771-bd63b63d8074.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/14317b85-df3d-beeb-2b5d-82787bb96c8a.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/9ce0df41-70e0-ab3c-e1e4-f0710a307139.png)

>自分でCulling＋手動でDrawMeshInstancedをコールする（直接マテリアルでinstanceをチェックすると合併できない場合がよくあります）ことで、パーツ種類と同じ数のDrawCallに減らすことができます
>
アニメーションの精度要求が高くなく、スペースを時間に変えられる場合、モデルを作成してフレームアニメーションごとにベイクして、DrawMeshInstancedを使用したら、モデル種類と同じ数のDrawCallに減らすことができます。
>
LWRP / HDRPを使用すると、１つ便利な点があります。SRP batcherを開き、マテリアルのenable instanceをチェックしない（「しない」と注意してください）、自有Shaderを使用する場合、DrawCallの急低下がすぐ見られます。カスタムShaderの場合、書き直すことも難しくないです。

---
###Animation
Q2: 何かアニメーションメモリ占用を最適化する良い方法ありませんか？よく見える精度の低下、圧縮、Scaleの削除などの一般的な操作以外に、frame Rateを下げることで行けますか？


①
>
frame Rateに関して、以下のことを補充できます。
>
問題主の問題が「アニメーションがUnityにインポートした後、再生する時にframe Rateを変更します（アニメーションの再生speedを制御することにより、Unityにインポートした後に実にはアニメーションクリップの元来frame Rateを変更できません）」の場合、frame Rateの変更はメモリに影響しません。
>
しかし、もし問題主がアニメーション制作ソフトウェア（3ds Max、Mayaなど）でframe Rateを変更することを指す場合、Unityにインポートした後にメモリが実際に影響を受けます。このとき、2つのアニメーションが同じである場合、単純にフレームレートが異なります。
>
1、アニメーションの圧縮がオフにする場合、実際にキーフレームが多い段落（一般的にはframe Rateの高い部分）のメモリは少し大きくなります。そして他にいくつの影響要因もあります。
>
a、インポート時にresample curvesをオンにします（このオプションは、インポート時にUnityがフレームを自動的に挿入するかどうかを決定し、再生期間中にすべてのカーブがフルフレームになるようにします。）、frame Rateの高いメモリは高くなります。
b、resampleを開くない場合、frame Rateの高い部分は少し高くなります。
>
2、Keyframe Reductionなどのアニメーション圧縮を開くと、異なるframe Rateのメモリは再び近くなります（アニメーションが同じであり、実際のアニメーションカーブも類似であるため、圧縮する時に一部の繰り返しデータも同じように圧縮されます）。
結論は、つまり、アニメーション圧縮オプションがオンになっている場合、アニメーションを作成する時のframe Rateがメモリへの影響も大きくないので、特にframe Rateに最適化する必要がありません。

②
>
一般的に使用されるiTween、DOTweenプラグインやUWAが推奨するXTweenなど、いくつかの線形アニメーションをシミュレートして、アニメーションキーフレーム設置のデータ量を減らすことができます。

---
###レンダリング
Q3: iPhoneでMetalAPIを使用し、MSAAもオンにします。不透明オブジェクトをレンダリングした後、透明オブジェクトをレンダリングする前のこの階段（例えばAfterForwardOpaque）に、任意１つのCommandBufferを挿入すると、透明隊列の最も前にあるオブジェクトをレンダリングさせ、ZTestはないようです。
注：OpenGL ES3.0の使用に問題はなく、Androidプラットフォームでも問題はありません。

再現用Demoを作成し、iPhoneに構築して実行すれば大丈夫です。MSAAとCommandBufferを同時に開くと、2つの赤いCubeが常に木の前にあることが分かりました。そのうちの1つを閉じたら問題ありません。

 

再現用Demoを添付します。
[MASSDemo.zip](http://t.cn/ESAsElt)

>透明オブジェクトをレンダリングした後、不透明オブジェクトをレンダリングする前に１つのCommandBufferを挿入し、このCubeにUnityのディープテクスチャを現在FrameBufferのDeepthBufferに書き込んだら解決できます。

---
###Script
Q4: Unityで、コンパイルするスクリプトがエラーを報告する時にコールバックがあるかどうかを知りたいです。または、使用できるTrickはありますか？

①
>
効果を試しました。
>
```ruby:
public class CompilePostProcesser : AssetPostprocessor
{
static CompilePostProcesser() { EditorApplication.update += Update; }
// すべてのコンパイルが完了した後のコールバック[再帰が発生するように注意してください。つまり、コールバックの操作によって再度コンパイルが発生します]
// コンパイルエラーがある場合、このコールバックは実行されません
[UnityEditor.Callbacks.DidReloadScripts]
private static void OnCompiled()
{
// Debug.ClearDeveloperConsole();
Debug.LogError(“コンパイルが成功しました!”);
SuccsccAction?.Invoke();
}
private static void Update()
{
if (EditorUtility.scriptCompilationFailed)
{
EditorApplication.update -= Update;
Debug.LogError(“コンパイルに失敗しました!”);
FailAction?.Invoke();
}
}
}
```


②
>
Trickは1つありますが、少し古いです。アイデアは、LogをClearしようとすることです。しかし、コンパイルエラーはClearできないため、コンパイルエラーが発生したかどうかを判断できます。
>
```ruby:
static void ClearLog()
     {
         Assembly assembly = Assembly.GetAssembly(typeof(SceneView));
         Type logEntries = assembly.GetType("UnityEditorInternal.LogEntries");
         logEntries.GetMethod("Clear").Invoke (new object (), null);
>
         int count = (int)logEntries.GetMethod("GetCount").Invoke(new object (), null);
>
         if (count > 0)
             throw new Exception("Cannot build because you have compile errors!");
     }
```

---
###UI
Q5: Unity 5.6.6バージョンでUGUIを使用してアトラスをパッケージします。スペースは512×512に十分し、各画像のサイズは101×101ですが、17枚の101は512×1024のアトラスにパッケージされます。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/9e3b7372-2554-236f-30aa-5515c34738f8.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/9705c3e9-76be-b2cd-c29c-89ae1d115a53.png)
テストに使用した画像、
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/aa3c1ba5-33af-f035-a3c8-1df30e69f26a.png)


①
>
Paddingがあります。両側に1ピクセルのパディングがあるため、101は103になり、512は足りません。


②
>
Sprite atlasにはPaddingプロパティがあり、最小は2ピクセル、デフォルトは4ピクセルです。
>
2ピクセルを例にとると、上記のアトラス画像の高さは512で、4つのテクスチャが占める高さは次のとおりです。2+101+2+101+2+101+2+101=412、残り100ピクセルで、これは垂直方向の5行目のTexureにもう足りません（5行目と4行目の間に2ピクセルのパディングがあることは言うまでもありません）。

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

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