Leistungsempfehlungen für UnityPerformance recommendations for Unity

Dieser Artikel baut auf den Leistungsempfehlungen für Mixed Reality auf, konzentriert sich aber auf Unity-spezifische Verbesserungen.This article builds on the performance recommendations for mixed reality, but focuses on Unity-specific improvements.

Der wichtigste erste Schritt beim Optimieren der Leistung von Mixed Reality-Apps in Unity besteht darin, sicherzustellen, dass Sie die empfohlenen Umgebungseinstellungen für Unity verwenden.The most important first step when optimizing performance of mixed reality apps in Unity is to be sure you're using the recommended environment settings for Unity. Der betreffende Artikel enthält Inhalte mit einigen der wichtigsten Szenenkonfigurationen zum Entwickeln leistungsfähiger Mixed Reality-Apps.That article contains content with some of the most important scene configurations for building performant Mixed Reality apps. Einige dieser empfohlenen Einstellungen werden unten ebenfalls hervorgehoben.Some of these recommended settings are highlighted below, as well.

So erstellen Sie ein Profil mit UnityHow to profile with Unity

Unity bietet den integrierten Unity Profiler , der eine hervorragende Ressource zum Sammeln wertvoller Einblicke zur Leistung für Ihre bestimmte App darstellt.Unity provides the Unity Profiler built-in, which is a great resource to gather valuable performance insights for your particular app. Der Profiler kann zwar im Editor ausgeführt werden, diese Metriken stellen aber nicht die reale Laufzeitumgebung dar, daher sollten Ergebnisse aus diesen Profilerläufen mit Umsicht angewendet werden.Although you can run the profiler in-editor, these metrics don't represent the true runtime environment so results should be used cautiously. Um besonders genaue und verwertbare Ergebnisse zu erhalten, empfiehlt es sich, das Profil Ihrer Anwendung während der Ausführung auf einem Gerät remote zu bestimmen.We recommended remotely profiling your application while running on device for most accurate and actionable insights. Darüber hinaus stellt der Frame Debugger von Unity ebenfalls ein leistungsstarkes Tool dar, mit dem sich Erkenntnisse gewinnen lassen.Further, Unity's Frame Debugger is also a powerful and insight tool to use.

Unity bietet eine hervorragende Dokumentation zu diesen Punkten:Unity provides great documentation for:

  1. Herstellen einer Remoteverbindung zwischen dem Unity-Profiler und UWP-AnwendungenHow to connect the Unity profiler to UWP applications remotely
  2. Effektive Diagnose von Leistungsproblemen mit dem Unity ProfilerHow to effectively diagnose performance problems with the Unity Profiler

Hinweis

Bei verbundenem Unity Profiler und nach dem Hinzufügen des GPU-Profilers (siehe dazu Add Profiler („Profiler hinzufügen“) in der oberen rechten Ecke) lässt sich in der Mitte des Profilers ablesen, wie viel Zeit für CPU bzw. GPU aufgewendet wird.With the Unity Profiler connected and after adding the GPU profiler (see Add Profiler in top right corner), one can see how much time is being spent on the CPU & GPU respectively in the middle of the profiler. Dadurch kann der Entwickler näherungsweise einschätzen, ob seine Anwendung CPU- oder GPU-lastig ist.This allows the developer to get a quick approximation if their application is CPU or GPU bounded.

Unity-CPU im Vergleich zu -GPU

CPU-LeistungsempfehlungenCPU performance recommendations

Die Inhalte unten befassen sich mit tiefgreifenden Praktiken zur Leistungsverbesserung, insbesondere für die Entwicklung mit Unity und C# bestimmt.The content below covers more in-depth performance practices, especially targeted for Unity & C# development.

Zwischenspeichern von VerweisenCache references

Wir empfehlen, Verweise auf alle relevanten Komponenten und GameObjects bei der Initialisierung zwischenzuspeichern, da wiederholte Funktionsaufrufe wie GetComponent<T>() und Camera.main relativ zu den Speicherkosten für die Speicherung eines Zeigers teurer sind.We recommend caching references to all relevant components and GameObjects at initialization because repeating function calls such as GetComponent<T>() and Camera.main are more expensive relative to the memory cost to store a pointer. .. Camera.main basiert auf der zugrundeliegenden Funktion FindGameObjectsWithTag() , die aufwändig Ihre Szenendarstellung nach einem Kameraobjekt mit dem Tag „MainCamera“ absucht.Camera.main just uses FindGameObjectsWithTag() underneath, which expensively searches your scene graph for a camera object with the "MainCamera" tag.

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

Hinweis

Vermeiden von GetComponent(string)Avoid GetComponent(string)
Beim Verwenden von GetComponent() haben Sie es mit einer handvoll verschiedener Überladungen zu tun.When using GetComponent(), there are a handful of different overloads. Es ist wichtig, immer die typbasierten Implementierungen und nie die zeichenfolgenbasierte Suchüberladung zu verwenden.It is important to always use the Type-based implementations and never the string-based searching overload. Die Suche nach der Zeichenfolge in Ihrer Szene ist erheblich teurer als die Suche nach dem Typ.Searching by string in your scene is significantly more costly than searching by Type.
(Gut) Component GetComponent(Typ Typ)(Good) Component GetComponent(Type type)
(Gut) T GetComponent<T>()(Good) T GetComponent<T>()
(Schlecht) Component GetComponent(string)>(Bad) Component GetComponent(string)>

