
Raytracing in Evergine
Einführung
Raytracing ist eine Technologie, mit der wir die Realitätsnähe unseres Renderings verbessern können. Die am weitesten verbreitete Technologie für Echtzeit-Rendering ist die Rasterisierung, bei der wir lange Zeit daran gearbeitet haben, alle Details der Welt wie unterschiedliche Oberflächen, Licht, Schatten und Reflexionen zu simulieren. Raytracing hingegen war eine Technologie, mit der sich all diese Details der realen Welt am besten annähern lassen, deren Einsatz im Echtzeit-Rendering jedoch sehr aufwendig war.
2018 brachte Nvidia seine neue Grafikkartengeneration mit RTX-Technologie auf den Markt, die den Rechenaufwand für Raytracing per Hardware senkt. Dadurch können wir Raytracing in Echtzeit nutzen und erhalten eine gute Alternative zur klassischen Rasterisierung.
Einige visuelle Effekte wie weiche Schatten, Echtzeit-Reflexionen oder globale Beleuchtung sind mit der klassischen Rasterisierung schwer umzusetzen, lassen sich mit Raytracing jedoch vergleichsweise einfach realisieren.
In den folgenden Jahren 2019, 2020 und 2021 verbreitete sich Raytracing auch bei anderen Grafikkartenherstellern wie AMD oder Intel, sodass Raytracing künftig zur Standardtechnologie werden dürfte.
Raytracing wird in Evergine als Teil seiner Low-Level-API unterstützt. Die Low-Level-API ist eine gemeinsame Schnittstelle zu den wichtigsten Grafik-APIs wie DX12, DX11, Metal, Vulkan oder OpenGL. Die Raytracing-Unterstützung ist derzeit allerdings nur in den Backends DirectX12 und Vulkan verfügbar.
Das Evergine-Team hat die Raytracing-APIs DirectX12 DXR und Vulkan in einer einzigen, gemeinsamen API vereint. So können Sie ein Projekt mit der Low-Level-API von Evergine schreiben und es später auf den Backends DX12 oder Vulkan ausführen.
Um die Möglichkeiten der Raytracing-Low-Level-API von Evergine zu zeigen, haben wir zum Start von Evergine eine Path-Tracer-Demo erstellt, die Sie auf Github herunterladen können. Diese Demo enthält einige interessante Effekte wie weiche Schatten, Ambient Occlusion, globale Beleuchtung und Antialiasing, die mit Raytracing umgesetzt wurden.
Im nächsten Abschnitt wird erläutert, wie die einzelnen Effekte umgesetzt wurden:

Zunächst sendet die Kamera einen einzelnen Strahl pro Pixel aus; jeder Strahl kann eine Oberfläche treffen oder nicht. Trifft der Strahl eine Oberfläche, ergibt sich die Farbe aus dem Material der Oberfläche; trifft er nichts, ist das Ergebnis die Hintergrundfarbe.
Weiche Schatten
Um Schatten per Raytracing umzusetzen, muss von jedem Trefferpunkt auf einer Oberfläche ein neuer Strahl zur Lichtquelle gesendet werden. Kollidiert dieser neue Strahl mit etwas, bevor er die Lichtquelle erreicht, gibt er den Wert „im Schatten“ zurück, andernfalls den Wert „im Licht“.

Das ist der einfachste Fall und erzeugt harte Schatten. Für weiche Schatten ist jedoch etwas mehr nötig. Unsere Implementierung sendet mehrere Strahlen von jedem Oberflächenpunkt zur Lichtquelle (in dieser Demo verwenden wir nur eine Lichtquelle). Der Einfachheit halber ist die Lichtquelle kugelförmig, und die Strahlen werden vom Trefferpunkt auf der Oberfläche in Form eines Kegels zur Lichtquelle gesendet.
Die Schattenfarbe ergibt sich dann aus dem kombinierten Ergebnis aller Strahlen. Halbschattenbereiche entstehen, wenn einige Strahlen „im Schatten“ und andere „im Licht“ zurückgeben.

Im folgenden Bild sind die Halbschattenbereiche zu sehen, wenn man die Schatten bei unterschiedlichen Radien der Lichtquelle vergleicht.

Ambient Occlusion
Ambient Occlusion simuliert Bereiche, die das Licht durch ein nahe gelegenes Objekt blockieren oder verdecken und daher dunkler erscheinen.
Unsere Ambient-Occlusion-Implementierung sendet mehrere kurze Strahlen vom Trefferpunkt auf der Oberfläche in eine an der Oberflächennormalen ausgerichtete Hemisphäre. Wie Schattenstrahlen erkennen diese Strahlen, ob sich etwas in der Nähe des Punktes befindet, das die Lichtreflexionen verdeckt.

Im folgenden Bild ist das Ergebnis mit unterschiedlichen Strahllängen für die Ambient Occlusion zu sehen:

Globale Beleuchtung
Das Verhalten von Licht in der realen Welt lässt sich simulieren, indem man von der Lichtquelle Strahlen aussendet, die auf eine Oberfläche treffen. Ein Teil der Energie des Strahls wird von der Oberfläche absorbiert, ein anderer Teil reflektiert, wodurch rekursiv ein neuer Strahl entsteht, bis die gesamte Energie des ursprünglichen Strahls absorbiert ist.

Mit einem Bounce-Parameter können wir simulieren, wie oft ein Lichtstrahl von den Oberflächen reflektiert werden kann. Die Farbe jeder Reflexion wird zur Oberflächenfarbe addiert, sodass beispielsweise ein rotes Objekt ein benachbartes Objekt rötlich färbt.
Im folgenden Bild ist das Ergebnis der globalen Beleuchtung zu sehen, bei dem einige Bereiche durch die Farben benachbarter Objekte gefärbt werden.

Antialiasing
Antialiasing entfernt Treppeneffekte aus dem Bild. Diese Treppeneffekte entstehen durch das begrenzte Pixelraster des Ausgabebildes.
Dazu müssen wir pro Pixel mehrere Strahlen von der Kamera aussenden und als Ergebnis eine Durchschnittsfarbe ermitteln. Wird nur ein Strahl pro Pixel gesendet, verläuft dieser durch die Pixelmitte. Für Antialiasing werden pro Pixel mehrere Strahlen in zufälliger Richtung innerhalb des Pixels gesendet. In unserer Implementierung verwenden wir eine Halton-Sequenz, die für diesen Zweck häufig eingesetzt wird.

Das Ergebnis der Kombination mehrerer Strahlen pro Pixel ist im folgenden Bild zu sehen:

Ausblick
Raytracing ist heute eine Technologie in ständiger Weiterentwicklung, doch das aktuelle Ergebnis ist sehr beeindruckend und dem Rendering per Rasterisierung überlegen. Alle modernen Grafik-Engines sind dabei, ihr Rendering auf Raytracing umzustellen. Der Integrationsaufwand ist jedoch hoch, und um ältere Grafikkarten weiterhin zu unterstützen, ist Raytracing nur eine Alternative. Viele moderne Engines setzen daher auf ein hybrides Rendering aus Rasterisierung und Raytracing.
Evergine ist die erste C#-Engine mit Raytracing-Integration. Unser Ziel ist es, unseren Nutzern die neuesten Grafiktechnologien für ihre industriellen Projekte und Produkte bereitzustellen.
Gemäß unserer Roadmap werden wir weiter an Raytracing arbeiten, um es in unserer High-Level-API nutzbar zu machen und auch eine Raytracing-Integration in Evergine Studio anzubieten.

