Wie kann ich die Leistungseinbußen beim Rendern von Bäumen verringern?


24

Ich mache eine Art Low-Poly-Spiel. Ich habe ein Gelände mit etwas Wasser und ich möchte viele, viele Bäume. Ich habe im Moment 10.000 Baummassen platziert. Jeder Baum besteht aus nicht mehr als 200 Dreiecken, daher sind sie nicht zu anstrengend.

Das Hauptproblem ist, dass es Seen gibt und die Seen ziemlich groß sind. Auf der anderen Seite des Sees sieht man eigentlich keine Bäume, und das sieht wirklich schlimm aus, besonders wenn man dorthin läuft und plötzlich Bäume auftauchen.

Um dies zu beheben, muss ich die Baumentfernung erhöhen, damit auf der anderen Seite des Sees eine anständige Anzahl von Bäumen zu sehen ist. Dadurch wird die Leistung jedoch auf 40-50 fps reduziert, und es ist noch kaum etwas anderes im Spiel. Ich benutze eine GTX 1080, wenn das hilft.

Was kann ich tun, um mein Spiel mit mehr Bäumen schneller zu machen?


IIRC, Silent Hill, verwendete Nebel, um den Cutoff an der entfernten Clipping-Ebene zu verbergen, wodurch sie anfingen konnten, Dinge dynamisch zu laden, gleich dahinter, wo der Nebel aufhört. Sie könnten von einer Veränderung der Spielatmosphäre profitieren.
Cody

Die Bäume ziehen Sie an, um aus dem Fenster zu schauen, was Ihre Leistung senkt.
mbomb007

Haben Sie versucht, den Profiler auszuführen? Wenn ja, wo ist der Engpass?
Mikael Högström

Machst du irgendeine Art von Frustum Culling?
Krythic

Was ist Kegelstumpf-Keulen?
Mr-Matt

Antworten:


43

Sie können verschiedene Maßnahmen ergreifen, um die Zeichenleistung zu verbessern.

  1. Sie sagten, sie wären ziemlich weit weg. Sie können LOD verwenden , um die Anzahl der Scheitelpunkte dieser Bäume und damit die Zeit zu verringern, die erforderlich ist, um alle gezeichneten Scheitelpunkte zu durchlaufen. Auch wenn dies höchstwahrscheinlich nicht das Problem ist (GTX1080 mit nur 10.000 Bäumen mit jeweils 200 Tris, winzige Zahlen für die GPU), habe ich es dennoch aufgenommen. Billboarding ist ein effektives Werkzeug für die niedrigste LOD-Ebene, da es sich im Wesentlichen um eine flache Ebene handelt, die immer der Kamera zugewandt ist und ein gerendertes Bild des Baums enthält. Es verliert an Tiefe, weshalb es für die niedrigste Stufe gut ist, da der Spieler den Unterschied höchstwahrscheinlich nicht bemerkt.

  2. Haben Sie die Stapelverarbeitung aktiviert ? Dynamisches Batching wird normalerweise automatisch durchgeführt, wenn die Anzahl der Scheitelpunkte der Netze relativ niedrig ist. Statisches Batching kann auch versucht werden, indem die Bäume statisch gemacht werden, indem das Kontrollkästchen im Unity-Editor auf dem übergeordneten Spielobjekt aktiviert wird. Dies funktioniert nicht gut mit animierten Objekten. Sie benötigen für die Objekte freigegebenes Material, damit dies funktioniert.

  3. Mit benutzerdefinierten Stapeln können Sie das Rendern steuern, indem Sie die Blöcke selbst generieren, anstatt Unity damit umgehen zu lassen. Außerdem können Sie auch größere Maschen stapeln. Dies geschieht einfach mit Mesh.CombineMeshes . Dies funktioniert auch nicht gut mit animierten Objekten. Sie benötigen für die Objekte freigegebenes Material, damit dies funktioniert. Wahrscheinlich möchten Sie Ihre Welt in einige Teile aufteilen und daraus Stapel erstellen. Wie diese Blöcke erzeugt werden sollen, hängt davon ab, wie sich Ihre Kamera in der Welt bewegt.

  4. Aktivieren Instancing auf den Shadern. Durch das Instanzieren kann die Engine mehrere Objekte (mit demselben Netz) mit nur einem Zeichnungsaufruf zeichnen. Damit dies funktioniert, müssen die Objekte über ein gemeinsames Netz und einen gemeinsamen Shader verfügen. Das Material kann variieren, aber der Shader muss alle unterschiedlichen variierenden Eigenschaften unterstützen.

    Damit die Engine instanziierte Rendering-Batches besser erstellt, möchten Sie wahrscheinlich dieselben Meshes in einer Szene gruppieren. Auch das Spielen mit der Material-Render-Warteschlange liefert gute Ergebnisse, wenn ein Mesh immer dasselbe Material enthält. Während der Entwicklung des Handyspiels, an dem ich gerade arbeite, habe ich das genutzt, um Drawcalls in meiner Testszene um mehr als die Hälfte zu reduzieren. Stellen Sie auch seit Unity 5.6 sicher, dass Sie das Enable InstancingKontrollkästchen im Material aktivieren.

  5. Halten Sie Ihre Drawcalls und SetPass-Anrufe im Allgemeinen niedrig. Dies sind die rohen Anforderungen an Ihre GPU, um Inhalte zu zeichnen, und sie haben einen großen Overhead. Das Reduzieren von Drawcalls (was durch Batching und Instancing erreicht wird) erhöht die Gesamtleistung Ihrer CPU, da weniger Wartezeiten erforderlich sind. SetPass-Aufrufe sind Änderungen an Ihren aktuellen Shadern. Wenn Sie also viele verschiedene Materialien haben, werden Sie mehrere SetPass-Aufrufe haben, die auch dazu führen, dass die CPU ein wenig wartet.

  6. Wenn Ihre Szene sehr umfangreich ist und Ihre CPU-Zeit für das Durchlaufen aller Objekte in der Szene aufgewendet wird, versuchen Sie, die Objekte in der Szene zu verkleinern. Gruppieren Sie einige Bäume, anstatt sie einzeln zu platzieren, und stellen Sie sie als einzelnes Objekt zur Verfügung. Stellen Sie außerdem sicher, dass Sie die Bäume oder die übergeordneten Objekte nicht verschieben, da Unity dadurch zwischengespeicherte Transformationen verwerfen und den gesamten Szenenbaum neu berechnen kann.

  7. Wenn Ihre Szene riesig ist und Ihre CPU-Zeit immer noch hauptsächlich für Unity aufgewendet wird, das durch den Szenenbaum geht, um Listen zum Rendern aller Objekte zu erstellen, können Sie Unity das Rendern nicht erlauben. Wenn Sie zeichnbare Objekte besser verfolgen können, können Sie sie mit CommandBuffer.DrawMeshInstanced oder Graphics.DrawMeshInstanced von Hand zeichnen. Ich werde nicht näher darauf eingehen, da es viel fortgeschrittener ist und das Ausmerzen von Obects selbst und so weiter beinhaltet.