Vermeiden aufwändiger VorgängeAvoid expensive operations

  1. Vermeiden Sie die Verwendung von LINQAvoid use of LINQ

    Zwar kann LINQ sauber und einfach zu lesen und zu schreiben sein, es erfordert im Allgemeinen aber mehr Berechnungen und Speicher, als sie für einen manuell geschriebenen Algorithmus erforderlich wären.Although LINQ can be clean and easy to read and write, it generally requires more computation and memory than if you wrote the algorithm manually.

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. Allgemeine Unity-APIsCommon Unity APIs

    Bestimmte Unity-APIs können zwar nützlich sein, sind in der Ausführung aber kostspielig.Certain Unity APIs, although useful, can be expensive to execute. Die meisten davon beinhalten das Durchsuchen Ihres gesamten Szenendarstellung nach einer Liste passender Spielobjekte.Most of these involve searching your entire scene graph for some matching list of GameObjects. Diese Vorgänge können im Allgemeinen durch das Zwischenspeichern von Verweisen oder das Implementieren einer Manager-Komponente für die GameObjects vermieden werden, um die Verweise zur Laufzeit zu verfolgen.These operations can generally be avoided by caching references or implementing a manager component for the GameObjects to track the references at runtime.

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

Hinweis

SendMessage() und BroadcastMessage() sollten unter allen Umständen entfernt werden.SendMessage() and BroadcastMessage() should be eliminated at all costs. Diese Funktionen können der Größenordnung nach 1000mal langsamer als direkte Funktionsaufrufe sein.These functions can be on the order of 1000x slower than direct function calls.

  1. Vermeiden von BoxingBeware of boxing

    Boxing ist ein Grundkonzept der C#- Sprache und ihrer Runtime.Boxing is a core concept of the C# language and runtime. Dabei handelt es sich um den Prozess, Variablen eines Werttyps, wie etwa char, int, bool usw., mit Variablen vom Verweistyp zu umschließen.It's the process of wrapping value-typed variables such as char, int, bool, etc. into reference-typed variables. Wenn eine Variable eines Werttyps „geboxt“ ist, ist sie von einem System.Object umschlossen, das auf dem verwalteten Heap gespeichert wird.When a value-typed variable is "boxed", it's wrapped in a System.Object, which is stored on the managed heap. Speicher wird zugewiesen und muss gegebenenfalls beim Verwerfen vom Garbage Collector verarbeitet werden.Memory is allocated and eventually when disposed must be processed by the garbage collector. Diese Zuweisungen und ihre Aufhebung bringen Leistungskosten mit sich und sind in vielen Szenarien unnötig oder können leicht durch preiswertere Alternativen ersetzt werden.These allocations and deallocations incur a performance cost and in many scenarios are unnecessary or can be easily replaced by a less expensive alternative.

    Um das Boxing zu vermeiden, stellen Sie sicher, dass die Variablen, Felder und Eigenschaften, in denen Sie numerische Typen und Strukturen (einschließlich Nullable<T>) speichern, stark als spezifische Typen typisiert sind, wie z. B. int, float? oder MyStruct, anstatt ein Objekt zu verwenden.To avoid boxing, be sure that the variables, fields, and properties in which you store numeric types and structs (including Nullable<T>) are strongly typed as specific types such as int, float? or MyStruct, instead of using object. Wenn Sie diese Objekte in eine Liste einfügen, stellen Sie sicher, dass Sie eine stark typisierte Liste verwenden, z. B. List<int> anstatt List<object> oder ArrayList.If putting these objects into a list, be sure to use a strongly typed list such as List<int> rather than List<object> or ArrayList.

    Beispiel für Boxing in C#Example of boxing in C#

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

Wiederholte CodepfadeRepeating code paths

Alle wiederholten Unity-Rückruf-Funktionen (d. h.Any repeating Unity callback functions (i.e Update), die mehrmals pro Sekunde und/oder Frame ausgeführt werden, sollten mit Sorgfalt geschrieben werden.Update) that are executed many times per second and/or frame should be written carefully. Alle aufwändigen Vorgänge an dieser Stelle haben einen sehr großen und konsistenten Einfluss auf die Leistung.Any expensive operations here will have huge and consistent impact on performance.

  1. Leere RückruffunktionEmpty callback functions

    Zwar mag der Code unten harmlos aussehen, und Sie neigen wohl dazu, ihn in Ihrer Anwendung zu belassen, vor allem, da sich jedes Unity-Skript automatisch mit einer Update-Methode initialisiert, diese leeren Rückrufe können aber teuer werden.Although the code below may seem innocent to leave in your application, especially since every Unity script auto-initializes with an Update method, these empty callbacks can become expensive. Unity überquert bei der Arbeit ständig in beiden Richtungen eine Grenze zwischen verwaltetem und nicht verwaltetem Code, nämlich zwischen dem Code der UnityEngine und Ihrem Anwendungscode.Unity operates back and forth between an unmanaged and managed code boundary, between UnityEngine code and your application code. Der Kontextwechsel beim Überqueren dieser Grenze ist ziemlich teuer, auch dann, wenn es gar nichts auszuführen gibt.Context switching over this bridge is fairly expensive, even if there's nothing to execute. Dies wird besonders dann problematisch, wenn Ihre App über 100e von Spielobjekten verfügt, die ihrerseits wiederholte leere Unity-Rückrufe verwenden.This becomes especially problematic if your app has 100s of GameObjects with components that have empty repeating Unity callbacks.

    void Update()
    {
    }
    

Hinweis

