Raytracing in Spielen VI: So werden Strahlen von GPUs beschleunigt

Update Christoph Riedel
202 Kommentare
Raytracing in Spielen VI: So werden Strahlen von GPUs beschleunigt
Bild: CD Projekt Red

Echtzeit-Raytracing ist gut vier Jahre nach dem Auftakt mit GeForce RTX 2000 und gut zwei Jahre nach Xbox Series X/S und PlayStation 5 in immer mehr Spielen optional verfügbar. Doch wie beschleunigen GPUs eigentlich die Berechnung der Strahlen? Ein Einblick in die Technik gibt Aufschluss.

Update

Der Artikel wurde um die seit seiner Erstveröffentlichung im April 2020 neu hinzugekommenen Erkenntnisse zu Hardware-Raytracing bei AMD und Intel, aber auch bei den Next-Gen-Konsolen und neuen Architekturen bei Nvidia ergänzt. Damals noch aktuelle, inzwischen aber überholte Textpassagen wurden angepasst.

Echtzeit-Raytracing in Hardware

15 Jahre ist es her, dass Gastautor Daniel Pohl im ersten Teil seiner über vier Jahre weiterverfolgten Serie „Raytracing in Spielen“ auf ComputerBase von seiner Forschungsarbeit in diesem Bereich berichtete. Er hatte als Diplomarbeit Quake 4 (und zuvor Quake III Arena) in Raytracing umgesetzt und ging auf die Vor- und Nachteile von Rendering mit Raytracing ein. Die Berechnung übernahm damals noch die CPU, denn Raytracing war „in Software“ umgesetzt.

Es folgten weitere Artikel zu den neuesten Entwicklungen und der Raytracing-Umsetzung von Enemy Territory: Quake Wars sowie ein Ausblick auf das, was mit Raytracing in der Cloud möglich wäre. Zwischenzeitlich trieb Pohl das Thema als Angestellter von Intel voran. Seit Anfang 2012 wurde es um selbiges ruhiger.

Nvidia Turing machte den ersten Schritt

Seit Ende 2018 und der Vorstellung der Grafikkarten vom Typ Nvidia GeForce RTX (in der 2000er Generation auf Basis von Turing) ist es mit der Ruhe vorbei. Mit den Next-Gen-Konsolen Xbox Series X/S sowie PlayStation 5 vund Grafikkarten von AMD sowie Intel, die Echtzeit-Raytracing ebenfalls unterstützen, wächst die Basis an kompatibler Hardware stetig an. Und die Anzahl der Spiele, die Raytracing als zusätzliche Grafikoption bietet, wächst und wächst.

Doch wie genau funktioniert die Beschleunigung der per Raytracing umgesetzten Grafikeffekte „in Hardware“ auf der GPU überhaupt?

Der folgenden Ausarbeitung liegt im Kern ein wissenschaftlicher Artikel aus dem Jahr 2017 zugrunde: „Toward Real-Time Ray Tracing: A Survey on Hardware Acceleration and Microarchitecture Techniques“ von Forschern von Qualcomm und der Tsinghua University in China erschien im Journal ACM Computing Surveys und liegt frei verfügbar als PDF auf Github. Die Forscher waren sich damals sehr sicher, dass innerhalb weniger Jahre Raytracing in Hardware in den Massenmarkt kommen würde – zumindest damit lagen sie zu diesem Zeitpunkt definitiv nicht falsch. Ob sie auch in anderen Aspekten Recht behalten werden?

We envision that a wave of research efforts on ray-tracing hardware will blossom in a few years.

Rasterisierung ist noch immer der Standard

Wird auf einem PC ein zweidimensionales Bild als Ausgabe einer dreidimensionalen Szene erstellt, so nennt man das „Rendern“. Um Bilder zu rendern, sind verschiedene Vorgehensweisen möglich. Bei Computerspielen überwiegt heutzutage die sogenannte Rasterisierung. Doch was genau steckt dahinter?

Im ersten Schritt wird eine dreidimensionale Szene in polygone (vieleckige) Grundflächen zerlegt, die auch „Primitives“ genannt werden. Bei der Rasterisierung werden die Polygone in Fragmente zerlegt, die den späteren Pixeln entsprechen. Im Anschluss werden den einzelnen Pixeln Farb- und Helligkeitswerte zugewiesen, das sogenannte „Shading“. Das fertige Bild wird anschließend ausgegeben.

Das klassische Rasterizer-Rendering
Das klassische Rasterizer-Rendering (Bild: Tsinghua University)

Das Rendern auf der Basis von Rasterisierung ermöglicht eine hohe Parallelisierung der Berechnung der Bildinformationen, da für alle Polygone parallel das Shading durchgeführt werden kann. Auf modernen Grafikkarten mit mehreren tausend Shadern können so sehr komplexe Szenen mit vielen Effekten gleichzeitig dargestellt werden. Die einfache Parallelisierung des Renderprozesses ist also der fundamentale Vorteil der Rasterisierung.

Rasterisierung ist schnell, weil es vereinfacht

Fundamentale Voraussetzung für das Gelingen des Renderns ist allerdings, dass die Polygone untereinander unabhängig sind und globale Parameter wie die Beleuchtung der Szene und damit auch der Schattenwurf im Vorhinein berechnet und abgespeichert wurden. Die realistische Darstellung der Polygon-übergreifenden Effekte wie globale und indirekte Beleuchtung, Schatten, Lichtbrechungen und Reflexionen ist nämlich ein Flaschenhals. Im Endeffekt können sie nur dann überzeugend erstellt werden, wenn mehrere Polygone gleichzeitig betrachtet werden, was auf herkömmlichen Grafikkarten zu erheblichem Leistungsverlust führen kann. Insbesondere Licht und Schatten sind bei der Rasterisierung also immer nur eine im Entwicklungsprozess sehr aufwändige Näherung – wenn auch zumindest auf den ersten Blick eine sehr gute.

