Commit 7fa28873 authored by Lukas Tietze's avatar Lukas Tietze

letzte Fixes

parent 6d231e30
......@@ -37,7 +37,8 @@ entstanden. Ein Stolperstein bei der Nutzung von ShaderC war die include-Mechani
\lstinline{#include} enth盲lt, nutzt der shaderC-Compiler eine vom Nutzer 眉bergebene Funktion, die
die einzuf眉gende Datei sucht. Diese Funktion wird standardm盲脽ig nicht bereitgestellt oder muss auf einem
unbekannten Weg aktiviert werden. Dies wurde jedoch erst nach einigem Debugging klar, da die Dokumentation von
ShaderC eher d眉rftig ausf盲llt.
ShaderC eher d眉rftig ausf盲llt. Nach dem Implementieren einer eigenen Funktion, funktioniert der
\lstinline{#include}-Befehl in Shadern nun wie gew眉nscht.
%
\subsection{Umbau zum Raytracer}
Nachdem nun ein funktionsf盲higer Rasterisierer in Vulkan realisiert war, war der n盲chste Schritt die
......
\label{s:aufbau}
\section{Aufbau der Anwendung}
\label{s:aufbau}
%
In diesem Abschnitt soll die entstandene Anwendung an sich beschrieben werden. Dabei soll prim盲r auf die
Aspekte der Grafikprogrammierung mit Vulkan eingegangen werden. Sofern in
......@@ -14,8 +14,8 @@ Es sei noch angemerkt, dass es viele Strukturen gibt, f眉r die es keine entsprec
gibt und bei denen es auch nicht sinnvoll erscheint eine solche einzuf眉hren. Daher wird f眉r Eigennamen an
vielen Stellen auch die Schreibweise in CamelCase gebraucht, wie sie beim Programmieren genutzt wird.
%
\label{ss:Vulkan Hpp}
\subsection{Vulkan-Hpp}
\label{ss:Vulkan Hpp}
Der gesamte Code wurde mit Vulkan-Hpp, den C++ Bindings f眉r Vulkan, geschrieben bzw. sp盲ter auf diese
Bindings umgestellt. Daher soll hier zun盲chst eine kurze 脺bersicht 眉ber diese Bindings eingeschoben werden.
Seit Version 1.0.24 ist Vulkan-Hpp ein Teil des Vulkan-SDK.
......@@ -36,13 +36,14 @@ Da es in C keine Standardwerte f眉r Argumente gibt und Vulkan nat眉rlich kompati
f眉r viele Parameter explizit Werte angegeben werden, die jedoch eigentlich nicht genutzt werden.
So ist der letzte Parameter der meisten
Vulkan-Funktionen ein Funktionspointer \lstinline{allocationCallback}, der immer als \lstinline{nullptr}
angegeben wird (und der auch f眉r spezielle Optimierungen 眉berhaupt n眉tzlich ist).
angegeben wird (und der auch nur f眉r spezielle Optimierungen 眉berhaupt n眉tzlich ist).
Mit den C++ Bindings gibt es jedoch Standardwerte f眉r Parameter, was die meisten
Funktionsaufrufe um ein oder mehr Parameter verk眉rzt. Dies ist in den Codeauschnitten \ref{c:createSwapChain}
und \ref{c:getQueueFamilyProperties} zu sehen.
\\
F眉r alle Array-盲hnlichen Parameter mussten ein Pointer und die L盲nge des Arrays 眉bergeben werden. Mit C++
Bindings kann f眉r derartige Parameter auch ein einzelner Wert oder ein \lstinline{std::vector} 眉bergeben werden.
F眉r alle Array-盲hnlichen Parameter mussten ein Pointer und die L盲nge des Arrays 眉bergeben werden. Mit den C++
Bindings wurden 脺berladungen f眉r diese Funktionen eingef眉hrt, bei denen f眉r derartige Parameter auch ein
einzelner Wert oder ein \lstinline{std::vector} 眉bergeben werden k枚nnen.
Dadurch l盲sst sich Vulkan wesentlich besser mit modernem C++ nutzen und viele Funktionen werden noch um einen
Parameter k眉rzer. Auf der anderen Seite - um ein Array von Daten abzurufen - musste die entsprechende
Funktion zweimal
......@@ -52,13 +53,13 @@ und ein zweites Mal um die tats盲chlichen Daten abzurufen. Ein Beispiel daf眉r i
\\
Ein weiteres Feature ist der sogenannte Dispatcher. Dieser stellt die Funktionspointer f眉r alle Funktionen in
Vulkan bereit. Der Dispatcher muss am Anfang des Programms, bevor irgendeine Vulkan-Funktion 眉ber die
C++-Bindings aufgerufen wird initialisiert werden. Au脽erdem muss er nach dem Erstellen der Instanz und dem
C++-Bindings aufgerufen wird, initialisiert werden. Au脽erdem muss er nach dem Erstellen der Instanz und dem
Erstellen des logischen Ger盲ts aktualisiert werden, um auch alle Funktionen f眉r Instanz- und
Ger盲teerweiterungen zu laden. Dies ist wesentlich komfortabler, als die Funktionspointer f眉r Erweiterungen
manuell anzufordern und zu speichern.
\\
Insgesamt f眉hren diese Bindings zu mehr Typsicherheit und wesentlich k眉rzeren Funktionsaufrufen
und erm枚glichen die Nutzung des Vulkan-SDK im Stile von modernem C++ anstelle im Stil von C.
und erm枚glichen die Nutzung des Vulkan-SDK im Stile von modernem C++ anstatt im Stil von C.
%
\begin{center}
\begin{figure}[htbp]
......@@ -116,14 +117,14 @@ this->queueFamilies = this->device.getQueueFamilyProperties();
\end{figure}
\end{center}
%
\label{ss:initialisierung}
\subsection{Initialisierung}
\label{ss:initialisierung}
Im Gegensatz zu OpenGl muss Vulkan explizit initialisiert werden. Es m眉ssen mehrere Handle zur Interaktion mit
Vulkan erzeugt werden. Au脽erdem m眉ssen die zu nutzende Hardware bestimmt und die aktiven Erweiterungen
festgelegt werden.
%
\label{p:instance}
\subsubsection{Instanz}
\label{p:instance}
\cgFuncRef{CreateInstance}
Um Vulkan zu initialisieren, muss zun盲chst eine Instanz (\lstinline{vk::Instance}) erzeugt werden.
Dieser lassen sich auch Informationen 眉ber die Anwendung mitgeben, wie Name und Version der Anwendung und der
......@@ -138,7 +139,7 @@ k枚nnen.
Au脽erdem werden hier die eben genannten Validierungsschichten aktiviert. Diese 眉bernehmen die Validierung aller
Funktionsaufrufe und sind nur optional, verursachen also keine Kosten, wenn sie nicht explizit aktiviert
werden. Dass Validierung in Vulkan \gquote{von Haus aus} m枚glich ist, aber nicht erzwungen wird, ist ein
weiterer Vorteil im Gegensatz zu OpenGL. Ohne Validierungsschichten werden Fehler in Vulkan kaum bemerkt und
Vorteil im Gegensatz zu OpenGL. Ohne Validierungsschichten werden Fehler in Vulkan kaum bemerkt und
resultieren in Abst眉rzen oder undefiniertem Verhalten.
Validierungsschichten sind jedoch nur ein Spezialfall vom allgemeinen
Schichten-Konzept in Vulkan. Es lassen sich zwischen einem Funktionsaufruf im Programm und dem
......@@ -161,7 +162,8 @@ entsteht:
\item Der Loader ruft die tats盲chliche Funktion im Treiber auf.
\end{enumerate}
%
Ein Nachteil der Validierungsschichten besteht darin, dass sie installiert werden m眉ssen, also nicht mit einem
Ein Nachteil der Validierungsschichten besteht darin, dass sie installiert werden m眉ssen, also nicht ohne
weiteres mit einem
Programm ausgeliefert werden k枚nnen. Allerdings wird mit dem Vulkan-SDK bereits die Validierungsschicht
\gquote{VK\_LAYER\_LUNARG\_standard\_validation} installiert, somit stellt die Verf眉gbarkeit
kaum ein Problem dar.
......@@ -171,8 +173,8 @@ auf die entsprechenden Artikel in der Vulkan-Spezifikation, was das Debugging re
\\
Nach diesem Schritt ist Vulkan initialisiert.
%
\label{ss:devices}
\subsection{Physisches und logisches Ger盲t}
\label{ss:devices}
Vulkan ben枚tigt eine explizite Auswahl der zu nutzenden Hardware und der aktiven Hardware-Erweiterungen
(\gquote{device extensions}). Diese unterscheiden sich von den Instanz-Erweiterungen, die bei der Initialisierung
von Vulkan angegeben wurden.
......@@ -180,8 +182,8 @@ In OpenGL werden diese Schritte nicht explizit ausgef眉hrt und Erweiterungen sin
Konzept von OpenGL, w盲hrend in Vulkan selbst die F盲higkeit, ein Bild auf einem Monitor darzustellen,
von einer Erweiterung 眉bernommen wird.
%
\label{p:surface}
\subsubsection{Surface}
\label{p:surface}
\cgFuncRef{CreateSurface}
Da Vulkan betriebssytemunabh盲ngig gestaltet ist und auch keine Konzepte von Fenstern oder gar Monitoren
beinhaltet, wird die Verbindung zu einem Fenster auf dem Bildschirm 眉ber eine Erweiterung gesteuert. Die
......@@ -190,8 +192,8 @@ wird jedoch komplett von GLFW 眉bernommen und man erh盲lt ein Objekt vom Typ \ls
das eine abstrakte Zeichenoberfl盲che darstellt. Dies ist jedoch nur der erste Teil zum Darstellen eines Bildes
in einem Fenster, der n盲chste Schritt ist die Erstellung einer SwapChain in Abschnitt \ref{p:swapchain}.
%
\label{p:physical_device}
\subsubsection{Physisches Ger盲t}
\label{p:physical_device}
\cgFuncRef{FindPhysicalDevice}
Zun盲chst muss noch die zu nutzende Hardware (\lstinline{vk::PhysicalDevice}) ausgew盲hlt werden.
Dazu werden Informationen 眉ber alle Vulkan-f盲higen
......@@ -207,24 +209,24 @@ Vereinfacht gesagt unterst眉tzt jede Queue-Familie verschiedene Operationen (z.B
Grafikkarte laden, etc.). Daher muss gepr眉ft werden, ob ein Ger盲t f眉r jede ben枚tigte Operation mindestens eine
Queue-Familie bereitstellt, die diese Operation unterst眉tzt.
%
\label{p:logical_device}
\subsubsection{Logisches Ger盲t}
\label{p:logical_device}
\cgFuncRef{CreateLogicalDevice}
Wenn die Hardware ausgew盲hlt ist, wird das logische Ger盲t (\lstinline{vk::Device}) erstellt, um mit dem
physischen Ger盲t zu interagieren. Diese Handle wird f眉r die Erstellung aller weiteren Ressourcen ben枚tigt.
Hier werden die zu aktivierenden Features und die ben枚tigten Queue-Familien festgelegt. Beides l盲sst sich
nicht im Nachhinein anpassen.
%
\label{ss:renderprozess}
\subsection{Aufbau des Renderprozesses}
\label{ss:renderprozess}
Als n盲chstes muss die Renderpipeline aufgebaut werden. Hierbei soll die Beschreibung von drei wichtigen
Komponenten vorgezogen werden, die st盲ndig ben枚tigt werden, n盲mlich Queues, CommandBuffer und Buffer.
%
\label{p:queue}
\subsubsection{Befehlsverarbeitung mit Queues}
\label{p:queue}
Das Konzept der Queue stellt einen wichtigen Unterschied zu OpenGL dar, obwohl OpenGL
intern sicherlich ein 盲hnliches System nutzt, da Funktionsaufrufe auch in OpenGL nicht unbedingt synchron
ausgef眉hrt werden). Eine Queue geh枚rt zu einer Queue-Familie, wodurch ihr Funktionsumfang festgelegt wird,
ausgef眉hrt werden. Eine Queue geh枚rt zu einer Queue-Familie, wodurch ihr Funktionsumfang festgelegt wird,
wie schon in Abschnitt \ref{p:physical_device} kurz angerissen wurde. Eine Queue wird genutzt um Befehle
asynchron auf der Grafikkarte auszuf眉hren. Diese Befehle stammen dabei aus einem CommandBuffer (siehe
Abschnitt \ref{p:commandbuffer}). Ein Programmierer hat keinen direkten Einfluss darauf, wann ein Befehl
......@@ -235,8 +237,8 @@ aktiven Auftr盲ge beendet sind. Das ist nicht sonderlich effizient, aber einfach
diesem kleinen Rahmen fast unmerklich. Eine bessere Implementierung best眉nde darin, erst auf die
Fertigstellung einer Operation zu warten, wenn das Ergebnis dieser Operation wirklich ben枚tigt wird.
%
\label{p:commandbuffer}
\subsubsection{Befehle aufzeichnen mit CommandBuffern}
\label{p:commandbuffer}
Viele Befehle werden in Vulkan nicht direkt an den Treiber geschickt und auch nicht direkt an eine Queue
眉bergeben, sondern zuvor in einem CommandBuffer (\lstinline{vk::CommandBuffer}) aufgezeichnet.
W盲hrend bei OpenGL in jedem Renderloop, je nach Komplexit盲t der Szene, eine gewisse Anzahl an Aufrufen gestartet
......@@ -248,14 +250,15 @@ verschiedene Anforderungen aufzeichnen, oder eine gr枚脽ere Aufgabe in mehrere C
von denen dann nur die ben枚tigten ausgef眉hrt werden.
\\
In diesem Programm reicht ein einziger CommandBuffer aus. Es werden allerdings mehrere identische Duplikate
erstellt, sodass jeder Frame einen CommandBuffer exklusiv nutzen kann, so wie es auch mit anderen Ressourcen
geschehen ist.
erstellt, damit, falls mehrere Frames gleichzeitig bearbeitet werden, jeder Frame einen CommandBuffer exklusiv
nutzen kann, so wie es auch mit anderen Ressourcen geschehen ist.
%
\label{p:buffer}
\subsubsection{Datenspeicherung mit Buffern}
\label{p:buffer}
Bei OpenGL l盲sst sich ein Buffer mit nur zwei Zeilen Code f眉llen
(\lstinline{glBindBuffer()}, gefolgt von \lstinline{glBufferData()}). In Vulkan ist dieser Vorgang wesentlich
komplexer. Vulkan unterscheidet zwischen verschiedenen Speichertypen, die jeweils verschiedene
komplexer, da die Speicherverwaltung in der Hand des Programmierers liegt. Zun盲chst unterscheidet Vulkan
zwischen verschiedenen Speichertypen, die jeweils verschiedene
Eigenschaften haben. Die Eigenschaften werden durch \lstinline{vk::MemoryPropertyFlagBits} angezeigt. Die
wichtigsten sind
%
......@@ -295,13 +298,13 @@ Dieser Vorgang hei脽t Buffer-Staging. Zun盲chst muss der Speicher mittels Memory
\lstinline{std::memcpy} in diesen Speicher kopiert
wurden, muss das Bearbeiten des Speichers explizit mit \lstinline{vk::Device::unmapMemory()} beendet werden. Wenn nun
alle Daten in den Host-Speicher kopiert sind, m眉ssen weitere Buffer erzeugt, ausreichend Device-Speicher
alloziert und an diese Buffer gebunden werden. Auch hier lie脽e sich das obengenannte optimierte
alloziert und an diese Buffer gebunden werden. Auch hier lie脽e sich das oben genannte optimierte
Vorgehen einsetzen. Danach m眉ssen alle Buffer vom Host-Speicher in den Device-Speicher kopiert
werden. Diese Operationen m眉ssen zun盲chst in einem CommandBuffer aufgezeichnet und dann an eine Queue
眉bergeben werden.
%
\label{p:queues}
\subsubsection{Queue-Handles}
\label{p:queues}
\cgFuncRef{CreateQueues}
Nachdem bei der Erstellung des logischen Ger盲ts alle ben枚tigten Queue-Familien angegeben wurden, werden in
diesem Schritt Handles zu den Queues der jeweiligen Familien erstellt. Es werden 4 Queues ben枚tigt:
......@@ -313,8 +316,8 @@ diesem Schritt Handles zu den Queues der jeweiligen Familien erstellt. Es werden
(siehe Abschnitt \ref{p:accelerationstructures}).
\end{itemize}
%
\label{p:swapchain}
\subsubsection{SwapChain}
\label{p:swapchain}
\cgFuncRef{CreateSwapChain}
Die SwapChain ist der zweite Teil der Infrastruktur, die f眉r die Interaktion von Vulkan mit einem
tats盲chlichen Fenster n枚tig ist. Sie steuert die Darstellung von Frames auf dem Bildschirm und stellt
......@@ -339,8 +342,8 @@ FIFO-Warteschlange genutzt.
\\
Zuletzt werden noch die Handles (\lstinline{vk::Image}) zu den Bildern der SwapChain abgerufen.
%
\label{p:imageviews}
\subsubsection{ImageViews}
\label{p:imageviews}
\cgFuncRef{CreateImageViews}
Die SwapChain erstellt und verwaltet die Bilder, mit denen sie arbeitet, selbst, in diesem Schritt werden
lediglich die Handles (\lstinline{vk::ImageView}) erzeugt um auf diese Bilder zuzugreifen. Im Gegensatz zu den
......@@ -350,8 +353,8 @@ Beispiel kann ein \lstinline{vk::Image} aus mehreren MipMap-Leveln bestehen. Dan
\lstinline{vk::ImageView} f眉r jedes MipMap-Level erstellt werden um den Zugriff auf diesen Teil des Bildes
zu regeln.
%
\label{p:uniformbuffers}
\subsubsection{UniformBuffers}
\label{p:uniformbuffers}
\cgFuncRef{CreateUniformBuffers}
Ein UBO (Uniform Buffer Object) enth盲lt Daten, die f眉r die Shader schnell zug盲nglich sein m眉ssen. UBOs sind
im allgemeinen schneller als SSBOs (Shader Storage Buffer Object), jedoch in ihrer Gr枚脽e begrenzt und sie
......@@ -399,8 +402,8 @@ werden, erheblich von OpenGL, wie sp盲ter in Abschnitt \ref{p:descriptorsets} no
Art, wie UBOs in OpenGL erstellt und mit Daten gef眉llt werden, unterscheidet sich von Vulkan, wie schon in
Abschnitt \ref{p:buffer} zu sehen war.
%
\label{p:commandpool}
\subsubsection{CommandPool}
\label{p:commandpool}
\cgFuncRef{CreateCommandPool}
CommandBuffer (siehe \ref{p:commandbuffer}) werden immer aus einem CommandPool (\lstinline{vk::CommandPool})
heraus alloziert. Der Pool verwaltet den Speicher der CommandBuffer, was das Management vieler CommandBuffer
......@@ -417,8 +420,8 @@ erstellt:
F眉r die Pr盲sentation von Bildern (mit Queue \lstinline{presentationQueue}) muss kein extra CommandBuffer
erstellt werden, da auf dieser Queue keine direkten Befehle ausgef眉hrt werden.
%
\label{p:model}
\subsubsection{Model}
\label{p:model}
\cgFuncRef{TryLoadModel}
Danach wird mit der Bibliothek Assimp die Szene geladen. Alle Daten werden zun盲chst in ein eigenes Format
konvertiert, das grob an das Datenformat von Assimp angelehnt ist. Es kennt Meshes (also
......@@ -436,11 +439,11 @@ Geometrien), Materialien und Objektinstanzen:
Speicheraufwand zu erzeugen.
\end{itemize}
%
F眉r die Objektinstanzen wird noch die Inverse Transformationsmatrix berechnet und dann werden all diese Daten
F眉r die Objektinstanzen wird noch die transponierte Inverse der Transformationsmatrix berechnet und dann werden all diese Daten
in eigene Buffer geladen und in Buffer mit Device-Speicher kopiert, wie in Abschnitt \ref{p:buffer} beschrieben.
%
\label{p:descriptorsetlayout}
\subsubsection{DescriptorSetLayout}
\label{p:descriptorsetlayout}
\cgFuncRef{CreateDescriptorSetLayout}
Ein DescriptorSetLayout beschreibt alle Datenbindungen der Pipeline bzw. der genutzten Shader.
F眉r jede Bindung werden der Typ der gebundenen Ressource, die Shaderstufe(n), in denen die Ressource verf眉gbar
......@@ -457,8 +460,8 @@ werden Rendervorg盲nge auch statischer, wobei man argumentieren kann, dass Rende
Dynamik ben枚tigen. Au脽erdem k枚nnen beliebig viele DescriptorSetLayouts erstellt werden, wodurch keine echte
Limitierung, wohl aber ein gewisser Programmieraufwand entsteht.
%
\label{p:descriptorpool}
\subsubsection{DescriptorPool}
\label{p:descriptorpool}
\cgFuncRef{CreateDescriptorPool}
Ein DescriptorPool erf眉llt eine 盲hnliche Funktion wie ein CommandPool aus Abschnitt \ref{p:commandpool}.
Im Gegensatz zu einem CommandPool muss hier die Gr枚脽e des Pools im Voraus bestimmt werden.
......@@ -466,8 +469,8 @@ F眉r jeden Eintrag im DescriptorSetLayout m眉ssen sp盲ter ausreichend viele Sets
(ein Set pro gleichzeitig m枚glichem Frame f眉r jeden Eintrag). Es ist nicht m枚glich einen DescriptorPool sp盲ter
noch zu erweitern.
%
\label{p:accelerationstructures}
\subsubsection{AccelerationStructures}
\label{p:accelerationstructures}
\cgFuncRef{CreateAccelerationStructures}
Die einfachste Variante um beim Raytracing einen Schnitt zwischen einem Lichtstrahl und einem Objekt der Szene
festzustellen, ist einfach alle Dreiecke der Szene zu testen. Dies kostet jedoch schon bei sehr einfachen Modellen
......@@ -514,17 +517,17 @@ Die Erstellung von AccelerationStructures l盲uft vereinfacht betrachtet wie folg
\item CommandBuffer an Queue 眉bergeben und ausf眉hren
\end{enumerate}
%
\label{p:descriptorsets}
\subsubsection{DescriptorSets}
\label{p:descriptorsets}
\cgFuncRef{CreateDescriptorSets}
W盲hrend ein DescriptoreSetLayout (siehe Abschnitt \ref{p:descriptorsetlayout}) die Art von Bindungen beschreibt,
stellt ein DescriptorSet (\lstinline{vk::DescriptoreSet}) eine Sammlung von tats盲chlichen Ressourcenbindungen
W盲hrend ein DescriptorSetLayout (siehe Abschnitt \ref{p:descriptorsetlayout}) die Art von Bindungen beschreibt,
stellt ein DescriptorSet (\lstinline{vk::DescriptorSet}) eine Sammlung von tats盲chlichen Ressourcenbindungen
dar. In diesem Schritt wird festgelegt, welche konkreten Ressourcen an Shader gebunden werden. F眉r jeden
gleichzeitig m枚glichen Frame wird ein eigenes DescriptorSet erstellt. All diese Sets werden aus dem zuvor
angelegten DescriptorPool alloziert.
%
\label{p:pipeline}
\subsubsection{Pipeline}
\label{p:pipeline}
\cgFuncRef{CreatePipeline}
In diesem Schritt wird die Raytracing-Pipeline erstellt, die alle Shader, UBOs, SSBOs und sonstigen Ressourcen
verkn眉pft. Dazu m眉ssen zun盲chst die Shader (\lstinline{vk::ShaderModule}) geladen werden. In diesem Programm
......@@ -533,8 +536,8 @@ entweder direkt SPIR-V-Dateien geladen werden oder es k枚nnen GLSL-Dateien einge
Dazu wurde ShaderC in das Programm integriert um GLSL-Shader zur Laufzeit zu SPIR-V kompilieren zu k枚nnen.
\\
Nun wird zun盲chst das Pipeline-Layout (\lstinline{vk::PipelineLayout}) erstellt, das die zu nutzenden
DescriptoreSetLayouts und Push-Konstanten festlegt. Eine Push-Konstante ist eine sehr kleine Datenmenge, die
ohne Buffer in den Shader geladen werden kann. Im Programm wird lediglich ein DescriptoreSetLayout genutzt.
DescriptorSetLayouts und Push-Konstanten festlegt. Eine Push-Konstante ist eine sehr kleine Datenmenge, die
ohne Buffer in den Shader geladen werden kann. Im Programm wird lediglich ein DescriptorSetLayout genutzt.
Push-Konstanten werden gar nicht genutzt, da diese nicht mit voraufgezeichneten CommandBuffern funktionieren.
Im CommandBuffer wird nicht etwa die Adresse der Daten gespeichert, sondern die Daten selbst. Um diese zu
盲ndern muss also der CommandBuffer neu aufgezeichnet werden.
......@@ -551,8 +554,8 @@ als GLSL geladen und dann von OpenGL kompiliert. Das ist hier 盲hnlich, nur, das
Vulkan, sondern eine externe Bibliothek ist. Das Linken von mehreren Shadern zu einem Shaderprogramm in OpenGL
ist 盲hnlich dem Binden von Shadern an die Pipeline in Vulkan. Dieser Schritt ist also in beiden APIs 盲hnlich.
%
\label{p:sbt}
\subsubsection{ShaderBindingTable}
\label{p:sbt}
\cgFuncRef{CreateShaderBindingTable}
Bei OpenGL werden meist nur die ben枚tigten Ressourcen gebunden, bevor ein Renderlauf stattfindet. Ein
typischer Ablauf, der f眉r jedes Objekt der Szene wiederholt wird, w盲re zum Beispiel
......@@ -586,8 +589,9 @@ verschiedene Objekte mit verschiedenen Materialien grundverschiedene Shader ben
In OpenGl gibt es keinen vergleichbaren Schritt, allerdings ist dieser Schritt auch spezifisch f眉r eine
Raytracing-Anwendung und w眉rde bei einem Rasterisierer mit Vulkan ebenfalls nicht vorkommen.
%
\label{p:sync}
\subsubsection{SyncObjects}
\label{p:sync}
\cgFuncRef{CreateSyncObjects}
Ein wichtiger Vorteil von Vulkan im Vergleich zu OpenGL besteht in der manuellen Synchronisation der
Operationen. Damit l盲sst sich Vulkan auch gut parallelisieren.
Um mehrere Frames gleichzeitig bearbeiten zu k枚nnen ist manuelle Synchronisation n枚tig.
......@@ -597,8 +601,8 @@ In OpenGL entscheidet die Implementierung dar眉ber ob mehrere Frames gleichzeiti
wie alle eingehenden Befehle synchronisiert werden. Die manuelle Synchronisation von Operationen erscheint
als gro脽e St盲rke von Vulkan, da sich die API auch aus mehreren Threads heraus nutzen l盲sst.
%
\label{ss:shader}
\subsection{Shader}
\label{ss:shader}
In diesem Abschnitt soll der wohl wichtigste Teil des Raytracings beleuchtet werden, n盲mlich die Shader
selbst. F眉r das Raytracing sind f眉nf Arten von Shadern von Bedeutung, jedoch werden nur die ersten drei genutzt.
%
......@@ -681,8 +685,8 @@ kugelf枚rmige Objekte enth盲lt, k枚nnte ein Intersection-Shader genutzt werden,
Strahls mit diesen Kugeln zu bestimmen, ohne dass diese Kugeln durch Dreiecke dargestellt werden m眉ssten.
Das Programm nutzt nur den eingebauten Intersection-Shader, der Schnittpunkte mit Dreiecken berechnet.
%
\label{ss:userinteraction}
\subsection{Nutzerinteraktion und Beispielprogramm}
\label{ss:userinteraction}
Die bis hierher beschriebene Anwendung erstellt, verwaltet und abstrahiert den Vulkan-Kontext. Die
Nutzerinteraktion wird von der Klasse \lstinline{lib::App} bereitgestellt. Diese Klasse verwaltet das Fenster
und verarbeitet Maus- und Tastatureingaben mithilfe von GLFW. Dieser Teil des Programms wurde nahezu
......
......@@ -22,8 +22,9 @@ werden keine zus盲tzlichen Texturen f眉r diese Effekte ben枚tigt. In diesem Beis
Reflexion oder Refraktion umgesetzt, dazu w盲re jedoch nur eine Anpassung der Shader und eventuell der
maximalen Rekursionstiefe notwendig.
\\
Raytracing kann keine Instanziierung im klassischen Sinne vollbringen, irgendwo \textit{m眉ssen}
Geometrieinformationen dupliziert werden (und wenn es nur einige Bounding-Boxen sind). Raytracing ist
Ein weiterer Nachteil von Raytracing ist, dass keine Instanziierung von Geometrie im klassischen Sinne m枚glich ist,
irgendwo \textit{m眉ssen} Geometrieinformationen dupliziert werden (und wenn es nur einige Bounding-Boxen
sind). Raytracing ist
allgemein sehr Speicherintensiv, da alle Daten einer Szene (Shader, Materialien, Lichter, Geometrien,
Szenenbeschreibung und Kamerainformationen) gleichzeitig abrufbar sein m眉ssen. Raytracing fordert auch
aufw盲ndigere Berechnungen als Rasterisierung, mit Hardwarebeschleunigung (z.B. auf einer GeForce RTX 2060)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment