Unity durchsuchen

Einige der besten Optimierungstipps für Unity UI

Last updated: January 2019

What you will get from this page: Tips on how to create optimized UI elements for your content, including dividing up your canvases, avoiding the use of Camera.main and Layout Groups, smart pooling of UI objects and more.

You’ll find many more in this great session by Unity engineer Ian Dundore, "Squeezing Unity: Tips for raising performance" (section on Unity UI starts at 23:38).

Teilen Sie Ihre Canvases auf

Problem: Wenn sich ein Element oder mehrere Elemente auf der UI-Canvas ändern, treten Konflikte auf.

Die Canvas ("Leinwand") is the basic component of Unity UI. It generates meshes that represent the UI elements placed on it, regenerates the meshes when UI elements change, and issues draw calls to the GPU so that the UI is actually displayed.

Die Erzeugung dieser Meshes kann aufwändig sein. UI-Elemente müssen in Batches gesammelt werden, damit zum Aufrufen so wenig Drawcalls wie möglich notwendig werden. Da die Batcherzeugung aufwändig ist, wollen wir sie nur regenerieren, wenn es wirklich nötig ist. Das Problem ist: Wenn sich ein oder mehrere Elemente auf der Canvas ändern, muss die gesamte Canvas neu analysiert werden um festzustellen, wie ihre Elemente optimal aufgerufen werden können.

Viele Benutzer erstellen die UI ihres gesamten Spiels auf nur einer Canvas mit tausenden Elementen. Wenn sie jetzt ein Element ändern, erleben sie eine CPU-Spitzenauslastung von mehreren Millisekunden (weitere Informationen dazu hören Sie in Ians Vortrag ab Minute 24:55).

Lösung: Teilen Sie Ihre Canvases auf.

Jede Canvas ist eine Insel, die ihre Elemente von Elementen auf anderen Canvases isoliert. Das Aufteilen von Canvases ist also das hauptsächliche Tool für die Lösung von Batching-Problemen mit Unity-UI.

Sie können Canvases auch verschachteln, was Designern ermöglicht, große, hierarchische UIs zu erstellen, ohne darüber nachzudenken, wo verschiedene Objekte onscreen über verschiedene Canvases erscheinen. Child-Canvases isolieren Inhalte ebenfalls, sowohl von Parent- als auch von Sibling-Canvases. Sie behalten ihre eigene Geometrie bei und führen ihr eigenes Batching durch.

Wenn Sie Canvases in Child-Canvases unterteilen, versuchen Sie sie nach dem Zeitpunkt ihrer Aktualisierung zu gruppieren. Separieren Sie beispielsweise dynamische Elementen von statischen Elementen (etwa ab Minute 29:36 gibt Ian ein schönes Beispiel zur geschickten Unterteilung von Canvases).

Optimale Verwendung des Graphic Raycaster

Problem: Optimale Verwendung des Graphic Raycasters:

Der Graphic Raycaster ist eine Komponente, die Ihre Eingaben in UI-Events übersetzt. Screen-/Touch-Eingaben werden in Events übersetzt und dann an geeignete UI-Elemente gesendet. Sie brauchen auf jeder Canvas, die Eingaben erfordert, einen Graphic Raycaster, auch für Sub-Canvases.

Trotz seines Namens ist der Graphic Raycaster eigentlich kein Raycaster: standardmäßig testet er lediglich die UI-Grafik. Er führt an einem Set von UI-Elementen, die auf einer Canvas auf Eingaben warten, Überschneidungsprüfungen durch. Er überprüft, dass der Punkt, an dem das Input-Event gegen den RectTransform jedes UI-Elements auf der Canvas des GraphicRaycasters auftritt, als interaktiv markiert ist.

Die Herausforderung dabei ist, dass nicht alle UI-Elemente daran interessiert sind, Updates zu erhalten.

Lösung: Schalten Sie den Raycast-Target für statische und nicht-interaktive Elemente aus.

