Unity BatchesとglDrawElementsの関係


今回の話題:
1)UnityBatchesとglDrawElementsの関係
2)広い草地をレンダリングすると時にコストを減らす方法
3)HUDはカメラとともにオフセットする原理
4)Unityでは、垂直画面モードのUIの上に強制水平画面のUIを表示する方法
5)iOSのコストの問題


Rendering

Q:Unityでは、FrameDebugは422のDrawCallと435のBatchesが表示されています。SnapDragonProfilerでキャプチャされたglDrawElementsの数は1449です。この違いをどのように理解しますか?

A1:以下の点を参考にしてください。
1.問題主のデータに問題があります。DrawCallの数はBatchs以上である必要があります。特定のルールによれば、複数のDrawCallは1つのBatchesと見なすことができ、1つのBatchesには複数のDrawCallが含まれるため、データを送信するCPUの操作の一部が節約されます。
2.glDrawElements関数を呼び出して描画することは、DrawCallの形式の一つです。

A2:このパートについては、UWA Day 2022で張さんが共有した「Unityモバイルゲームプロジェクトの最適化ケース分析(パート1)」(中国語注意)の2番目のセクションを参照してください。

Rendering

**Q1:広い範囲の草地をレンダリングする時にコストを減らすにはどうすればよいですか?

A1:以下の点があります。
1.DrawMeshInstanceを使用します。
2.上記のAPIは、視線カリング、錐台カリング(Frustum Culling)、および閉塞カリング(Occlusion Culling)を実行しません。
2つのオプションがあります。
a.草地を面積でグループ化し、各グループの中心点を使用して表示視的距離を計算し、その距離に応じてメッシュLODに切り替えるか削除するかを実行します
ベクトル内積を使用して、カメラの背後にある草を単純に除去することもできます。 (臨界問題に注意を払う)
b.CullingGroupを使用します
CullingGroup.onStateChangedイベントバインディング。イベントトリガーを介して、DrawMeshInstancedに渡されるMatrixの順序とレンダリング量を調整します。(より難しいのは、DrawMeshInstancedがレンダリング用に最初のいくつかのMatrixしか指定できないことです)
cullingGroup.SetBoundingSpheresを介して錐台カリングと閉塞カリングを実現します。
cullingGroup.SetBoundingDistancesを介して視線カリングとLODを実現します。
このソリューションは、区域のグループ化にも最適です。そうしないと、CullingGroupのイベント監視の占有率が高くなります。ミドルエンドモデルの4000台のモニターは約2msかかります。
将来、2つのソリューションのパフォーマンスを比較する場合は、追加します。

A2: IndirectモードのInstancingを使用して、ComputerShaderを合わせて錐台カリングと閉塞カリングを実現できます。

Q2:スマートフォンで使用できますか?

A:URPで作られた草海効果をお勧めします。Mobile端末でも使用できます。
Unity URP Mobile Draw Mesh Instanced Indirect Example

パーフォマンステスト:

can handle 10 million instances on Samsung Galaxy A70 (GPU = adreno612, not a strong GPU), 50~60fps, performance mainly affected by visible grass count on screen(draw distance = 125)

can handle 10 million instances on Lenovo S5 (GPU = adreno506, a weak GPU), 30fps, performance mainly affected by visible grass count on screen(draw distance = 75)

Rendering

Q:HUDがカメラとともにオフセットするのはなぜですか?

コードは次のように表示されます。

Vector3 midVe1   = obj.transform.position;
    Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1 + new Vector3(0, 2, 0));
    viewPose.x *= Screen.width;
    viewPose.y *= Screen.height;
    hud.anchoredPosition = viewPose;

写真は次のとおりです。




A:上記の現象は合理的です。

Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1); Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1 + new Vector3(0, 2, 0));

計算された2つのviewPos.xは同じではありません。したがって、最初にxを計算し、次にyをオフセットするように変更できます。次のようになります。

Vector3 midVe1 = obj.transform.position; Vector2 viewPose = worldCamera.WorldToViewportPoint(midVe1); viewPose.x *= Screen.width; viewPose.y *= Screen.height; viewPose.y += 130; hud.anchoredPosition = viewPose;

ここで、y方向のオフセット値(130)は自分で調整する必要があります。

UGUI