Wenn die statische oder dynamische Stapelverarbeitung nicht ordnungsgemäß funktioniert (was Sie anhand des Frame-Debuggers feststellen können), müssen Sie sicherstellen, dass Sie tatsächlich freigegebenes Material verwenden und keine versehentlichen Kopien des Materials mit dem Aufruf anfertigen meshRenderer.material. Durch Aufrufen von .materialwerden Kopien Ihrer Materialien erstellt und die Stapelverarbeitung unterbrochen. Verwenden Sie .sharedMaterialstattdessen.

Seit Unity 5.6 können Sie mit dem Frame-Debugger feststellen, warum bestimmte Drawcalls nicht mit den vorherigen Drawcalls abgeglichen wurden. Dies ist sehr hilfreich, wenn Sie versuchen, die Drawcalls Ihres Spiels zu reduzieren.

Die Instanziierung bietet gegenüber der statischen / dynamischen / benutzerdefinierten Stapelverarbeitung die folgenden Vorteile:

  • Verbraucht weniger Speicher, da das Netz nicht im Speicher dupliziert werden muss
  • Kann mehrere Materialien verwenden, es ist nur ein gemeinsamer Shader erforderlich
  • Objekte können animiert werden

Auch als Nachteil ist es ein ziemlich neues Feature in Unity und könnte ein bisschen instabil sein. Auch ältere GPUs oder GPUs für mobile Geräte unterstützen nicht unbedingt die Instanziierung.


1. Ja, ich habe LODs ausprobiert, und zu meiner Überraschung hat es das Ganze noch schlimmer gemacht. Ich hatte 3 Variationen der Bäume mit jeweils einer geringfügig niedrigeren Scheitelpunktzahl und eine flache Ebene mit einem gerenderten Bild des Baums darauf.
Mr-Matt

2. Alle meine Bäume sind als statisch markiert. Soweit ich weiß, ermöglicht das das Batching? Ist das korrekt? Und wenn Sie von geteiltem Material sprechen, meinen Sie damit einfach, dass die Bäume dasselbe Material haben?
Mr-Matt

3. Was für eine Leistungsverbesserung würde dies tatsächlich bewirken? Lohnt es sich, es zu versuchen?
Mr-Matt

1
2/3: Nach meiner Erfahrung leistet Unity beim dynamischen Batching keine sehr gute Arbeit, und statisches Batching vergrößert die Build-Größe. Ich habe das Batching selbst implementiert und das Mesh mit der Ladezeit kombiniert. Mit dieser Technik gelang es mir, 2500 Drawcalls zu erstellen, um sie zu ungefähr 300 Drawcalls zu komprimieren. Dies war entscheidend für unser Handyspiel, bei dem Drawcalls wichtig sind. Es hat ein wenig unnötige Eckpunkte zum Berechnen gebracht (außerhalb des Bildschirms), aber es hat sich gelohnt.
Lasse

2
tfw, wenn Sie eine Frage über schlechte Leistung mit Bäumen und nicht ein einziges Wort über Billboarding lesen, ist verloren
Num Lock

13

Ok, das Problem war einfach, dass ich keinen vorberechneten Echtzeit-GI verwendet habe. Ich überprüfe das vor einiger Zeit, aber es wirkte sich nicht sofort aus, also habe ich es verlassen und vergessen, und die Bearbeitungszeit für die Beleuchtung war auch so lang. Es ist jedoch gerade fertig damit, und mein Wort, meine FPS sind um das Dreifache gestiegen. Also lasse ich es fürs Erste dabei und stelle in Zukunft sicher, dass ich immer Precomputer Realtime GI verwende!

Wenn ich noch etwas tun könnte, um die Leistung weiter zu verbessern, lassen Sie es mich bitte wissen, ich wäre Ihnen sehr dankbar!


2
Verwenden Sie Occlusion Culling, auch wenn Ihre Szene groß ist. Teilen Sie sie in Abschnitte auf, z. B. in vielen Gebieten, und laden und entladen Sie sie.
Candid Moon_Max_

Angesichts der Tatsache, dass Sie Ihr Problem anscheinend gelöst haben, sollten Sie diese Antwort wahrscheinlich akzeptieren.
Gnemlock
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.