Unity Canvas Optimierung an einem Beispiel

Einleitung

In diesem Artikel betrachten wir verschiedene Aspekte und Möglichkeiten, um die uGUI von Unity richtig einzusetzen und die Performance zu verbessern. Das Ganze wird anhand eines Beispiels demonstriert.

Ich bin zu diesem Thema gekommen, als ich einen kleinen Bug in der Tastatur des MixedRealityToolkits für die HoloLens beheben wollte. Dazu habe ich schlussendlich die Test-Szene der Tastatur auf die HoloLens geladen, um den Fix zu testen. Dabei fiel mir auf, dass durch die schlechte Performance der Tastatur die Applikation nahezu unbenutzbar ist.

Hierzu ein kleines Video mit der Test-Szene und eine FPS-Anzeige. Es ist zu beachten, dass aufgrund der Aufnahme die FPS bereits auf maximal 19 FPS eingeschränkt sind.

Die FPS sinkt auf sieben, wodurch die Benutzung der Tastatur alles andere als flüssig ist. Der Cursor folgt kaum der Blickrichtung, die Hervorhebung der Tasten ist schwerfällig und das Schreiben ist stark verzögert.

Quelle der Probleme

Das grundlegende Problem in diesem Fall ist die Aufteilung der einzelnen Tasten in einzelne UI Draw Batches. Draw Batches sind die Zusammenfassung von ähnlichen Elementen in einem einzigen Draw Call, wobei sehr viel Zeit gespart werden kann. Es ist sehr einfach, diese Batches zu unterbrechen und damit die Performance zu hindern. Es gilt also herauszufinden, welche Gründe es in diesem Fall gibt, warum die Batches nicht zusammengefasst sind.

Unser Ausgangszustand ist eine Gesamtanzahl von etwa 85 Batches von der Tastatur. Die Anzahl lässt sich im UI-Profiler auslesen und über den Frame-Debugger kann man die einzelnen Draw Calls abspielen.

Seit Unity 2017.1 gibt es die neuen UI-Profiler, welche Hinweise auf die Gründe geben können. Diese können jedoch nicht alle Gründe erkennen und sollten somit also nicht zu ernst genommen werden. In unserem Fall bekommen wir den Hinweis, dass alle Elemente unterschiedliche Texturen haben, wobei dies in Wahrheit nur für einen Teil zutrifft.

Z-Positionen

Die Tastatur ist in verschiedenen Z-Ebenen unterteilt, wobei Unterelemente jeweils einen kleinen Z-Offset besitzen. Die uGUI Canvas Elemente müssen in der selben Z-Ebene liegen, damit diese in einem Batch zusammengefasst werden können. Mit dieser einfachen Änderung sind wir schon auf etwa zwölf Batches runter, da nun fast alle Text-Elemente auf der Tastatur auf einen Schlag gezeichnet werden können.

Sprite Atlas

Der nächste große Sprung ist das Zusammenfassen von Texturen in einen sogenannten Sprite Atlas. Alle UI-Elemente referenzieren dieselbe Textur und stellen nur einen Teil derer dar, um somit alle Draw Calls auf einen Nenner zu bekommen. Diese Funktion ist mit Unity 2017.1 bereits eingebaut und muss nur über Editor Settings > Sprite Packer > Always Enabled aktiviert werden. Danach legt man über das Contextmenü in einem Ordner einen neuen Sprite Atlas an und gibt die Ordner an, in denen sich die Texturen befinden. Der Rest geschieht vollkommen automatisch. Möglicherweise muss man Rotation und Tight Packing im Sprite Atlas deaktivieren, um Überschneidungen zu vermeiden.

Mit dieser kleinen Änderung sind nun alle Buttons mit Icons auf der Tastatur zusammengefasst und wir sinken auf vier Batches.

Reihenfolge in der Hierarchy

Den letzten Ausreißer habe ich nur durch ausprobieren herausgefunden. Jede Taste auf der Tastatur besitzt ein Text/Icon und weiterhin ein Highlight-Element, womit der Fokus der Taste dargestellt wird. In der Hierarchy auf den Elementen liegt das Highlight-Element immer als erstes und danach folgen die anderen Elemente.

Aus einem mir unbekannten Grund, hat diese Konstellation zur Folge, dass der Text in einem einzelnen Batch gezeichnet wird. Um dies zu beheben, muss man die Reihenfolge der zwei Elemente auf allen Tasten der Tastatur umdrehen, sodass das Highlight-Element immer am Ende steht.

Fazit und Resultat

Es ist sehr einfach das Draw Batching in Unity zu zerstören, jedoch bietet Unity mit den verschiedenen Profilern und dem Frame-Debugger sehr gute Tools, um den Problemen nachzugehen. Letztendlich mussten wir für diese Optimierungen noch nicht mal eine einzige Zeile Code schreiben. Die Problemstellen sollte man direkt beim Erstellen der UI beachten und weiterhin ab und zu mit den Profilern überprüfen.

Nach diesen Änderungen wird die komplette Tastatur in den folgenden drei Aufrufen gezeichnet:

  1. Hintergrund
  2. Text
  3. Texturen

Auch auf der HoloLens läuft die Applikation um ein Vielfaches besser. Das Aufrufen der Tastatur verursacht nicht mehr einen kompletten Einbruch der FPS.

Anhang

Issue im Repository des MixedRealityToolkits.

Der PullRequest mit den Änderungen.

Unite ’17 Seoul – Tips and Tricks for Optimising Unity UI

Unite Europe 2017 – Squeezing Unity: Tips for raising performance