Rendering in Unreal Engine
Einführung in das Rendering in Spiel-Engines
Rendering bezieht sich auf den Prozess der Generierung eines endgültiges Bildes (Frame) auf dem Bildschirm aus einer Sammlung von Objekten in einer Szene.
Die Software, die für das Rendering eines Frames verwendet wird, wird als Rendering-Engine bezeichnet und diese Engines werden normalerweise wie folgt kategorisiert:
-
Offline-Rendering: Konzipiert für hochwertiges Rendering, bei dem Qualität Priorität vor der Verarbeitungszeit hat. Dies wird im Allgemeinen bei Anwendungen eingesetzt, bei denen die Rendering-Zeit im Vergleich zur Qualität des fertigen gerenderten Frames nicht wichtig ist.
-
Echtzeit-Rendering: Konzipiert im Hinblick auf die Performance für ein schnelles Rendering der Frames. Die normalen Echtzeit-Frameraten-Zielwerte liegen bei 30 (33 ms), 60 (16 ms) und 120 (8 ms) Frames pro Sekunde (FPS), aber die tatsächlichen Frameraten können im Lauf der Zeit abhängig von einer Reihe Faktoren variieren. Mit Echtzeit-Rendering entwickelte Projekte müssen häufig das Gleichgewicht zwischen Performance und Qualität finden, um einheitliche Frameraten zu erzielen. Echtzeit-Rendering-Engines werden normalerweise für interaktive Medien, wie Videospiele, Simulationen und Architekturvisualisierungen eingesetzt.
Unreal Engine ist eine leistungsstarke Tool-Suite für das Echtzeit-Rendering, um die Anforderungen zahlreicher Plattformen von Mobilgeräten bis hin zu leistungsstarken Desktop-Computern zu erfüllen. Unreal Engine kann sowohl hochwertiges Echtzeit- als auch Offline-Rendering bieten. Sie können damit alles erstellen, von interaktiven 2D- und 3D-Erlebnissen auf Mobilgeräten, Konsolen und Desktop-Plattformen bis zum Rendering endgültiger Frames für Film- und Fernsehproduktionen.
Im Gegensatz zu anderen Echtzeit-Engines auf dem Markt bietet Unreal Engine viele proprietäre Funktionen, die speziell im Hinblick auf Echtzeit und Performance konzipiert wurden. Das Ziel besteht darin, die Komplexität der Entwicklung zu reduzieren und schneller Ergebnisse zu erzielen, während eine hohe Qualität und Performance beibehalten werden.
Funktionen wie das Lumen-System für globale Beleuchtung und Reflexionen, die virtualisierte Nanite-Geometrie und virtuelle Shadow-Maps sind wichtige Schritte hin zu dem Ziel, die Komplexität bei der Entwicklung mit Funktionen zu eliminieren, die für Konsolen- und Desktopanwendungen „einfach funktionieren“. Mobile Plattformen unterstützen dynamische Beleuchtung und vorberechnete Beleuchtungs-Workflows, für die Sie Beleuchtung in Texturen baken müssen.
Einführung in das Rendering in Unreal Engine
Spiel-Engines führen einige Schritte aus, die häufig als Rendering-Pipeline bezeichnet werden, um ein Bild (oder einen Frame) in der Szene zu rendern. Dieser Abschnitt beschreibt, wie Unreal Engine hierzu seinen Standardpfad für aufgeschobenes Rendern nutzt, und vergleicht (wo angemessen) die Schritte mit dem Pfad für aufgeschobenes Rendern von Unity.
Die Unity-Engine umfasst drei unterschiedliche Rendering-Pipelines: Integriert, Universal und Hochauflösung. Jede Pipeline ist für spezifische Anwendungsfälle konzipiert und wird im Allgemeinen ausgewählt, bevor Sie ein neues Projekt starten.
Unreal Engine umfasst eine einheitliche Rendering-Pipeline, die einzelne Funktionen auf Grundlage der Zielplattform skaliert: von Handheld- und Mobilgeräten bis zur aktuellen Konsolen- und Computergeneration. Das bedeutet, dass Sie einen Rendering-Pfad und unterstützte Funktionen auswählen können, die Ihrem Projekt am besten entsprechen, ohne dass Sie auf einen einzelnen Pfad festgelegt sind.
Die Rendering-Pipeline von Unreal Engine kann mit ihrem Standardpfad für das aufgeschobene Rendering genutzt werden, oder sie kann für die Ausführung in einem Vorwärtsrendern-Pfad konfiguriert werden. Des Weiteren können Sie den mobilen Rendering-Pfad aktivieren, um auch Geräte mit niedrigerer Leistung zu berücksichtigen, darunter der Vulkan Mobile Renderer. In der Dokumentation Vom Renderingpfad unterstützte Funktionen finden Sie weitere Informationen zu den von jedem Rendering-Pfad unterstützten Rendering-Funktionen.
Die folgende Abbildung zeigt eine detailliert Visualisierung der Schritte, die Unreal Engine für jeden Frame ausführt, um ein endgültiges Bild mit dem Pfad für aufgeschobenes Rendern zu rendern:
Der Vorgang verläuft von links nach rechts, wobei die Schritte 2 bis 5 parallel erfolgen.
Weiter unten erfahren Sie mehr über diese Schritte in der Rendering-Pipeline und darüber, was für das Rendering jedes Frames erforderlich ist.
Szenenvorbereitung und Okklusion
Unreal Engine verfügt über drei Haupt-Threads: die Spiel- (CPU), Zeichnen- und GPU-Threads.
Bevor der Rendering-Prozess gestartet wird, sammelt der Spiel-Thread (oder CPU-Thread) die Transformationen aller Objekte in einer Szene. Das umfasst die Verarbeitung aller Animationen, Physik-Simulationen und künstlichen Intelligenz (KI), bevor die endgültiges Umwandlung für jedes Objekt erfasst wird.
Die Transformationsinformationen werden dann an den Zeichnen-Thread der CPU übergeben. Der Zeichen-Thread führt den Ausblenden-Prozess aus, der eine Liste der sichtbaren Objekte in der aktuellen Kameraansicht erstellt und alle anderen Objekte entfernt, die für die Kamera nicht sichtbar sind. Diese Objekte müssen nicht gezeichnet werden. Wenn sie nicht gerendert werden, verbessert dies die Performance.
Dieser Prozess führt die folgenden Schritte aus (in dieser Reihenfolge):
- Entfernungsausblendung: Entfernt alle Objekte, die sich weiter als ein bestimmter Abstand von der Kamera entfernt befinden.
- Frustum-Ausblendung: Entfernt Objekte, die im Frustum (Ansicht) der Kamera nicht sichtbar sind.
- Okklusionsausblendung: Überprüft ganz genau den Sichtbarkeitsstatus aller verbleibenden Objekte in der Szene. Dieses Verfahren ist kostenaufwendig und erfolgt daher am Ende des Okklusionsprozesses, wenn die verbleibenden sichtbaren Objekte weiter getestet werden, um zu sehen, ob sie durch andere Objekte okkludiert (verborgen) werden.
Die endgültige Liste sichtbarer Objekte wird an den GPU-Thread übergeben, um den Rendering-Prozess zu beginnen.
Unity-Entsprechung
Unity führt in seiner Rendering-Pipeline eine Frustum- und Okklusionsausblendung durch. Des Weiteren kann es mit seiner CullingGroup-API eine Entfernungsausblendung ausführen. Eine Kombination dieser Techniken erstellt die endgültige Liste sichtbarer Objekte in der Szene.
Geometrie-Rendering
In diesem Schritt durchläuft Unreal Engine die Liste aller sichtbarer Objekte in der Szenen und bereitet sie auf den nächsten Schritt vor, in dem 3D-Scheitelpunktdaten in Pixeldaten umgewandelt werde, die in der Szene angezeigt werden.
Scheitelpunkt-Shader
Ein Shader ist ein Stück Code, der direkt auf der GPU ausgeführt wird und mit dem bestimmte Berechnungen ausgeführt werden. Sie sind effizient und die GPU kann viele Shader-Berechnungen gleichzeitig ausführen.
Der Scheitelpunkt-Shader führt die folgenden Schritte aus:
- Konvertiert lokale Scheitelpunkt-Positionen in Weltpositionen: Objekt-Scheitelpunktdaten werden im lokalen Raum gespeichert, aber sobald das Objekt in der Welt platziert wird, müssen die Scheitelpunkt-Informationen in Weltenraum-Koordinaten umgewandelt werden.
- Verarbeitet Scheitelpunkt-Schattierung und -Farbgebung: Der Scheitelpunkt-Shader verarbeitet die Scheitelpunktglättung sowie alle Scheitelpunkt-Farbdaten im Objekt selbst.
- Kann einen zusätzlichen Versatz auf Scheitelpunktpositionen anwenden: Der Scheitelpunkt-Shader kann die Position jedes Scheitelpunktes auf dem Bildschirm versetzen, um spezifische Effekte zu erzielen. Das erfolgt über das Material eines Objekts und wird als Welt-Positionsversatz bezeichnet.
Tiefenpass
Vor dem Rendering einzelner Objekte führt Unreal Engine einen Tiefenpass oder frühen Z-Pass durch, um die Position der Objekte in Relation zueinander zu bestimmen. Dies verhindert eine Situation, in der Unreal Engine die gleichen Pixel auf dem Bildschirm mehrfach rendert. Das wird als Überziehen bezeichnet und kann bedeutende Auswirkungen auf die Performance haben. Die Engine versucht, dies so weit wie möglich zu vermeiden.
Draw-Aufrufe
Nach dem Tiefenpass rendert die GPU jedes Objekt, indem alle Polygone gezeichnet werden, die zur gleichen Zeit die gleichen Eigenschaften haben, wie Meshs und Materialien. Das wird als Draw-Aufruf bezeichnet.
Alle Polygone eines Objekts, die dem gleichen Material zugewiesen sind, werden als der gleiche Draw-Aufruf gezählt. Jedes eindeutige Material erfordert aber seinen eigenen separaten Draw-Aufruf. Zum Beispiel erfordert jedes Objekt auf dem Bildschirm mindestens einen Draw-Aufruf, kann aber abhängig von der Anzahl der Materialien, die dem Objekt zugewiesen sind, mehr haben.
Die virtualisierte Nanite-Geometrie von Unreal Engine rendert alle Polygone für alle Objekte mit einem bestimmten Material zur gleichen Zeit. Frame-Budgets werden nicht mehr durch die Polygonanzahl, Draw-Aufrufe oder die Mesh-Speicherverwendung beschränkt.
Unity-Entsprechung
Die Rendering-Pipeline von Unity führt ähnliche Schritte durch, wenn sie einen Tiefenpass ausführt, und verwendet Draw-Aufrufe, um die Objekt in der Szene zu zeichnen.
Rasterisierung und der Geometrie-Buffer
Der Rasterisierungsprozess wandelt 3D-Scheitelpunktdaten in 2D-Pixeldaten um, die auf Ihrem Bildschirm angezeigt werden. Dieser Prozess beginnt, nachdem der Scheitelpunkt-Shader alle seine Daten verarbeitet hat.
Der Geometrie-Buffer (GBuffer) von Unreal Engine umfasst eine Reihe Bilder, die Informationen über die Geometrie in der Szene speichern. Diese Bilder umfassen normalerweise Dinge wie Beleuchtungsinformationen für Basisfarbe, Weltnormale, metallisch, Rauheit und spiegelnd in der Szene. Diese Bilder im GBuffer werden zusammengestellt und bilden das endgültige Bild, das Sie auf dem Bildschirm sehen.
Der Prozess der Umwandlung dieser zusammengesetzten Bilder erfolgt für jeden Frame, der gerendert wird, und für jeden Draw-Aufruf, bei dem Scheitelpunktdaten in Pixeldaten umgewandelt werden, und zeichnet die richtigen Teile des Bildes in den GBuffer.
Unity-Entsprechung
Der aufgeschobene Renderingpfad von Unity verwendet ebenfalls einen GBuffer, um wichtige Informationen über die Szene zu speichern. Im Fall von Unity speichert der GBuffer ähnliche Informationen über die Szene (referenziert mit anderen Namen): Albedo, räumlich, normal, und emissive/Beleuchtungsinformationen für die Objekte.
Rendering von Texturen
Die Unreal Engine verwendet zum Rendern von Texturen das [Texturenstreaming] (designing-visuals-rendering-and-graphics/rendering-optimization/textures-streaming/Overview), um das Laden von Texturen in die Szene zu optimieren. Das Texturenstreaming-System verwendet Textur-Mip-Maps. Dabei handelt es sich um eine vorberechnete Sequenz von Bildern mit derselben Textur in unterschiedlichen Auflösungen. Stellen Sie sich dies als Detailstufen (LODs, Levels of Detail) für Texturen anstelle von Meshs vor. Die Engine erstellt automatisch diese Mip-Maps, wobei jedes Bild die halbe Auflösung des vorherigen aufweist.
Unreal Engine streamt die Mip-Map der Textur im Gameplay basierend auf dem Abstand zur Kamera. Dies erfolgt automatisch, um die Bandbreite und den Speicherverbrauch zu optimieren sowie um Rauschen weiter weg von der Kamera zu reduzieren.
Texturgrößen müssen eine Zweierpotenz aufweisen, um Mip-Maps zu erhalten. Gängige Texturgrößen sind 3840 x 2160 Pixel (4K) und 1920 x 1080 Pixels (HD). Beachten Sie, dass Texturen kein bestimmtes Verhältnis haben müssen. Eine Textur mit 1920 x 480 Pixeln erhält auch Mip-Maps.
Unity-Entsprechung
Das Mip-Map-Streaming-System von Unity verwendet Textur-Mip-Maps, um seine Texturen zur Laufzeit zu streamen. Ähnlich wie Unreal Engine streamt dieses System die entsprechende Textur-Mip-Map automatisch basierend auf dem Abstand von und dem Winkel zur Kamera.
Pixel-Shader und Materialien
Wenn die Objekte im GBuffer vollständig gerendert wurden, beginnt Unreal Engine mit dem Shading jedes Objekts auf dem Bildschirm, indem die Materialeigenschaften jedes Objekts mit dem Pixel-Shader verwendet werden.
Ein Pixel-Shader führt eine Reihe Berechnungen durch, um die Pixelfarbe auf dem Bildschirm zu ändern. Pixel-Shader laufen auf der GPU und sind extrem effizient. Sie sind der Antrieb für das Materialsystem von Unreal Engine und werden verwendet, wenn Beleuchtung, Nebel, Reflexionen und Nachbearbeitungseffekte berechnet werden.
Das Materialsystem verwendet Shader-Vorlagen der High-Level Shader Language (HLSL) zusammen mit dem Material-Editor, um die endgültige Materialien zu erstellen, die auf die Objekte auf dem Bildschirm angewendet werden. Diese Materialien können Parameter, wie Texturen, nutzen, um das Aussehen jedes Objekts zu definieren.
Unity-Entsprechung
Unity umfasst mehrere vorkonfigurierte Shader (entsprechend den Materialien in Unreal Engine) sowie seinen Shader Graph, um Shader für Ihr Projekt zu erstellen. Der Material-Editor von Unreal Engine entspricht dem Shader Graph von Unity.
Reflexionen
Nach dem Shading aller Objekte in der Szene beginnt Unreal Engine mit dem Rendering der Objektreflexionen basierend auf deren Materialeigenschaften.
Unreal Engine verwendet vier Systeme für das Rendering von Reflexionen in der Szene. Diese Systeme werden in der folgenden Reihenfolge ausgeführt:
- Reflexion-Erfassungen: Vorberechnet und in einer statischen Cubemap an einer bestimmten Position gespeichert
- Planare Reflexionen: Erfasst Reflexionen von und auf einer Ebene
- Bildschirmraum-Reflexionen (Screen Space Reflections, SSR): Verwendet die verfügbaren Bildschirminformationen, um genaue Reflexionen für Objekte in Echtzeit zu zeichnen
- Lumen-Reflexionen: Löst Reflexionen für den gesamten Bereich der Rauheitswerte in der Szene. Diese Reflexionen umfassen Unterstützung für das Skylight, Clear-Coat-Materialien, Transluzenz und sogar Wassermaterialien mit einzelnen Schichten.
Unreal Engine führt eine Überblendung zwischen den drei Methoden aus, wobei die Bildschirmraum-Reflexionen Priorität erhalten, und greift dann auf planare Reflexionen und zuletzt auf Reflexionserfassungen zurück. Das letzte Reflexionsergebnis wird mit der Rauheit, räumlichen und metallischen Bilder im GBuffer kombiniert.
Wenn Sie die globale Lumen-Beleuchtung verwenden, werden automatisch Lumen-Reflexionen verwendet. Sie können aber auch Lumen-Reflexionen ohne Lumen-GI verwenden. In diesem Fall verwendet Unreal Engine gebakte Beleuchtung mit Lumen-Reflexionen.
Unity-Entsprechung
Die Reflection Probes von Unity biete eine ähnliche Funktionalität und werden verwendet, um Reflexionsdaten für Ihre Szene vorzuberechnen.
Statische Beleuchtung und Schatten
Nachdem die Reflexionen gerendert wurden, rendert Unreal Engine die statische Beleuchtung und Schatten für alle Objekte in der Szene.
Unreal Engine verwendet sein globales Lightmass-Beleuchtungssystem, um die Beleuchtungsinformationen für die Szene vorzuberechnen. Die Beleuchtungs- und Schatteninformationen werden in einer Light-Map-UV-Textur gespeichert und diese Textur wird mit der Basisfarbe des Objekts überblendet, wenn das Objekt in der Szene gerendert wird.
Dieses System ist sehr schnell, aber es erfordert mehr Speicher und muss jedes Mal vorberechnet werden, wenn es eine Änderung der Szene gibt.
Das globale Lightmass-Beleuchtungssystem ist eine gute Option für Projekte, die auf Mobilgeräte und Geräte mit niedrigerer Leistung abzielen.
Unity-Entsprechung
Unitys Systeme Progressive Lightmapper und Enlighten Baked Global Illumination bieten ähnliche Funktionalität, wenn die Beleuchtung für Ihre Szene vorberechnet wird.
Dynamische Beleuchtung und Schatten
Nachdem die statische Beleuchtung gerendert wurde, rendert Unreal Engine die dynamische Beleuchtung (Echtzeit) und Schatten mit Lumen, seinem System für die dynamische, globale Beleuchtung.
Lumen ist ein vollständig dynamisches globales Beleuchtungs- und Reflexionssystem, das für Konsolen und High-End-Computer der nächsten Generation konzipiert ist. Das System verwendete mehrere Raytracing-Methoden, um die globale Beleuchtung und Reflexionen in der Skalierung zu lösen.
Lumen bietet unendliche Streureflexionen und funktioniert nahtlos mit der virtualisierten Nanite-Geometrie. Des Weiteren funktioniert das System in Verbindung mit virtuellen Shadow-Maps, um weiche Echtzeit-Schatten mit hoher Auflösung zu erzeugen.
Lumen bietet Lumen-Reflexionen, die Reflexionen für den gesamten Bereich der Rauheitwerte in der Szene lösen. Diese Reflexionen umfassen Unterstützung für das Skylight, Clear-Coat-Materialien, Transluzenz und sogar Wassermaterialien mit einzelnen Schichten.
Lumen ersetzt Bildschirmraum-Reflexionen, wenn es in der Szene verwendet wird.
Unity-Entsprechung
Unity bietet mit der Enlighten Realtime Global Illumination dynamische Beleuchtung in der Szene. Dieses System bietet globale Echtzeit-Beleuchtung, indem vorberechnete Sichtbarkeitsinformationen zusammen mit Light-Maps eingesetzt werden, um indirekte Lichtreflexionen zur Laufzeit zu berechnen.
Dies weicht von Lumen ab, da Lumen keine vorberechneten Daten erfordert, um indirekte Lichtreflexionen zu bieten.
Nebel und Transparenz
Nach dem Rendering von dynamischer Beleuchtung und Schatten rendert Unreal Engine als Nächstes Nebel- und Transparenzeffekte.
Unreal Engine rendert Nebeleffekte mit seinem Exponentieller-Höhennebel-System, das die Nebeldichte basierend auf der Höhe und dem Abstand zur Kamera rendert. Des Weiteren kann das System volumetrischen Nebel generieren.
Transparente Objekte verwenden ein transparentes Material und werden in dieser Phase im Prozess gerendert. Wenn der Pfad für aufgeschobenes Rendern verwendet wird, nutzt Unreal Engine Informationen, die im GBuffer verfügbar sind, um die Transparenz zu rendern. Alternativ können Sie das Material so konfigurieren, dass der Vorwärtsrendern-Pfad verwendet wird, um einen genaueren Transparenzeffekt zu erzeugen.
Unity-Entsprechung
Unity unterstützt die Nebelvarianten Linear, Exponential und Exponential Squared in der Szene.
Nachbearbeitungseffekte
Wenn Nebel und Transparenz gerendert wurden, kann Unreal weitere Effekte auf das Bild anwenden. Diese Effekte werden als Nachbearbeitungseffekte bezeichnet, weil sie angewendet werden, nachdem das endgültige Bild verarbeitet wurde. Die Effekte stützen sich auf den Pixel-Shader und nutzen die im GBuffer verfügbaren Informationen.
Einige gängige Nachbearbeitungseffekte umfassen Licht-Bloom, Schärfentiefe, Lichtschächte, Tonemapping und Bewegungsunschärfe.
Als Teil dieses Nachbearbeitungsschritts kann Unreal Engine Temporal Super Resolution (TSR) anwenden. TSR ist ein plattformunabhängiger temporaler Upscaler, mit dem Unreal Engine wunderschöne 4K-Bilder rendert. Bilder kosten nur noch einen Bruchteil ihrer Kosten, indem einige der aufwendigen Rendering-Berechnungen über mehrere Frames amortisiert werden.
In der Rendering-Kette erfolgt die Temporal Super Resolution nach der Schärfentiefe und alles, was danach folgt, wird hochskaliert, wie Bewegungsunschärfe, Bloom usw.
Sobald diese Effekte auf den GBuffer angewendet wurden, rendert Unreal Engine das endgültige Bild der Szene.
Die oben aufgeführten Schritte generieren einen einzelnen Frame auf dem Bildschirm. Diese Schritte werden häufig abhängig von der Ziel-Framerate des Spiels zwischen 30 und 60 Mal pro Sekunde wiederholt.
Unity-Entsprechung
Unity umfasst Nachbearbeitungslösungen auf Basis der gewählten Rendering-Pipeline. Viele der verfügbaren Effekte ähneln denen, die in Unreal Engine verfügbar sind.
Des Weiteren umfasst Unity 6 auch Spatial-Temporal Post-processing (STP), einen nativen, softwarebasierten Scaler, der räumliche und zeitliche Upsampling-Techniken nutzt, um ein hochwertiges Anti-Aliasing-Bild zu produzieren.
Übersicht über die Renderingfunktionen in Unreal Engine
Da Sie nun die Schritte kennen, die Unreal Engine unternimmt, um einen Frame in der Szene zu rendern, können Sie mehr über spezifische Rendering-Funktionen lernen, die in die Engine integriert sind.
In der Dokumentation Beleuchtung der Umgebung erfahren Sie mehr über die Rendering-Funktionen von Unreal Engine.