Q1:Unityでは、垂直画面モードUIの上に強制水平画面UIを表示する方法に関して、2つのアイデアがあります。
1.Screen.orientationを変更した後に表示します。
–内側を適応させる前に、外側のRectTransformが画面遷移によって引き起こされた変更を「完了」したかどうかを考慮する必要があります。信頼できるイベントは見つかりませんでした。
–背景を処理する必要があるため、半透明の背景は背後のUIレイアウトの混乱を明らかにする可能性があります。
2.新しいUIをz軸上で-90度回転させて、表示します。
– Notch Screenへの適応はそれに応じて修正する必要があります。
–画面を切り替えることができません(画面がまだ垂直で、Upside Downをサポートしていないため)。しかし、これは克服されるはずです。
この二つの方法、どちらがいいですか?

A1:簡単な方法:
CanvasのRenderModeがWorldSpaceに変更され、カメラがどのようにトリミングされても、UIキャンバスは変更されません。
自適応できない場合は、必要に応じてCanvasで実行してください。

A2:以前のプロジェクトでも同様の要件がありました。水平スクリーンゲームでは、個々のプレイ方は垂直スクリーンに切り替えられました。
当時採用された解決策は、Screen.orientationを変更すると同時に、UIのグローバルルートノードでCanvasScalerのreferenceResolutionを変更することでした(垂直画面の場合は1080、1920、水平画面の場合は1920、1080に設定)。 matchWidthOrHeight(プロジェクトの適応策略に関連します。垂直画面の場合は0、水平画面1に設定)、切り替え時に、表示エラーを回避するために、フルスクリーンマスクのfade効果があります。

Q2:90度回転してみませんか?

A:当時は回転の方法をテストしていませんでした。今、正しいかどうかはわかりませんが、2つの問題があると思います。
1.単純な回転角度では、水平画面の中央部分に垂直画面インターフェイスのみを表示する必要がありますね。他の処理が必要なようです。
2.ワークフローに影響しますか?垂直画面インターフェイスが必要な場合、制作中に最初に水平画面インターフェイスを作成する必要がありますか?内部コントロールを処理する必要がありますか?たとえば、最終的に垂直画面効果を示すプロットテキストは左から右に表示され、回転する前に水平画面で下から上に表示され、各テキストも回転されます。

Q3:RectTransformのサイズは変更が遅延されますが、問題はありませんか?

A:はっきりとは覚えていませんが、印象に大きな問題はありませんでした。しかし、この種の需要に切り替えたとき、それはすべてフルスクリーンUIであり、マスクFadeを追加した後の明らかなバレは見えませんでした。

iOS

Q:Xcode実機のデバッグ中、コスト量は常にVery Highに置かれていることがわかりました。こちらのプロジェクトの基本的な状況は次のとおりです(GPUレンダリング3.5ms /フレーム、60フレーム/秒、レンダリング解像度750 * 1624、デバイスiPhone XS 、シーンUGUIのみに他の3Dまたは2Dオブジェクトはありません)、この電力消費が正常であるかどうかを確認してもらえませんか?最適化の余地はありますか?(プロジェクトの効果に影響を及ぼすため、フレーム数と解像度は低下できないと思います)

A1:テスト後、空のシーンのAverage Energy ImpactもVery Highに表示されます(下の図を参照)。問題主のGPUエネルギー消費量は比較的に大きいというのは、CPUのストレスは比較的に小さいと言えます。

この投稿も同様の問題です。Unityエンジン自体が通常のAPPよりも大きいため、エネルギー消費量が多く見えます。目標フレームレートを下げると改善されるようです。

Energy Impactは、グローバル(単一のAPPではない)のエネルギー消費量を特徴付けるものであり、テスト中の統計でUSB接続の充電がどのように回避されるかは明確ではありません。XcodeInstrumentsツールのEnergy Logテンプレートを使用して、単一のAPPのエネルギーコスト量を測定します。

Energy Logドキュメント

エネルギー消費の最適化に関しては、最初にGPU全体またはCPU(または他の側面)のどちらに焦点を当てますか?GPUはFrameCaptureを使用して、時間コストが高いShaderを特定して、最適化します。CPUはTimeProfilerテンプレートと組み合わせて、いくつかの高エネルギーCPU Boundを特定します。

A2:GPUはFrameCaptureを使用して、時間コストが高いShaderを特定して、最適化します。肝心なのはどのフレームをCaptureするかは、非常にブラインドになります。


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