Update () ist die gängigste Form dieses Leistungsproblems, aber andere sich wiederholende Unity-Rückrufe, wie z. B. die folgenden, können genauso schlecht sein, wenn nicht gar schlechter: FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage() usw.Update() is the most common manifestation of this performance issue but other repeating Unity callbacks, such as the following can be equally as bad, if not worse: FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage(), etc.

  1. Vorgänge, die vorzugsweise einmal pro Frame ausgeführt werden solltenOperations to favor running once per frame

    Die folgenden Unity-APIs stellen gängige Vorgänge für viele Holografie-Apps dar.The following Unity APIs are common operations for many Holographic Apps. Es ist zwar nicht immer möglich, aber oft können die Ergebnisse dieser Funktionen einmal berechnet und dann für einen bestimmten Frame im gesamten Bereich der Anwendung wiederverwendet werden.Although not always possible, the results from these functions can commonly be computed once and the results reutilized across the application for a given frame.

    a) Es ist eine gute Praxis, eine dedizierte Singleton-Klasse oder einen Dienst einzusetzen, die bzw. der Ihren Raycast vom Anvisieren der Szene verarbeitet, und dieses Ergebnis dann in allen anderen Szenekomponenten wiederzuverwenden, statt wiederholte und identische Raycastvorgänge für jede Komponente auszulösen.a) It's good practice to have a dedicated Singleton class or service to handle your gaze Raycast into the scene and then reuse this result in all other scene components, instead of making repeated and identical Raycast operations by each component. In manchen Anwendungen sind möglicherweise Raycasts aus einem anderen Ursprung oder gegen andere LayerMasks (Ebenenmasken) erforderlich.Some applications may require raycasts from different origins or against different LayerMasks.

        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    

    b) Vermeiden Sie GetComponent()-Vorgänge in wiederholten Unity-Rückrufen wie Update(), indem Sie Verweise zwischenspeichern: in Start() oder Awake()b) Avoid GetComponent() operations in repeated Unity callbacks like Update() by caching references in Start() or Awake()

        UnityEngine.Object.GetComponent()
    

    c) Es ist eine bewährte Methode, nach Möglichkeit alle Objekte bei der Initialisierung zu instanziieren und Objektpooling zu verwenden, um die gesamte Laufzeit Ihrer Anwendung hindurch Spielobjekte zu recyceln und wiederzuverwendenc) It's good practice to instantiate all objects, if possible, at initialization and use object pooling to recycle and reuse GameObjects throughout runtime of your application

        UnityEngine.Object.Instantiate()
    
  2. Vermeiden von Schnittstellen und virtuellen KonstruktenAvoid interfaces and virtual constructs

    Das Aufrufen von Funktionsaufrufen über Schnittstellen im Gegensatz zu direkten Objekten oder dem Aufrufen von virtuellen Funktionen ist oftmals sehr viel kostspieliger als die Verwendung direkter Konstrukte oder direkter Funktionsaufrufe.Invoking function calls through interfaces vs direct objects or calling virtual functions can often be much more expensive than using direct constructs or direct function calls. Wenn die virtuelle Funktion oder Schnittstelle nicht benötigt wird, sollte sie entfernt werden.If the virtual function or interface is unnecessary, then it should be removed. Der Leistungspreis für diese Ansätze spricht aber für den Kompromiss, wenn ihre Verwendung die Zusammenarbeit bei der Entwicklung vereinfacht, die Lesebarkeit und die Wartbarkeit des Codes verbessert.However, the performance hit for these approaches is worth the trade-off if using them simplifies development collaboration, code readability, and code maintainability.

    Im Allgemeinen wird empfohlen, Felder und Funktionen nicht als virtuell zu markieren, es sei denn, es gibt eine klare Annahme, dass das betreffende Element überschrieben werden muss.Generally, the recommendation is to not mark fields and functions as virtual unless there's a clear expectation that this member needs to be overwritten. Insbesondere im Umfeld stark frequentierter Codepfade, die mehrmals pro Frame oder auch nur einmal pro Frame aufgerufen werden, wie etwa eine UpdateUI()-Methode, sollten Sie vorsichtig sein.One should be especially careful around high-frequency code paths that are called many times per frame or even once per frame such as an UpdateUI() method.

  3. Vermeiden der Übergabe von Strukturen über den WertAvoid passing structs by value

    Im Gegensatz zu Klassen sind Strukturen Werttypen, und bei der direkten Übergabe an eine Funktion werden ihre Inhalte in eine neu erstellte Instanz kopiert.Unlike classes, structs are value-types and when passed directly to a function, their contents are copied into a newly created instance. Diese Kopie bewirkt höhere CPU-Kosten sowie zusätzlichen Speicherbedarf auf dem Stack.This copy adds CPU cost, as well as additional memory on the stack. Für kleine Strukturen ist der Effekt minimal und daher akzeptabel.For small structs, the effect is minimal and thus acceptable. Bei Funktionen, die in jedem Frame wiederholt aufgerufen werden, sowie bei Funktionen, die große Strukturen akzeptieren, ändern Sie nach Möglichkeit die Funktionsdefinition, um durch Verweis zu übergeben.However, for functions repeatedly invoked every frame as well as functions taking large structs, if possible modify the function definition to pass by reference. Weitere Informationen finden Sie hierLearn more here