Ein Beispiel ist Text auf einer Schaltfläche. Das Ausschalten des Raycast-Targets reduziert sofort die Anzahl der Überschneidungsprüfungen, die der Graphic Raycaster jedes Frame durchführen muss.

Unity UI: Tipps zur Optimierung

Problem: In manchen Belangen verhält sich der Graphic Raycaster nicht wie ein Raycaster.

Wenn Sie den Render-Modus auf Ihrer Canvas auf Worldspace-Kamera oder Screen-Space-Kamera setzen, können Sie auch eine Blocking Mask einstellen. Die Blocking Mask bestimmt, ob der Raycaster Strahlen über 2D- oder 3D-Physik ausgibt, um festzustellen, ob ein Physikobjekt blockierend wirkt und verhindert, dass der Benutzer mit der UI interagieren kann.

Lösung: Das Raycasting über 2D- und 3D-Physik kann aufwändig sein, nutzen Sie diese Funktion nicht zu häufig.

Reduzieren Sie außerdem die Anzahl der Graphic Raycaster, indem Sie sie nicht-interaktiven UI-Canvases nicht hinzufügen, da in diesem Fall keine Notwendigkeit für die Überprüfung von Interaktions-Events besteht.

Vermeiden Sie die Verwendung von Camera.main

Problem: World-Space-Canvases müssen wissen, von welcher Kamera ihre Interaktions-Events kommen sollen.

Wenn Sie eine Canvas einrichten, um entweder im World Space oder im Screen Space einer Kamera zu rendern, ist es möglich, die Kamera anzugeben, die für die Erzeugung von Interaktions-Events für den Graphic Raycaster der UI verwendet wird. Diese Einstellung ist für "Screen Space - Camera"-Canvases erforderlich und heißt "Render Camera".

Unity UI optimization tips screen space camera

Für "World Space"-Canvases ist diese Einstellung allerdings optional und heißt "Event Camera".

Unity UI optimization tips world space

Wenn Sie auf einer World-Space-Canvas das Feld "Event Camera" leer lassen, bedeutet das nicht, dass Ihre Canvas keine Events empfängt, sondern dass sie dazu die Hauptkamera (Main Camera) verwendet. Um festzustellen, welche Kamera die Hauptkamera ist, greift sie auf die Camera.main-Eigenschaft zu.

Unity UI optimization tips camera main property

Abhängig vom Codepfad, den Unity einschlägt, greift sie 7 bis 10 Mal pro Frame auf Camera.main zu, jeweils pro Graphic Raycaster und pro World-Space-Canvas. Und Camera.main ruft bei jedem Zugriff Object.FindObjectWithTag auf! Das ist zur Laufzeit ganz offensichtlich nicht günstig.

Lösung: Vermeiden Sie die Verwendung von Camera.main.

Nehmen Sie Referenzen zu Kameras in den Cache auf und erstellen Sie ein System zur Feststellung der Hauptkamera. Wenn Sie World-Space-Canvases verwenden, weisen Sie immer eine Event Camera zu. Lassen Sie diese Einstellung nicht leer! Wenn die Event Camera geändert werden muss, schreiben Sie Code, der die Event-Camera-Eigenschaft aktualisiert.

Vermeiden Sie nach Möglichkeit Layout-Gruppen

Problem: Jedes UI-Element, dessen Layout "dirty" wird, führt mindestens einen GetComponents-Aufruf durch.

Wenn sich eins oder mehrere Child-Elemente eines Layout-Systems ändern, wird es "unsauber" ("dirty"). Die geänderten Child-Elemente machen das Layout-System, dem sie gehören, quasi ungültig.

Etwas zu Layout-Systemen: Ein Layout-System ist ein Satz zusammenhängender Layout-Gruppen, die direkt über einem Layout-Element liegen. Ein Layout-Element ist nicht nur die Layout-Element-Komponente: UI-Images, Texte und Scroll Rects sind ebenfalls Layout-Elemente. Und Scroll Rects sind auch Layout-Gruppen.

