Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Optimieren der Navigations-Performance

../../_images/nav_optimization.webp

Häufige Performance-Probleme im Zusammenhang mit der Navigation lassen sich in die folgenden Kategorien einteilen:

  • Performance-Probleme bei der Analyse von Nodes des Szenenbaums für das Backen von Navigations-Meshes.

  • Performance-Probleme beim Backen des eigentlichen Navigations-Meshs.

  • Performance-Probleme mit NavigationAgent-Pfadabfragen.

  • Performance-Probleme bei der eigentlichen Pfadsuche.

  • Performance-Probleme bei der Synchronisierung der Navigations-Map.

In den folgenden Abschnitten finden Sie Informationen darüber, wie Sie deren Auswirkungen auf die Framerate erkennen und beheben oder zumindest abmildern können.

Performance-Probleme beim Parsen von Nodes in Szenenbäumen

Tipp

Verwenden Sie vorzugsweise einfache Formen mit möglichst wenigen Kanten, z. B. keine runden Formen wie Kreise, Kugeln oder Torus.

Bevorzugen Sie physikalische Collision Shapes gegenüber komplexen visuellen Meshes als Ausgangsgeometrie, da Meshes von der GPU kopiert werden müssen und in der Regel viel detaillierter sind als nötig.

Vermeiden Sie im Allgemeinen die Verwendung sehr komplexer Geometrie als Ausgangsgeometrie für das Backen von Navigationsmeshes. Verwenden Sie z.B. niemals ein sehr detailliertes visuelles Mesh, da das Parsen seiner Form in Datenarrays und die Voxelisierung für das Backen des Navigationsmeshs viel Zeit in Anspruch nehmen wird, ohne dass das endgültige Navigationsmesh dadurch an Qualität gewinnt. Verwenden Sie stattdessen eine sehr detailarme Version einer Geometrie. Noch besser ist es, sehr primitive Geometrien wie Kästchen und Rechtecke zu verwenden, die nur grob die gleiche Geometrie abdecken, aber dennoch ein Ergebnis liefern, das gut genug für die Wegfindung ist.

Bevorzugen Sie einfache Physik-Collision Shapes gegenüber visuellen Meshes als Ausgangsgeometrie für das Backen von Navigationsmeshes. Physik-Shapes sind standardmäßig sehr begrenzte und optimierte Geometrien, die einfach und schnell zu analysieren sind. Ein visuelles Mesh hingegen kann von einfach bis komplex reichen. Um Zugriff auf visuelle Mesh-Daten zu erhalten, muss der Parser die Mesh-Daten-Arrays vom RenderingServer anfordern, da visuelle Mesh-Daten direkt auf der GPU gespeichert werden und nicht auf der CPU zwischengespeichert sind. Dies erfordert das Sperren des RenderingServer-Threads und kann die Framerate zur Laufzeit stark beeinträchtigen, wenn das Rendering in mehreren Threads ausgeführt wird. Wenn das Rendering als Single-Thread läuft, kann die Auswirkung auf die Framerate noch schlimmer sein und das Mesh-Parsing kann bei komplexen Meshes das gesamte Spiel für ein paar Sekunden einfrieren.

Performance-Probleme beim Backen von Navigations-Meshes

Tipp

Zur Laufzeit sollte immer ein Hintergrund-Thread für das Backen von Navigations-Meshes verwendet werden.

NavigationMesh cell_size und cell_height erhöhen, um weniger Voxel zu erzeugen.

Ändern Sie den SamplePartitionType von Watershed auf Monotone oder Layers, um die Performance beim Backen zu erhöhen.

Warnung

Skalieren Sie Quellgeometrie NIEMALS mit Nodes, um Präzisionsfehler zu vermeiden. Die meisten Skalierungen gelten nur visuell und Geometrien, die in ihrem Grundmaßstab sehr groß sind, erfordern auch bei einer Verkleinerung noch eine Menge zusätzlicher Bearbeitung.

Das Backen von Navigations-Meshes zur Laufzeit sollte nach Möglichkeit immer in einem Hintergrund-Thread erfolgen. Selbst kleine Meshes können weitaus mehr Zeit in Anspruch nehmen, als man in ein einzelnes Frame quetschen kann, zumindest wenn die Framerate auf einem erträglichen Niveau bleiben soll.

Die Komplexität der Quellgeometriedaten, die aus den Nodes des Szenenbaums geparst werden, hat große Auswirkungen auf die Performance beim Backen, da alles auf ein Raster / Voxel abgebildet werden muss. Für die Performance des Backens zur Laufzeit sollten die Zellengröße und -höhe des NavigationMeshs so hoch wie möglich eingestellt werden, ohne dass die Qualität des Meshs für ein Spiel beeinträchtigt wird. Wenn die Zellgröße oder Zellhöhe zu niedrig eingestellt ist, ist das Backen gezwungen, eine übermäßige Anzahl von Voxeln zu erzeugen, um die Quellgeometrie zu verarbeiten. Wenn sich die Quellgeometrie über eine sehr große Spielwelt erstreckt, ist es sogar möglich, dass dem Back-Prozess in der Mitte der Speicher ausgeht und das Spiel abstürzt. Der Partitionstyp kann auch herabgesetzt werden, je nachdem wie komplex die Ausgangsgeometrie des Spiels ist, um etwas Performance zu gewinnen. Spiele mit überwiegend flachen Oberflächen und blockartiger Geometrie können z.B. mit dem Monotone- oder Layer-Modus auskommen, die viel schneller zu backen sind (z.B. weil sie keinen Distance Field-Durchlauf benötigen).

