Vorwort
Nachdem das letzte Spiel aus der Metro-Serie veröffentlicht worden war, verbrachte ich mehrere Stunden damit, seine interne Arbeit zu studieren, und beschloss, etwas zu teilen, das aus technologischer Sicht interessant erscheinen könnte. Ich werde keine detaillierte Analyse durchführen oder den zerlegten Code der Shader untersuchen, aber ich werde die allgemeinen Entscheidungen zeigen, die die Entwickler bei der Erstellung des Spiels getroffen haben.
Im Moment haben die Entwickler noch nicht über die im Spiel verwendeten Rendering-Techniken gesprochen. Die einzige offizielle Informationsquelle ist der
GDC-Bericht , der nirgendwo anders im Internet zu finden ist. Und das ist ärgerlich, weil das Spiel auf einer sehr interessanten proprietären Engine läuft, die sich aus früheren Spielen der Metro-Serie entwickelt hat. Dies ist eines der ersten Spiele, die
DXR verwenden .
Hinweis: Dieser Artikel ist keine vollständige Beschreibung und ich werde darauf zurückkommen, wenn ich etwas finde, das es wert ist, hinzugefügt zu werden. Vielleicht habe ich etwas verpasst, weil einige Aspekte erst in den nächsten Phasen des Spiels auftauchen, oder ich habe mir nur die Details angesehen.
Erste Schritte
Ich habe mehrere Tage gebraucht, um eine Umgebung zu finden, die mit diesem Spiel arbeiten kann. Nachdem ich mehrere Versionen von RenderDoc und PIX getestet hatte, entschied ich mich, die Ergebnisse der Raytracing-Funktion mit Nvidia NSight zu untersuchen. Ich wollte das Rendern ohne Raytracing lernen, aber NSight erlaubte mir, auch die Details dieser Funktion zu untersuchen, und entschied mich, sie aktiviert zu lassen. Für den Rest des Renderings passt PIX gut. Mit beiden Anwendungen wurden Screenshots gemacht.
NSight hat einen Nachteil: Das Speichern der Aufnahme in einer Datei wird nicht unterstützt, sodass ich nicht zu den Frames zurückkehren konnte, die ich studiert habe.
Gleich zu Beginn meiner Arbeit stieß ich auf ein anderes Problem, das nichts mit Frame-Debugging-Anwendungen zu tun hatte: Für die Raytracing-Funktionen musste das neueste Windows-Update installiert werden, aber das Spiel ermöglichte es, sie in die Optionen aufzunehmen, ohne das Update zu installieren. In diesem Fall führte die Einbeziehung von Funktionen dazu, dass das Spiel beim Start abstürzte. Die GeForce Experience sagte auch nichts über die Notwendigkeit der richtigen Windows-Version aus, um diese Funktionen zu aktivieren. Dieses Problem muss auf beiden Seiten angegangen werden.
Der Vollständigkeit halber habe ich Aufnahmen von einem Spiel gemacht, das mit den maximal möglichen Parametern ausgeführt wurde, jedoch ohne DLSS.
Rahmenanalyse
Fertiger RahmenEine kurze Analyse des Renderings zeigt einen ziemlich standardmäßigen Satz von Funktionen, mit Ausnahme der globalen Beleuchtung, die durch Raytracing (Raytraced GI) durchgeführt wird.
Vor dem Rendern des Bildes wird der Maßstab des vorherigen Frames in der Rechenwarteschlange reduziert und die durchschnittliche Helligkeit berechnet.
Die grafische Warteschlange beginnt mit dem Rendern von Verzerrungspartikeln (Tröpfchen auf der Kamera), die in der Nachbearbeitungsphase angewendet werden. Dann erzeugt ein schneller vorläufiger Durchlauf der Tiefen einen Teil der Tiefen vor dem Gbuffer; es sieht so aus, als würde es nur eine Erleichterung bringen.
Der GBuffer-Durchlauf füllt 4 Rendering-Ziele gemäß dem folgenden Diagramm und vervollständigt auch das Füllen des Tiefenpuffers.
1. Ziel im RGBA8-Format mit Albedo und möglicherweise Umgebungsokklusion im Alphakanal; Auf einigen Oberflächen sieht es sehr dunkel aus.2. Ziel im RGB10A2-Format mit Normalen und möglicherweise einer unterirdischen Streumaske im Alphakanal.3. Ziel im RGBA8-Format mit anderen Materialparametern, wahrscheinlich Metall und Rauheit im Alphakanal. Seltsamerweise enthalten die RGB-Kanäle in diesem Fall genau die gleichen Daten.4. Ziel im RG16F-Format mit 2D-Bewegungsvektoren.Nachdem die Tiefen vollständig gefüllt sind, wird ein linearer Tiefenpuffer erstellt und sein Maßstab nimmt ab. All dies erfolgt in der Rechenwarteschlange. In derselben Warteschlange wird der Puffer mit etwas gefüllt, das der gerichteten Beleuchtung ähnelt, ohne Schatten zu verwenden.
In der Grafikwarteschlange verfolgt die GPU die Strahlen der globalen Beleuchtung, aber ich werde weiter unten mehr darüber sprechen.
Die Rechenwarteschlange berechnet Umgebungsokklusion, Reflexionen und ähnliches wie die Kantenerkennung.
In der Grafikwarteschlange wird eine vierstufige Schattenkarte in eine 32-Bit-Tiefenkarte der Größe 6k * 6k gerendert. Mehr dazu weiter unten. Nach Fertigstellung der Karte der gerichteten Schatten verringert sich die Auflösung der dritten Kaskade aus unbekannten Gründen auf 768 * 768.
In der Mitte des Schattenwiedergabeprozesses gibt es einen merkwürdigen Moment: Der Betrügeratlas wird durch einige Objekte ergänzt, bevor lokale Schatten aus der Beleuchtung gerendert werden (darüber, welche Betrüger
hier zu finden
sind ). Sowohl die Impostor-Puffer als auch die lokalen Lichtschattenpuffer sind ebenfalls 6k * 6k-Texturen.
Nachdem alle Schatten abgeschlossen sind, beginnt die Berechnung der Beleuchtung. Dieser Teil des Renderings ist ziemlich unverständlich, da es viele Renderings gibt, die einige mysteriöse Aktionen ausführen und daher zusätzliche Studien erfordern.
Das Rendern der Szene endet mit frontal beleuchteten Objekten (Augen, Partikel). Visuelle Effekte werden in einen Puffer mit halber Auflösung gerendert. Anschließend werden sie durch Zoomen mit undurchsichtigen Objekten zusammengesetzt.
Das endgültige Bild wird durch Tonwertkorrektur und Bloom-Berechnung erzielt (verringern und erhöhen Sie dann die Auflösung des Rahmens mit Tonwertkorrektur). Schließlich wird die Benutzeroberfläche in einen separaten Puffer gerendert und zusammen mit Bloom Compositing über die Szene gelegt.
Ich habe den Teil, in dem die Glättung durchgeführt wird, nicht gefunden, daher lasse ich ihn für später.
Globale Lichtstrahlverfolgung
Einige Informationen zur globalen Beleuchtung durch Raytraced GI. Diese beschleunigende Struktur deckt einen großen Bereich der Spielwelt ab, wahrscheinlich mehrere hundert Meter, und behält überall sehr hohe Details bei. Es scheint irgendwie zu streamen. Die Szene der beschleunigenden Struktur stimmt nicht mit der gerasterten Szene überein. Beispielsweise sind die Gebäude im Bild unten in der gerasterten Form nicht sichtbar.
Blick von obenHier sehen wir vier Kacheln, die die Position des Spielers umgeben. Ebenfalls offensichtlich ist der Mangel an Geometrie, die auf dem Alphakanal getestet wird. Bäume haben Stämme, aber kein Laub, kein Gras, keine Büsche.
Ansicht schließenIn der Nahansicht werden die Details und die Dichte von Objekten besser gesehen. Jedes Objekt einer anderen Farbe hat seine eigene Beschleunigungsstruktur der unteren Ebene. Nur auf diesem Bild gibt es mehrere hundert davon.
Spielergegenstände unter den FüßenInteressanterweise sind die Gegenstände des Spielers auch Teil der Beschleunigungsstruktur, befinden sich jedoch aus irgendeinem Grund unter seinen Füßen.
Gebrochene Haut?Wieder gebrochene Haut?Einige der Objekte mit Hautbildung sehen in der Beschleunigungsstruktur gebrochen aus. Eines der beobachteten Probleme ist das Dehnen des Netzes (an den Beinen des Kindes). Ein weiteres Problem führt dazu, dass sich verschiedene Teile des Charakters mit Hautbildung in unterschiedlichen Positionen befinden. Es gibt keine Dehnung, aber die Teile sind voneinander getrennt. Es scheint, dass nichts davon in der globalen Raytracing-Beleuchtung sichtbar ist, oder zumindest konnte ich dies im Spiel nicht bemerken.
Eine große Anzahl von ObjektenAuf einer allgemeineren Ebene können Sie sehen, wie viele verschiedene Objekte sich in der Beschleunigungsstruktur befinden. Die meisten von ihnen werden nicht wirklich zu den Ergebnissen der Berechnungen der globalen Beleuchtung beitragen. Hier ist auch zu sehen, dass es kein LOD-Schema gibt. Alle Objekte werden detailliert hinzugefügt. Es wäre interessant zu wissen, ob dies Auswirkungen auf das Raytracing hat (ich würde ja annehmen).
Ultrahohe LOD, jede Skala und jeder Schalter vollständig modelliertEin weiterer Screenshot zeigt ein großes Detail von Objekten, die noch weit vom Player entfernt sind. Jeder Schalter und jede Skala in diesem Bild sind auch ohne Texturen gut lesbar. Der Ort, an dem ich die Kamera bewegt habe, um diesen Screenshot aufzunehmen, befindet sich mehrere zehn Meter vom Player entfernt, und das Eliminieren dieser Details hätte die Bildqualität nicht verschlechtert. Möglicherweise wäre die Aktualisierung der Beschleunigungsstruktur mithilfe von LOD zu kostspielig, aber es besteht eine hohe Wahrscheinlichkeit, dass diese Aktualisierung asynchron durchgeführt werden kann. Dieser Punkt ist definitiv eine nähere Untersuchung wert.
Richtungsschatten rendern
Der Hauptteil des Renderns von Schatten ist einfach und erfordert keine besondere Erwähnung, aber hier gibt es interessante Punkte.
Maschen, für die Schattenwurf unwahrscheinlich istRiesige Details in SchattenkartenNetze, die anscheinend den falschen Indexpuffer verwendenEs scheint, dass das Schatten-Rendering wie das Beschleunigen von Strukturen absolut alles umfasst. Es gibt Objekte, die fast nicht zur Schattenkarte beitragen, aber dennoch gerendert werden. Ich frage mich, ob dies aufgrund einer Erlaubnis geschieht oder ob es keine einfache Möglichkeit im Motor gibt, sie auszuschließen.
Es gibt Objekte, die selbst bei Schatten im Bildschirmbereich schwer zu erkennen sind. Das Rendern dauert nicht lange, aber es wäre interessant zu sehen, ob sie entfernt werden können, um ein wenig Zeit zu sparen.
Bei der Untersuchung des Netzes scheinen einige der in der Schattenkarte gerenderten Netze defekte Indexpuffer zu haben, aber nach dem Vertex-Shader sehen sie korrekt aus (die Ergebnisse sind in PIX und NSight gleich). Dies ist das beste Beispiel, das ich gefunden habe, aber es ist bei weitem nicht das einzige. Vielleicht ist dies eine spezielle Verpackungsposition?
Maschen scheinen eine schlechte Haut zu habenDas Enthäuten scheint nicht nur bei der Beschleunigung von Strukturen Probleme zu verursachen. Interessanterweise führt dies nicht zu sichtbaren Artefakten auf dem Bildschirm.
Teil 2
Kleinere Änderung
Im vorherigen Teil habe ich geschrieben, dass das dritte Renderziel des GBuffer-Puffers höchstwahrscheinlich Metall enthält, aber es scheint, dass es tatsächlich Spiegelfarben enthält. Zuerst habe ich keine Farben gesehen und nicht verstanden, warum alle drei RGB-Kanäle dieselben Daten enthalten, aber wahrscheinlich, weil die Szene keine Farbreflexionen aufwies. Für diese Waffe enthält der Puffer viel mehr verschiedene Farben.
Ich habe auch vergessen, meine Lieblingstextur hinzuzufügen, die ich bei der Untersuchung des Renderings des Spiels gefunden habe. Es ist definitiv erwähnenswert, weil es die chaotische Natur der Spieleentwicklung demonstriert, wenn es nicht immer möglich ist, sie zu bereinigen.
"Verbessere mich!"Transparenz-Compositing und Anti-Aliasing
Beim Versuch herauszufinden, wie sich die Auflösung des Transparenzpuffers in halber Größe erhöht und wie das Spiel Antialiasing ausführt, fiel mir etwas Interessantes auf. Ich brauchte eine Szene, in der es viel mehr Kontrast gab, damit klar erkennbar war, was geschah. Glücklicherweise habe ich es geschafft, ein Bild zu erfassen, in dem sich die Waffe des Spielers leicht zwischen den Bildern bewegt.
Vor dem Rendern von TransparenzEs scheint, dass der Puffer vor dem Zusammensetzen des Transparenzpuffers bereits ein vollständig gerendertes Bild enthält. Da dieser Rahmen keine scharfen Kanten enthält, ist es logisch anzunehmen, dass dies die Daten des vorherigen Rahmens sind.
Nach dem Zusammensetzen der Transparenz des aktuellen FramesWenn Sie dem aktuellen Frame Transparenz hinzufügen, können Sie einzelne gebrochene Kanten feststellen. Es geschah, weil sich die Waffe leicht nach rechts bewegte. Einige Wolken werden transparent gemacht, aber sie werden am Horizont abgeschnitten (was undurchsichtig ist), sodass beim Zusammensetzen der Boden nicht verändert wird, sondern bereits das Waffennetz aus dem vorherigen Frame mithilfe des Tiefenpuffers des aktuellen Frames gerendert wird.
Nach dem Hinzufügen von Deckkraft zum aktuellen BildNach mehreren Zeichenaufrufen werden Compositing- und undurchsichtige Netze ausgeführt. Es scheint keinen besonderen Grund zu geben, dies in dieser Reihenfolge zu tun. Es ist logisch, den Transparenzpuffer in die Daten undurchsichtiger Objekte des aktuellen Frames zu komponieren. Dies ist jedoch nicht der Fall, und es wäre interessant zu wissen, warum.
Nach TAANach Abschluss des vollständigen Frames glättet der TAA-Durchgang (Temporal Smoothing) die Kanten. Das hat mich schon früher interessiert, weil ich nicht gesehen habe, wo die Glättung stattfindet. Aber ich habe dies übersprungen, weil unmittelbar nach diesem Draw-Aufruf das Downsampling für den Bloom-Pass beginnt und ich diesen einen Draw-Aufruf verpasse.
Linseneffekt
Normalerweise möchte ich keine einzelnen Effekte analysieren, aber es gibt viele Möglichkeiten, Linseneffekte zu implementieren. Daher war ich gespannt, welche Entwickler sich entschieden haben.
Linseneffekt beim fertigen CompositingIn den meisten Fällen ist der Linseneffekt kaum wahrnehmbar, aber dies ist ein schöner Effekt. Es ist schwierig, auf dem Screenshot zu zeigen, daher werde ich mich nicht viel Mühe geben.
Linseneffekt im BlütenpufferNach der Suche fand ich einen Draw-Aufruf, der diesen Effekt hinzufügt, und es stellte sich heraus, dass es sich um einen Aufruf nach der letzten Phase der Erhöhung der Bloom-Auflösung handelte. In diesem Puffer ist der Effekt viel deutlicher.
Geometrie LinseneffektWenn Sie sich die Geometrie ansehen, ist der Linseneffekt ziemlich einfach. Mindestens 6 Vierecke sind an der Erstellung des Endergebnisses auf dem Bildschirm beteiligt, es gibt jedoch keine Reihe kleinerer Vierecke, die sich dem Sonnenstand nähern. Wir können daraus schließen, dass dies eine ziemlich standardmäßige Lösung ist, obwohl einige Entwickler den Linseneffekt direkt in der Rendertarget-Szene rendern, während andere den Effekt als Nachbearbeitung berechnen.
Terrain-Rendering
Eine der interessantesten Schwierigkeiten bei allen Open-World-Spielen ist das Rendern von Gelände. Ich entschied, dass es interessant erscheinen könnte, diesen Aspekt zu untersuchen, aber ehrlich gesagt ein wenig enttäuscht.
Auf den ersten Blick sieht ein Fragment des Reliefs so aus, als würde eine Art Tessellation durchgeführt. Die Art und Weise, wie das Relief während der Bewegung verformt wird, macht es logisch anzunehmen, dass es eine zusätzliche Verschiebung gibt. Darüber hinaus verwendet das Spiel auf einem PC aktiv die Tessellation, sodass es logisch wäre, sie als Relief zu verwenden.
Vielleicht hatte ich die falschen Parameter eingestellt, aber das Spiel rendert alle Fragmente des Reliefs ohne Tessellation. Für jedes Fragment des Reliefs verwendet sie dieses einheitliche 32 * 32-Raster. Es gibt auch keine LOD.
Wenn Sie sich ein Fragment des Reliefs nach dem Scheitelpunkt-Shader ansehen, sehen Sie, dass die meisten Scheitelpunktpaare zu einem nahezu perfekten 16 * 16-Raster zusammengeführt wurden, mit Ausnahme einiger Stellen, die mehr Genauigkeit erfordern (wahrscheinlich aufgrund der Krümmung des Reliefs). Die oben erwähnte Verformung entsteht wahrscheinlich durch das Lesen der Mip-Texturen der Höhenkarte des Reliefs, wenn das Relief weit von der Kamera entfernt ist.
Ray Tracking Tricks
Und nun darüber, worauf alle gewartet haben.
Daten streamen
Einer der derzeit interessantesten Aspekte einer DXR-Implementierung ist die Art und Weise, wie Sie mit Daten arbeiten. Das Wichtigste ist, wie die Daten in beschleunigende Strukturen geladen und wie sie aktualisiert werden. Um dies zu testen, habe ich zwei Aufnahmen gemacht und die beschleunigenden Strukturen in NSight verglichen.
Der Spieler ist im SchiffBei der ersten Aufnahme stand ich in einem kaputten Schiff, das in der Mitte dieses Bildes sichtbar ist. Es werden nur die nächstgelegenen Objekte geladen, mit Ausnahme großer Steine am Rand der Karte.
Der Player hat sich in die obere linke Ecke dieses Bildes bewegt.Bei der zweiten Aufnahme entfernte ich mich vom Rand der Karte und befand mich näher am oberen linken Rand des Bildes. Das Schiff und alles um es herum ist noch geladen, aber es wurden auch neue Objekte geladen. Interessanterweise kann ich keine Kachelstruktur definieren. Objekte können basierend auf Entfernung und Sichtbarkeit aus der Beschleunigungsstruktur geladen / daraus entfernt werden (möglicherweise wird das Parallelogramm eingeschränkt?). Außerdem sieht der obere rechte Rand detaillierter aus, obwohl er sich von ihm entfernt hat. Es wäre interessant, mehr darüber zu erfahren.
Erleichterung und was darunter ist
Einige Aspekte der DXR-Implementierung in Metro: Exodus in Bezug auf das Gelände können erwähnt werden.
Erstens ist es interessant, dass Beschleunigungsstrukturen keine Reliefnetze enthalten (mit Ausnahme von Sonderfällen). Diese Monster rennen tatsächlich im Spiel auf dem Boden, aber nach den Daten in NSight könnte man denken, dass sie fliegen. Dies wirft für uns eine interessante Frage auf: Kann die Implementierung der globalen Beleuchtung das Relief irgendwie berücksichtigen (möglicherweise unter Verwendung einer Höhenkarte und eines Reliefmaterials) oder nicht?
Im nächsten Moment hätte ich es nie bemerkt, wenn die Erleichterung vorhanden wäre. Als ich zu Beginn des Levels die Beschleunigungsstruktur in NSight betrachtete, bemerkte ich einige Maschen unter dem Relief.
Künstler platzieren aus verschiedenen Gründen häufig Debug-Meshes unter dem Level, aber sie werden normalerweise gelöscht, bevor das Spiel veröffentlicht wird. In diesem Fall überlebten diese Maschen nicht nur bis zur Freisetzung, sondern wurden auch Teil der beschleunigenden Struktur.
Zusätzlich zu den oben genannten fand ich andere Maschen, die unter dem Relief verstreut waren. Grundsätzlich sind sie nicht sehr erwähnenswert, aber dieser war sehr interessant - dies ist ein Charakter, der direkt unter dem Startpunkt des Levels steht. Es hat sogar einen eigenen Pool.
Das letzte merkwürdige Element der Beschleunigungsstruktur sind die einseitigen Maschen, die nach außen schauen. Wenn sie nicht als bilateral betrachtet werden, besteht nur eine sehr geringe Chance, dass sie einen Beitrag zum Bild des Spiels leisten. Selbst wenn die Maschen zweiseitig sind, sind sie so weit vom spielbaren Bereich entfernt, dass sie wahrscheinlich nur die Beschleunigungsstruktur dehnen. Es ist interessant zu sehen, dass sie nicht gefiltert werden. Dieses Bild zeigt auch einen der Sonderfälle des "Reliefnetzes" in der unteren rechten Ecke zwischen Zug und Gebäude.
Kopflosigkeit beim Häuten
Ich habe bereits über die Probleme beim Enthäuten von Maschen gesprochen, aber auf dieser Ebene ist mir etwas anderes aufgefallen.
Erstens zeigt dieses Monster beide Fehler in einem Bild, die ich oben bemerkt habe. Ich frage mich immer noch, was sie verursacht hat.
Mir ist auch aufgefallen, dass diese kleinen Kreaturen wie Fledermäuse keine Köpfe in der Beschleunigungsstruktur haben.
Ein weiteres Beispiel. Beachten Sie das Loch, in dem sich der Kopf befinden sollte. Ich habe keinen einzigen Fall gesehen, in dem der Kopf sichtbar war.
Die gleiche Art von Kreaturen im Rastermodus.
Beachten Sie, dass der Kopf deutlich sichtbar ist.Und hier ist das Drahtgitter des Kopfes.Abschließend
Das ist alles für heute. Ich hoffe, Ihnen hat dieser Blick auf die Innenseiten von Metro: Exodus gefallen.Ich werde mich weiterhin mit dem Rendern des Spiels befassen, aber ich werde keine neuen Teile des Artikels veröffentlichen, es sei denn, ich finde einige spezielle Teile, die für die Leute interessant wären, oder finde etwas, das es wert ist, geteilt zu werden.