VerschiedenesMiscellaneous

  1. Physische EffektePhysics

    a) Im Allgemeinen ist die einfachste Möglichkeit, die physischen Effekte zu verbessern, die Menge an Zeit oder die Anzahl der Iterationen pro Sekunde einzuschränken, die zu ihrer Berechnung aufgewendet wird.a) Generally, the easiest way to improve physics is to limit the amount of time spent on Physics or the number of iterations per second. Dadurch wird die Genauigkeit der Simulation reduziert.This will reduce simulation accuracy. Mehr dazu finden Sie unter TimeManager in UnitySee TimeManager in Unity

    b) Die verschiedenen Collidertypen in Unity weisen stark unterschiedliche Leistungsmerkmale auf.b) The types of colliders in Unity have widely different performance characteristics. Der Auftrag unten listet Collider nach ihrer Leistungsfähigkeit auf, von den leistungsfähigsten links bis zu den am wenigsten leistungsfähigen Collidern rechts.The order below lists the most performant colliders to least performant colliders from left to right. Es ist wichtig, Gittermodell-Collider zu meiden, die erheblich teurer sind als die primitiven Collider.It's important to avoid Mesh Colliders, which are substantially more expensive than the primitive colliders.

    Kugel < Kapsel < Kasten <<< Gittermodell (konvex) < Gittermodell (nicht konvex)Sphere < Capsule < Box <<< Mesh (Convex) < Mesh (non-Convex)

    Weitere Informationen finden Sie unter Unity Physics Best Practices (Bewährte Methoden für physische Effekte in Unity).See Unity Physics Best Practices for more info

  2. AnimationenAnimations

    Deaktivieren Sie Leerlaufanimationen, indem Sie die Animatorkomponente deaktivieren (das Deaktivieren des Spielobjekts hat nicht die gleiche Wirkung).Disable idle animations by disabling the Animator component (disabling the game object won't have the same effect). Vermeiden Sie Entwurfsmuster, bei denen ein Animator in einer Schleife sitzt und einen Wert ständig erneut festlegt.Avoid design patterns where an animator sits in a loop setting a value to the same thing. Diese Technik verursacht beträchtlichen Mehraufwand ohne positiven Effekt auf die Anwendung.There's considerable overhead for this technique, with no effect on the application. Weitere Informationen finden Sie hier.Learn more here.

  3. Komplexe AlgorithmenComplex algorithms

    Wenn Ihre Anwendung komplexe Algorithmen verwendet, wie z. B. inverse Kinematik, Pfadsuche usw., suchen Sie nach einem einfacheren Ansatz, oder passen Sie relevante Einstellungen leistungsbezogen an.If your application is using complex algorithms such as inverse kinematics, path finding, etc, look to find a simpler approach or adjust relevant settings for their performance

CPU- im Vergleich mit GPU-LeistungsempfehlungenCPU-to-GPU performance recommendations

Im Allgemeinen lässt sich das Leistungsverhältnis zwischen CPU und GPU auf die Zeichenaufrufe reduzieren, die an die Grafikkarte übermittelt werden.Generally, CPU-to-GPU performance comes down to the draw calls submitted to the graphics card. Um die Leistung zu verbessern, müssen Zeichenaufrufe strategisch a) verringert oder b) neu strukturiert werden, um optimale Ergebnisse zu erzielen.To improve performance, draw calls need to be strategically a) reduced or b) restructured for optimal results. Da Zeichenaufrufe ihrerseits ressourcenintensiv sind, bewirkt ihre Verringerung auch eine Verringerung der insgesamt aufzuwendenden Arbeit.Since draw calls themselves are resource-intensive, reducing them will reduce overall work required. Ferner werden durch Statuswechsel zwischen Zeichenaufrufen aufwändige Schritte zur Validierung und Übersetzung im Grafiktreiber erforderlich, daher kann eine Neustrukturierung der Zeichenaufrufe Ihrer Anwendung mit dem Ziel, die Statuswechsel (d. h.Further, state changes between draw calls require costly validation and translation steps in the graphics driver and thus, restructuring of your application's draw calls to limit state changes (i.e verschiedene Materialien usw.) zu verringern, die Leistung steigern.different materials, etc) can boost performance.

Unity bietet einen hervorragenden Artikel, der einen Überblick hierzu gibt und tief in die Batchverarbeitung von Zeichenaufrufen für die Unity-Plattform einsteigt.Unity has a great article that gives an overview and dives into batching draw calls for their platform.

Single-Pass-InstanzrenderingSingle pass instanced rendering

Single-Pass-Instanzrendering in Unity ermöglicht es, die Zeichenaufrufe für jedes Auge auf einen instanziierten Zeichenaufruf zu reduzieren.Single Pass Instanced Rendering in Unity allows for draw calls for each eye to be reduced down to one instanced draw call. Aufgrund der Cachekohärenz zwischen zwei Zeichenaufrufen kommt es hier auch zu einer gewissen Leistungsverbesserung bei der GPU.Because of cache coherency between two draw calls, there's also some performance improvement on the GPU as well.

Aktivieren dieser Funktion in Ihrem Unity-ProjektTo enable this feature in your Unity Project

  1. Öffnen Sie die Player XR Settings (Player XR-Einstellungen) (navigieren Sie zu Edit > Project Settings > Player > XR Settings („Bearbeiten > Projekteinstellungen > Player > XR-Einstellungen))Open Player XR Settings (go to Edit > Project Settings > Player > XR Settings)
  2. Wählen Sie im Dropdownmenü Stereo Rendering Method (Stereo-Renderingmethode) Single Pass Instanced (Single-Pass-Instanz) aus (das Kontrollkästchen Virtual Reality Supported (Virtuelle Realität unterstützt) muss aktiviert sein)Select Single Pass Instanced from the Stereo Rendering Method drop-down menu (Virtual Reality Supported checkbox must be checked)

Details zu diesem Renderingansatz finden Sie in den folgenden Artikeln von Unity.Read the following articles from Unity for details with this rendering approach.

Hinweis

Ein häufiges Problem beim Single-Pass-Instanzrendering tritt auf, wenn Entwickler bereits vorhandene benutzerdefinierte Shader einsetzen, die noch nicht für die Instanziierung geschrieben wurden.One common issue with Single Pass Instanced Rendering occurs if developers already have existing custom shaders not written for instancing. Nach dem Aktivieren dieses Features stellen die Entwickler möglicherweise fest, dass manche Spielobjekte nur für ein Auge gerendert werden.After enabling this feature, developers may notice some GameObjects only render in one eye. Dies hat den Grund, dass die zugeordneten benutzerdefinierten Shader nicht die geeigneten Eigenschaften für die Instanziierung aufweisen.This is because the associated custom shaders do not have the appropriate properties for instancing.

Informationen zum Beheben dieses Problems finden Sie unter Single Pass Stereo Rendering for HoloLens (Single-Pass-Stereorendering für HoloLens) von UnitySee Single Pass Stereo Rendering for HoloLens from Unity for how to address this problem

Statische BatchverarbeitungStatic batching

Unity kann viele statische Objekte als Batch verarbeiten, um die Zeichenaufrufe an die GPU zu verringern.Unity is able to batch many static objects to reduce draw calls to the GPU. Die statische Batchverarbeitung funktioniert für die meisten Rendererobjekte in Unity, die 1) das Material gemeinsam haben und 2) alle als Static gekennzeichnet sind (Wählen Sie ein Objekt in Unity aus, und aktivieren Sie das Kontrollkästchen in der oberen rechten Ecke des Inspektors).Static Batching works for most Renderer objects in Unity that 1) share the same material and 2) are all marked as Static (Select an object in Unity and select the checkbox in the top right of the inspector). GameObjects, die als Static gekennzeichnet sind, können nicht durch die Runtime Ihrer Anwendung bewegt werden.GameObjects marked as Static cannot be moved throughout your application's runtime. Daher kann es schwierig sein, statische Batchverarbeitung für HoloLens zu nutzen, bei der praktisch jedes Objekt platziert, bewegt, skaliert usw. werden muss. Bei immersiven Headsets kann statische Batchverarbeitung die Anzahl der Zeichenaufrufe drastisch reduzieren und die Leistung so verbessern.Thus, static batching can be difficult to leverage on HoloLens where virtually every object needs to be placed, moved, scaled, etc. For immersive headsets, static batching can dramatically reduce draw calls and thus improve performance.