Um den Realismus in Computerspielen auch mit Rasterisierung weiter voranzutreiben, werden immer umfangreichere Tricks angewandt, um die Aufgabe für den Rasterizer passend zu gestalten. Beispiele hierfür sind Bildschirmbereich-Reflexionen, Umgebungsverdeckung und Globale Beleuchtung.

Besser eignet sich für solche Effekte aber die alternative Rendering-Methode Raytracing, bei der Lichtstrahlen aus der Kameraperspektive auf die einzelnen Pixel geschossen und darauf aufbauend Reflexionen, Streuungen oder Brechungen der Strahlen aufgezeichnet werden. Raytracing dient bereits seit langer Zeit der Darstellung von fotorealistischen Bildern. Es ist die prominenteste Methode bei CGI-Effekten für Spielfilme und „Computer-Aided Design“ (CAD). Es bietet immense Vorteile, aber auch Nachteile.

Wie funktioniert Raytracing?

Raytracing emuliert die Wahrnehmung des Menschen. In der Realität werden Lichtstrahlen von Objekten gestreut bzw. reflektiert und erreichen danach das menschliche Auge. Im Raytracing-Algorithmus geht man den umgekehrten Weg und sendet Lichtstrahlen vom Betrachter auf die Szene. Treffen diese Primärstrahlen auf eine Oberfläche, werden je nach Eigenschaft verschiedene Sekundärstrahlen gebildet, die Schatten oder Reflexionen und bei transparenten Objekten auch Lichtbrechung berechnen. Weitere untergeordnete Strahlen können bei Bedarf, zum Beispiel bei Mehrfach-Reflexionen, ausgesendet werden.

Rendering basierend auf Raytracing
Rendering basierend auf Raytracing (Bild: Tsinghua University)

Raytracing ist von der grundlegenden Art des Algorithmus her optimal für viele Kerne, da sich die Strahlen leicht parallel berechnen lassen. Allerdings sind die Zugriffe auf den Arbeitsspeicher asynchron und schwer vorhersehbar, weswegen Raytracing auf herkömmlichen Grafikkarten-Shadern weniger effizient arbeitet als Rasterisierung. Das zeigt ein anschauliches Beispiel für eine komplexe Szene mit mehr als einer Millionen Polygone.

Von der theoretischen Leistung von 1,1 Milliarden Strahlen pro Sekunde (GigaRays/s), die eine traditionell aufgebaute GTX 1080 Ti berechnen kann, bleiben wegen der Belastung durch Speicherzugriffe nur ca. 300 Mio. tatsächlich berechnete Strahlen pro Sekunde übrig. Ohne Hardware-Beschleunigung ist Raytracing also nur schwer auf Grafikkarten umsetzbar. Dass es trotzdem geht, zeigt der von Crytek entwickelte Benchmark Neon Noir . Allerdings ist nicht gesichert, inwiefern Effekte in diesem Benchmark durch die ständig gleiche Kamerafahrt besser optimiert wurden, als es in richtigen Spielen möglich ist.

Der fundamentale Algorithmus für Raytracing wurde 1980 von Turner Whitted auf der Konferenz Siggraph vorgestellt. Als Ausgangspunkt dient wie bei der Rasterisierung eine in Polygone zerlegte Szene. Der Algorithmus besteht aus einer Schleife, die im Optimalfall alle Pixel der Kameraperspektive durchzählt und je einen Primärstrahl aussendet. Bei einer Auflösung von 4K und 60 FPS sind das knapp 500 Millionen Primärstrahlen pro Sekunde. Für eine höhere Bildqualität können auch mehrere Primärstrahlen pro Pixel aus leicht verschiedenen Positionen verschossen werden. Für jeden Primärstrahl gelten dann die folgenden Schritte:

  1. Es wird das Polygon bestimmt, das als Erstes vom Strahl getroffen wird.
  2. Es wird geprüft, ob die Stelle im Schatten liegt, indem zu jeder Lichtquelle je ein Sekundärstrahl verschossen wird.
  3. Ist die Oberfläche reflektierend, wird ein entsprechender Sekundärstrahl verschossen.
  4. Ist die Oberfläche transparent, wird ein gebrochener Sekundärstrahl verschossen.
  5. Sind alle Helligkeitsinformationen gesammelt, werden sie zusammen mit der Farbe des Polygons zum Shading übergeben.

Der erste Schritt ist derjenige, den Nvidia mithilfe seiner RT-Cores beschleunigt, wobei die Aufgabe vom Streaming-Multiprocessor an den RT-Core übergeben wird. Er nimmt in herkömmlichen Berechnungen am meisten Zeit in Anspruch, da die Komplexität mit steigender Anzahl Strahlen und Polygone jeweils proportional steigt. Die Schritte 2 bis 4 erzeugen mehrere Sekundärstrahlen, weswegen auch bei nur einem Primärstrahl pro Pixel schnell viele GigaRays/s an Raytracing-Leistung notwendig werden können. Eine besonders schwierige Szene sind Bäume mit einem hohen Anteil an transparenten Texturen, wie in einem früheren Artikel über Raytracing anschaulich dargestellt wurde. Es stellt sich die Frage, wie der Prozess effizient und ohne zu viel Verlust bei der Qualität beschleunigt werden kann.

RT-Cores übernehmen bei Nvidia Turing die Durchquerung der Beschleunigungsstruktur UND die Schnittstellen-Bestimmung
RT-Cores übernehmen bei Nvidia Turing die Durchquerung der Beschleunigungsstruktur UND die Schnittstellen-Bestimmung (Bild: Nvidia)