Aber zurück zum Problem: Jedes UI-Element, das sein Layout als "dirty" kennzeichnet, führt mindestens einen GetComponents-Aufruf durch. Dieser Aufruf sucht nach einer gültigen Layout-Gruppe auf dem Parent des Layout-Elements. Wird eine Gruppe gefunden, steigt er die Transform-Hierarchie weiter hinauf, bis keine weiteren Layout-Gruppen gefunden werden können oder die Hierarchie-Root erreicht ist – je nachdem, was zuerst passiert. Folglich fügt jede Layout-Guppe einen GetComponents-Aufruf zu jedem Dirtying-Prozess eines Child-Layout-Elements hinzu, was verschachtelte Layout-Gruppen äußerst nachteilig für die Performance macht.

Lösung: Vermeiden Sie nach Möglichkeit Layout-Gruppen.

Nutzen Sie Anchors für proportionale Layouts. Erwägen Sie, für UIs mit einer dynamischen Anzahl von Elementen eigenen Code zu schreiben, der Layouts berechnet und nutzen Sie diesen lediglich bei Bedarf statt bei jeder einzelnen Änderung.

Legen Sie UI-Objekte geschickt im Pool ab

Problem: UI-Objekte werden "falsch herum" im Pool abgelegt.

Oft werden UI-Objekte im Pool abgelegt, indem ein Re-Parenting durchgeführt und das Objekt danach deaktiviert wird, aber das führt zu unnötigen Dirty-Prozessen.

Lösung: Deaktivieren Sie zuerst das Objekt und führen Sie dann ein Re-Parenting in den Pool durch.

Die alte Hierarchie wird auf diese Weise zwar einmal "unsauber" ("dirty"), aber durch das Reparenting vermeiden Sie, sie ein zweites Mal "dirty" zu machen. Die neue Hierarchie bleibt außerdem völlig sauber. Wenn Sie ein Objekt aus dem Pool entfernen, führen Sie zunächst ein Reparenting durch, aktualisieren Sie dann Ihre Daten und aktivieren sie es danach.

Wie man eine Canvas verbirgt

Problem: Eine Canvas verbergen

Manchmal sollen UI-Elemente und Canvases verborgen werden. Wie kann man das am effizientesten tun?

Lösung: Deaktivieren Sie die Canvas-Komponente

Die Deaktivierung der Canvas-Komponente bewirkt, dass die Canvas keine Drawcalls mehr an die GPU ausgibt und somit nicht länger sichtbar ist. Die Canvas löscht dabei aber nicht ihren Vertex-Buffer; alle Meshes und Vertices bleiben erhalten und wenn Sie sie wieder aktivieren, wird kein Rebuild ausgelöst, sondern es werden einfach wieder Drawcalls gestartet.

Weiterhin löst die Deaktivierung der Canvas-Komponente keine aufwändigen OnDisable/OnEnable-Callbacks in der Canvas-Hierarchie aus. Achten Sie darauf, Child-Komponenten zu deaktivieren, die aufwändigen Pro-Frame-Code ausführen.

Optimale Verwendung von Animatoren für UI-Elemente

Problem: Die Verwendung von Animatoren auf der UI

Animatoren machen ihre Elemente mit jedem Frame "dirty", selbst wenn sich der Wert in der Animation nicht ändert. Animatoren verfügen nicht über Nulloperation-Prüfungen.

Lösung:

Only put animators on dynamic elements that always change. For elements that rarely change or that only change in response to events, for a short period of time, write your own code or tweening system (there are a number on the Asset Store).

Weitere Ressourcen

Wir wollen es wissen! Haben Ihnen diese Inhalte gefallen?

Ja, weiter so. Na ja. Könnte besser sein.
Alles klar

Wir verwenden Cookies, damit wir Ihnen die beste Nutzererfahrung auf unserer Website bieten können. Weitere Informationen erhalten Sie in unserer Cookie-Richtlinie.