Skalieren Sie niemals die Quellgeometrie mit Nodes. Dies kann nicht nur zu vielen Präzisionsfehlern mit falsch angepassten Vertices und Kanten führen, sondern auch dazu, dass manche Skalierungen nur visuell und nicht in den tatsächlich geparsten Daten vorhanden sind. Wenn z.B. ein Mesh im Editor visuell herunterskaliert wird, z.B. die Skalierung auf 0.001 bei einer MeshInstance, benötigt das Mesh immer noch ein gigantisches und sehr komplexes Voxel-Gitter, um für das Baking verarbeitet zu werden.

Performance-Probleme mit NavigationAgent-Pfadabfragen

Tipp

Vermeiden Sie unnötige Pfadrücksetzungen und Abfragen bei jedem Frame in NavigationAgent-Skripten.

Vermeiden Sie es, alle NavigationAgent-Pfade im selben Frame zu aktualisieren.

Logische Fehler und verschwenderische Operationen in den benutzerdefinierten NavigationAgent-Skripten sind sehr häufige Ursachen für Performance-Probleme, z.B. das Zurücksetzen des Pfades in jedem einzelnen Frame. Standardmäßig sind NavigationAgents so optimiert, dass sie nur dann neue Pfade abfragen, wenn sich die Zielposition ändert, die Navigations-Map sich ändert oder sie zu weit von der gewünschten Pfaddistanz entfernt sind.

Wenn sich z.B. die KI auf den Spieler zubewegen soll, sollte die Zielposition nicht in jedem einzelnen Frame auf die Spielerposition gesetzt werden, da dies in jedem Frame einen neuen Pfad abfragt. Stattdessen sollte die Distanz zwischen der aktuellen Zielposition und der Spielerposition verglichen werden, und nur wenn sich der Spieler zu weit entfernt hat, sollte eine neue Zielposition festgelegt werden.

Prüfen Sie nicht in jedem Frame, ob eine Zielposition erreichbar ist. Was wie eine harmlose Prüfung aussieht, ist das Äquivalent einer teuren Pfadabfrage hinter den Kulissen. Wenn der Plan ist, einen neuen Pfad anzufordern, falls die Position erreichbar ist, sollte ein Pfad direkt abgefragt werden. Die Frage "Ist diese Position erreichbar?" wird beantwortet, indem man die letzte Position des zurückgegebenen Pfades betrachtet und prüft, ob diese Position in einer "erreichbaren" Entfernung zur geprüften Position liegt. Dadurch wird vermieden, dass für jedes Frame zwei vollständige Pfadabfragen für denselben NavigationAgent durchgeführt werden.

Teilen Sie die Gesamtzahl der NavigationAgents in Update-Gruppen ein oder verwenden Sie zufällige Timer, damit sie nicht alle im selben Frame neue Pfade anfordern.

Performance-Probleme bei der Synchronisierung von Navigations-Maps

Tipp

Fügen Sie die Polygone von Navigations-Meshes per Vertex statt per Kantenverbindung zusammen, wo immer dies möglich ist.

Wenn Änderungen z.B. an Navigations-Meshes oder Navigationsregionen vorgenommen werden, muss der NavigationServer die Navigation-Map synchronisieren. Je nach Komplexität der Meshes kann dies sehr viel Zeit in Anspruch nehmen, was sich auf die Framerate auswirken kann.

Der NavigationServer vereinigt Navigations-Meshes entweder per Vertex oder per Kantenverbindung. Die Vereinigung per Vertex erfolgt, wenn die beiden Vertices zweier unterschiedlicher Kanten in denselben Map-Rasterzellen landen. Dies ist ein relativ schneller und kostengünstiger Vorgang. Die Vereinigung per Kantenverbindung erfolgt in einem zweiten Durchgang für alle noch nicht vereinigten Kanten. Dabei werden alle freien Kanten auf mögliche Kantenverbindungen anhand von Abstand und Winkel geprüft, was recht aufwändig ist.

Abgesehen von der allgemeinen Regel, so wenig Polygonkanten wie möglich zu haben, sollten also so viele Kanten wie möglich im Vorfeld per Vertex vereinigt werden, damit nur wenige Kanten für die aufwendigere Berechnung der Kantenverbindung übrig bleiben. Die Debug-Navigation PerformanceMonitor kann verwendet werden, um Statistiken darüber zu erhalten, wie viele Polygone und Kanten verfügbar sind und wie viele davon gar nicht vereinigt oder nicht per Vertex vereinigt sind. Wenn das Verhältnis zwischen per Vertex und per Kantenverbindung vereinigten Vertices überhaupt nicht passt (Vertex-Vereinigungen sollte deutlich häufiger vorkommen), werden die Navigations-Meshes nicht richtig erstellt oder sehr ineffizient platziert.