Weitere Details erfahren Sie unter Static Batching (Statische Batchverarbeitung) unter Draw Call Batching in Unity (Batchverarbeitung von Zeichenaufrufen in Unity).Read Static Batching under Draw Call Batching in Unity for more details.

Dynamische BatchverarbeitungDynamic batching

Da es in der HoloLens-Entwicklung problematisch ist, Objekte als Static zu kennzeichnen, kann dynamische Batchverarbeitung ein hervorragendes Mittel darstellen, das Fehlen dieser Funktion zu kompensieren.Since it's problematic to mark objects as Static for HoloLens development, dynamic batching can be a great tool to compensate for this lacking feature. Es kann auch bei immersiven Headsets nützlich sein.It can also be useful on immersive headsets, as well. Die dynamische Batchverarbeitung in Unity kann aber schwierig zu aktivieren sein, da die GameObjects a) das gleiche Material verwenden und b) eine lange Liste weiterer Kriterien erfüllen müssen.However, dynamic batching in Unity can be difficult to enable because GameObjects must a) share the same Material and b) meet a long list of other criteria.

Die vollständige Liste finden Sie unter Dynamic Batching (Dynamische Batchverarbeitung) unter Draw Call Batching in Unity (Batchverarbeitung von Zeichenaufrufen in Unity).Read Dynamic Batching under Draw Call Batching in Unity for the full list. In den meisten Fällen wird die dynamische Batchverarbeitung von GameObjects ungültig, da die zugeordneten Gittermodelldaten nicht mehr als 300 Scheitelpunkte umfassen dürfen.Most commonly, GameObjects become invalid to be batched dynamically, because the associated mesh data can be no more than 300 vertices.

Andere VerfahrenOther techniques

Batchverarbeitung kann nur erfolgen, wenn mehrere GameObjects gemeinsam dasselbe Material verwenden können.Batching can only occur if multiple GameObjects are able to share the same material. Normalerweise steht dem das Erfordernis gegenüber, dass GameObjects eine eindeutige Textur für ihr jeweiliges Material besitzen müssen.Typically, this will be blocked by the need for GameObjects to have a unique texture for their respective Material. Es ist üblich, Texturen in einer großen Textur zusammenzufassen, eine Methode, die als Texture Atlasing bezeichnet wird.It's common to combine Textures into one big Texture, a method known as Texture Atlasing.

Darüber hinaus ist es vorzuziehen, Gittermodelle zu einem GameObject zu kombinieren, wo es möglich und vernünftig ist.Furthermore, it's preferable to combine meshes into one GameObject where possible and reasonable. Für jeden Renderer in Unity ist eine bestimmte Anzahl Zeichenaufrufe im Vergleich mit dem Übermitteln eines kombinierten Gittermodells unter einem Renderer typisch.Each Renderer in Unity will have its associated draw call(s) versus submitting a combined mesh under one Renderer.

Hinweis

Beim Ändern von Eigenschaften von „Renderer.material“ zur Laufzeit wird eine Kopie des Materials erstellt, was die Batchverarbeitung möglicherweise unmöglich macht.Modifying properties of Renderer.material at runtime will create a copy of the Material and thus potentially break batching. Verwenden Sie Renderer.sharedMaterial, um die mehreren GameObjects gemeinsamen Materialeigenschaften zu ändern.Use Renderer.sharedMaterial to modify shared material properties across GameObjects.

GPU-LeistungsempfehlungenGPU performance recommendations

Weitere Informationen zum Optimieren des Grafikrenderings in UnityLearn more about optimizing graphics rendering in Unity

Optimieren der gemeinsamen Nutzung des TiefenpuffersOptimize depth buffer sharing

Es wird empfohlen, in den Player XR-Einstellungen die Gemeinsame Nutzung des Tiefenpuffers zu aktivieren, um die Hologrammstabilität zu optimieren.It's recommended to enable Depth buffer sharing under Player XR Settings to optimize for hologram stability. Wenn die tiefenbasierte Neuprojektion in der Spätphase mit dieser Einstellung aktiviert wird, wird die Wahl des 16-Bit-Tiefenformats anstelle des 24-Bit-Tiefenformats empfohlen.When enabling depth-based late-stage reprojection with this setting however, it's recommended to select 16-bit depth format instead of 24-bit depth format. Die 16-Bit-Tiefenpuffer reduzieren die Bandbreite (und somit die erforderliche Leistung), die mit dem Tiefenpuffer-Datenverkehr einhergeht, drastisch.The 16-bit depth buffers will drastically reduce the bandwidth (and thus power) associated with depth buffer traffic. Dies kann sowohl für den Stromverbrauch als auch für die Leistungsverbesserung ein großer Gewinn sein.This can be a big win both in power reduction and performance improvement. Allerdings gibt es zwei mögliche negative Ergebnisse durch Einsatz des 16-Bit-Tiefenformats.However, there are two possible negative outcomes by using 16-bit depth format.

Z-FightingZ-Fighting

Die verringerte Genauigkeit des Tiefenbereichs erhöht die Wahrscheinlichkeit von Z-Fighting bei 16-Bit im Vergleich mit 24-Bit.The reduced depth range fidelity makes z-fighting more likely to occur with 16 bit than 24-bit. Um diese Artefakte zu vermeiden, ändern Sie die Clippingebenen der Unity-Kamera für nah und fern, um der geringeren Genauigkeit Rechnung zu tragen.To avoid these artifacts, modify the near/far clip planes of the Unity camera to account for the lower precision. In HoloLens-basierten Anwendungen kann eine Clippingebene von 50 m anstelle des Unity-Standardwerts von 1000 m im Allgemeinen jegliches Z-Fighting beseitigen.For HoloLens-based applications, a far clip plane of 50 m instead of the Unity default 1000 m can generally eliminate any z-fighting.

Deaktivierter SchablonenpufferDisabled Stencil Buffer

Wenn Unity eine Rendertextur mit 16-Bit Tiefe erstellt, wird kein Schablonenpuffer erstellt.When Unity creates a Render Texture with 16-bit depth, there's no stencil buffer created. Beim Auswählen eines Formats mit 24-Bit Tiefe wird gemäß der Unity-Dokumentation ein 24-Bit-Z-Puffer erstellt sowie ein [8-Bit-Schablonenpuffer] (https://docs.unity3d.com/Manual/SL-Stencil.html) (wenn 32-Bit auf einem Gerät möglich sind, was aber allgemein der Fall ist, etwa bei HoloLens).Selecting 24-bit depth format, per Unity documentation, will create a 24-bit z-buffer, as well as an [8-bit stencil buffer] (https://docs.unity3d.com/Manual/SL-Stencil.html) (if 32-bit is applicable on a device, which is generally the case such as HoloLens).

Vermeiden von VollbildeffektenAvoid full-screen effects

Techniken, die im Vollbildmodus arbeiten, können teuer sein, da sie die Größenordnung von Millionen von Vorgängen pro Frame erreichen.Techniques that operate on the full screen can be expensive since their order of magnitude is millions of operations every frame. Es wird empfohlen, Effekte der Nachbearbeitung wie Antialiasing, Blooming und mehr zu vermeiden.It's recommended to avoid post-processing effects such as anti-aliasing, bloom, and more.

Optimale BeleuchtungseinstellungenOptimal lighting settings

Die globale Beleuchtung in Echtzeit in Unity kann herausragende visuelle Ergebnisse produzieren, bringt jedoch umfangreiche Beleuchtungsberechnungen mit sich.Real-time Global Illumination in Unity can provide outstanding visual results but involves expensive lighting calculations. Wir empfehlen, die globale Beleuchtung in Echtzeit für jede Unity-Szenendatei mit dieser Einstellung zu deaktivieren: Window > Rendering > Lighting Settings > Uncheck Real-time Global Illumination (Fenster > Rendering > Beleuchtungseinstellungen > Globale Beleuchtung in Echtzeit deaktivieren).We recommended disabling real-time Global Illumination for every Unity scene file via Window > Rendering > Lighting Settings > Uncheck Real-time Global Illumination.

Ferner wird empfohlen, jede Art von Schattenwurf zu deaktivieren, da dieser ebenfalls teure GPU-Durchgänge für eine Unity-Szene mit sich bringt.Furthermore, it's recommended to disable all shadow casting as these also add expensive GPU passes onto a Unity scene. Schatten können durch Licht deaktiviert werden, lassen sich über die Qualitätseinstellungen aber auch im Ganzen steuern.Shadows can be disable per light but can also be controlled holistically via Quality settings.

Edit > Project Settings (Bearbeiten > Projekteinstellungen), wählen Sie dann die Kategorie Quality (Qualität) aus > wählen Sie Low Quality (Niedrige Qualität) für die UWP-Plattform.Edit > Project Settings, then select the Quality category > Select Low Quality for the UWP Platform. Sie können auch einfach die Shadows-Eigenschaft (Schatten) auf Disable Shadows (Schatten deaktivieren) festlegen.One can also just set the Shadows property to Disable Shadows.

Wir empfehlen, für Ihre Modelle in Unity „Baked Lighting“ (vorab gerenderte Lichtdetails) zu verwenden.We recommended that you use baked lighting with your models in Unity.

Reduzieren der PolygonanzahlReduce poly count

Das Reduzieren der Polygonanzahl wird durch eins dieser Verfahren erreichtPolygon count is reduced by either

  1. Entfernen von Objekten aus einer SzeneRemoving objects from a scene
  2. Starke Herabsetzung der Medienobjekte, wodurch sich die Anzahl der Polygone für ein bestimmtes Gittermodell reduziertAsset decimation, which reduces the number of polygons for a given mesh
  3. Implementieren eines Level of Detail (LOD) System (Detailstufensystems) in Ihrer Anwendung, bei der weit entfernte Objekte mit einer aus weniger Polygonen bestehenden Version der gleichen Geometrie gerendert werdenImplementing a Level of Detail (LOD) System into your application, which renders far away objects with lower-polygon version of the same geometry

Grundlegendes zu Shadern in UnityUnderstanding shaders in Unity

Eine einfache Annäherung für den Leistungsvergleich von Shadern besteht darin, die durchschnittliche Anzahl der Vorgänge zu bestimmen, die jeder zur Laufzeit ausführt.An easy approximation to compare shaders in performance is to identify the average number of operations each executes at runtime. Dies kann in Unity sehr einfach erfolgen.This can be done easily in Unity.

  1. Wählen Sie Ihr Shadermedienobjekt oder ein Material aus, und wählen Sie dann in der oberen rechten Ecke des Inspektorfensters das Zahnradsymbol aus, gefolgt von „Select Shader“ (Shader auswählen)Select your shader asset or select a material, then in the top-right corner of the inspector window, select the gear icon followed by "Select Shader"

    Auswählen eines Shaders in Unity

  2. Wählen Sie bei ausgewähltem Shadermedienobjekt die Schaltfläche „Compile and show code“ (Compilieren und Code anzeigen) unter dem Inspektorfenster ausWith the shader asset selected, select the "Compile and show code" button under the inspector window

    Kompilieren von Shadercode in Unity

  3. Suchen Sie nach dem Compilieren nach dem Statistikabschnitt in den Ergebnissen mit der Anzahl der verschiedenen Vorgänge sowohl für den Vertex- als auch für den Pixelshader (Hinweis: Pixelshader werden auch häufig als Fragmentshader bezeichnet)After compiling, look for the statistics section in the results with the number of different operations for both the vertex and pixel shader (Note: pixel shaders are often also called fragment shaders)

    Standardshadervorgänge in Unity

Optimieren von PixelshadernOptimize pixel shaders

Beim Blick auf die compilierten Statistikergebnisse unter Verwendung der Methode oben zeigt sich, dass der Fragmentshader im Mittel mehr Vorgänge als der Vertexshader ausführt.Looking at the compiled statistic results using the method above, the fragment shader will generally execute more operations than the vertex shader, on average. Der Fragmentshader, auch als Pixelshader bezeichnet, wird pro Pixel der Bildschirmausgabe ausgeführt, während der Vertexshader nur pro Scheitelpunkt aller Gittermodelle ausgeführt wird, die auf dem Bildschirm gezeichnet werden.The fragment shader, also known as the pixel shader, is executed per pixel on the screen output while the vertex shader is only executed per-vertex of all meshes being drawn to the screen.

Daher weisen Fragmentshader aufgrund der vielen Beleuchtungsberechnungen nicht nur mehr Anweisungen auf, sie werden auch fast immer auf einem größeren Dataset ausgeführt.Thus, not only do fragment shaders have more instructions than vertex shaders because of all the lighting calculations, fragment shaders are almost always executed on a larger dataset. Wenn die Bildschirmausgabe beispielsweise ein Bild mit 2.000 mal 2.000 Pixeln ist, kann der Fragmentshader 2.000*2.000 = 4.000.000 Mal ausgeführt werden.For example, if the screen output is a 2k by 2k image, then the fragment shader can get executed 2,000*2,000 = 4,000,000 times. Wenn zwei Augen gerendert werden, verdoppelt sich diese Zahl, da zwei Bildschirme vorhanden sind.If rendering two eyes, this number doubles since there are two screens. Wenn eine Mixed Reality-Anwendung mehrere Durchgänge, Nachbearbeitungseffekte im Vollbildmodus und/oder Rendering mehrerer Gittermodelle für das gleiche Pixel aufweist, erhöht sich diese Zahl dramatisch.If a mixed reality application has multiple passes, full-screen post-processing effects, or rendering multiple meshes to the same pixel, this number will increase dramatically.

Daher können mit dem Verringern der Zahl der Vorgänge im Fragmentshader im Allgemeinen viel größere Leistungssteigerungen als durch Optimierungen im Vertexshader erreicht werden.Therefore, reducing the number of operations in the fragment shader can generally give far greater performance gains over optimizations in the vertex shader.

Alternativen zu den Unity-StandardshadernUnity Standard shader alternatives

Anstatt ein physikalisch basiertes Rendering (PBR) oder einen anderen hochwertigen Shader zu verwenden, sollten Sie einen leistungsfähigeren und kostengünstigeren Shader nutzen.Instead of using a physically based rendering (PBR) or another high-quality shader, look at utilizing a more performant and cheaper shader. Im Mixed Reality-Toolkit steht der MRTK-Standardshader bereit, der für Mixed Reality-Projekte optimiert wurde.The Mixed Reality Toolkit provides the MRTK standard shader that has been optimized for mixed reality projects.

Unity bietet darüber hinaus unlit (nicht beleuchtet), vertex lit (nach Scheitelpunkten beleuchtet), diffuse (diffus), und weitere vereinfachte Shaderoptionen, die im Vergleich schneller arbeiten als der Unity-Standardshader.Unity also provides an unlit, vertex lit, diffuse, and other simplified shader options that are faster compared to the Unity Standard shader. Detailliertere Informationen finden Sie unter Usage and Performance of Built-in Shaders (Verwendung und Leistung der integrierten Shader).See Usage and Performance of Built-in Shaders for more detailed information.

Vorabladen der ShaderShader preloading

Verwenden Sie Vorabladen der Shader und andere Tricks, um die Shaderladezeiten zu optimieren.Use Shader preloading and other tricks to optimize shader load time. Insbesondere bedeutet Vorabladen der Shader, dass kein Hängen aufgrund von Shadercompilierung zur Laufzeit sichtbar wird.In particular, shader preloading means you won't see any hitches due to runtime shader compilation.

Einschränken des ÜberzeichnensLimit overdraw

In Unity kann Überzeichnung für eine Szene angezeigt werden, indem ein Wert im Zeichenmodusmenü in der oberen linken Ecke der Szenenansicht auf Overdraw (Überzeichnung) umgeschaltet wird.In Unity, one can display overdraw for their scene, by toggling the draw mode menu in the top-left corner of the Scene view and selecting Overdraw.

Im Allgemeinen kann Überzeichnung durch rechtzeitiges Culling (Entfernen der Rückseiten) von Objekten abgemildert werden, bevor sie an die GPU gesendet werden.Generally, overdraw can be mitigated by culling objects ahead of time before they're sent to the GPU. Unity bietet ausführliche Informationen zum Implementieren von Occlusion Culling (Verdeckungs-Culling) für ihre Engine.Unity provides details on implementing Occlusion Culling for their engine.

Empfehlungen zum ArbeitsspeicherMemory recommendations

Exzessive Zuweisungsvorgänge von Arbeitsspeicher und deren Aufhebung können in Ihrer Holografieanwendung negative Effekte zeigen, die zu inkonsistenter Leistung, eingefrorenen Frames und anderem abträglichem Verhalten führen.Excessive memory allocation & deallocation operations can have adverse effects on your holographic application, resulting in inconsistent performance, frozen frames, and other detrimental behavior. Das Verstehen der Arbeitsspeicheraspekte ist beim Entwickeln in Unity besonders wichtig, da die Arbeitsspeicherverwaltung vom Garbage Collector gesteuert wird.It's especially important to understand memory considerations when developing in Unity since memory management is controlled by the garbage collector.

Garbage CollectionGarbage collection

Holografie-Apps verlieren Prozessorzeit an den Garbage Collector (GC), wenn der GC aktiviert wird, um Objekte zu analysieren, die sich während der Ausführung nicht mehr im Bereich befinden und deren Arbeitsspeicher freigegeben werden muss, damit er für die Wiederverwendung zur Verfügung steht.Holographic apps will lose processing compute time to the garbage collector (GC) when the GC is activated to analyze objects that are no longer in scope during execution and their memory needs to be released, so it can be made available for reuse. Ständiges Zuweisen und Freigeben macht häufigere Läufe des Garbage Collectors erforderlich, was Leistung und Benutzererfahrung beeinträchtigt.Constant allocations and de-allocations will generally require the garbage collector to run more frequently, thus hurting performance and user experience.

Unity hat eine hervorragende Seite zur Verfügung gestellt, auf der die Arbeitsweise des Garbage Collectors detailliert beschrieben ist und Tipps zum Schreiben von – im Hinblick auf die Speicherverwaltung – effizienterem Code gegeben werden.Unity has provided an excellent page that explains in detail how the garbage collector works and tips to write more efficient code in regards to memory management.

Eine der gängigsten Methoden, die zu einer übermäßigen Garbage Collection führt, besteht darin, in der Unity-Entwicklung keine Verweise auf Komponenten und Klassen zwischenzuspeichern.One of the most common practices that leads to excessive garbage collection isn't caching references to components and classes in Unity development. Alle Verweise sollten während Start() oder Awake() erfasst und in späteren Funktionen wie Update() oder LateUpdate() wiederverwendet werden.Any references should be captured during Start() or Awake() and reused in later functions such as Update() or LateUpdate().

Weitere schnelle Tipps:Other quick tips:

  • Verwenden Sie die StringBuilder-Klasse von C#, um dynamisch zur Laufzeit komplexe Zeichenfolgen zu generierenUse the StringBuilder C# class to dynamically build complex strings at runtime
  • Entfernen Sie Aufrufe von Debug.Log(), wenn sie nicht mehr erforderlich sind, da sie in allen Buildversionen einer App trotzdem noch ausgeführt werdenRemove calls to Debug.Log() when no longer needed, as they still execute in all build versions of an app
  • Wenn Ihre Holografie-App allgemein viel Arbeitsspeicher erfordert, erwägen Sie das Aufrufen von System.GC.Collect() in Ladephasen etwa beim Anzeigen eines Lade- oder ÜbergangsbildschirmsIf your holographic app generally requires lots of memory, consider calling System.GC.Collect() during loading phases such as when presenting a loading or transition screen

ObjektpoolingObject pooling

Objektpooling ist eine gängige Methode, um die Kosten für fortlaufende Objektzuordnungen und deren Aufhebung zu reduzieren.Object pooling is a popular technique for reducing the cost of continuous object allocation and deallocations. Dies erfolgt durch Zuordnen eines großen Pools identischer Objekte und Wiederverwendung inaktiver, verfügbarer Instanzen aus diesem Pool, statt im Lauf der Zeit ständig neue Objekte zu erstellen und zu entfernen.This is done by allocating a large pool of identical objects and reusing inactive, available instances from this pool instead of constantly spawning and destroying objects over time. Objektpools eignen sich hervorragend für wiederverwendbare Komponenten, die im Rahmen einer App eine variable Lebensdauer haben.Object pools are great for reuseable components that have variable lifetime during an app.

StartleistungStartup performance

Erwägen Sie, Ihre App mit einer kleineren Szene zu starten und dann SceneManager.LoadSceneAsync zu verwenden, um den Rest der Szene zu laden.Consider starting your app with a smaller scene, then using SceneManager.LoadSceneAsync to load the rest of the scene. Dadurch kann Ihre App so schnell wie möglich in einen interaktiven Zustand gelangen.This allows your app to get to an interactive state as fast as possible. Beim Aktivieren der neuen Szene kann es zu einer großen CPU-Spitze kommen, und alle gerenderten Inhalte werden möglicherweise stockend oder hängend ausgeführt.There may be a large CPU spike while the new scene is being activated and that any rendered content might stutter or hitch. Eine Möglichkeit, dies zu umgehen, besteht darin, die AsyncOperation.allowSceneActivation-Eigenschaft für die zu ladende Szene auf „false“ festzulegen, das Laden der Szene abzuwarten, den Bildschirm auf schwarz zu setzen und den Wert der Eigenschaft dann wieder auf „true“ festzulegen, um die Szenenaktivierung abzuschließen.One way to work around this is to set the AsyncOperation.allowSceneActivation property to "false" on the scene being loaded, wait for the scene to load, clear the screen too black, and then set it back to "true" to complete the scene activation.

Beachten Sie, dass während des Ladens der Startszene für den Benutzer der holografische Begrüßungsbildschirm angezeigt wird.Remember that while the startup scene is loading, the holographic splash screen will be displayed to the user.

Siehe auchSee also