...
 
Commits (4)
......@@ -70,6 +70,7 @@ add_library(
src/Lib/src/VkUtil/VkResult.cpp
src/Lib/src/VkUtil/Buffer.cpp
src/Lib/src/VkUtil/Texture.cpp
src/Lib/src/VkUtil/RenderTarget.cpp
src/Lib/src/VkUtil/StagedBuffer.cpp
src/Lib/src/VkUtil/OneTimeCommandBuffer.cpp
src/Lib/src/VkUtil/StbImageImpl.cpp
......
......@@ -4,7 +4,7 @@
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D texSampler;
layout(binding = 0) uniform sampler2D texSampler[4];
void main() {
vec2 offsets[9] = {
......@@ -25,12 +25,12 @@ void main() {
1.0 / 84.0, 4.0 / 84.0, 1.0 / 84.0,
};
vec2 relativePixelSize = vec2(1.0) / textureSize(texSampler, 0);
vec2 relativePixelSize = vec2(1.0) / textureSize(texSampler[0], 0);
vec4 samples[9];
for(int i = 0; i < 9; i++) {
samples[i] = texture(texSampler, texCoord + offsets[i] * relativePixelSize);
samples[i] = texture(texSampler[0], texCoord + offsets[i] * relativePixelSize);
}
vec3 edge = vec3(0);
......@@ -50,6 +50,6 @@ void main() {
res = l * blur + (1 - l) * samples[5].rgb;
color = vec4(vec3(samples[5].a * 0.5), 1.0);
// color = vec4(res, 1.0);
// color = vec4(vec3(samples[5].a * 0.5), 1.0);
color = vec4(res, 1.0);
}
\ No newline at end of file
\section{Bewertung}
Die beiden Umsetzungen sollen danach entsprechend der folgenden Kriterien bewertet werden:
Die beiden Umsetzungen sollen danach entsprechend der folgenden Kriterien bewertet und mit bestehenden
Verfahren verglichen werden.
%
\paragraph{Qualit├Ąt:}
\begin{enumerate}
......@@ -15,3 +16,9 @@ Die beiden Umsetzungen sollen danach entsprechend der folgenden Kriterien bewert
\item Gibt es noch Optimierungspotenzial?
\end{enumerate}
%
\paragraph{Vergleich zu rasterbasierten Techniken:}
\begin{enumerate}
\item Liefert das Verfahren optisch bessere/detailliertere Ergebnisse?
\item Sind die Performancekosten in Bezug auf das erreichte Ergebnis mit bestehenden Verfahren
vergleichbar? Wie ist das \gquote{Kosten-Nutzen-Verh├Ąltnis}?
\end{enumerate}
\ No newline at end of file
......@@ -9,14 +9,13 @@
\item Hardwareunterst├╝tzung
\end{enumerate}
%
\item Die Rendergleichung und ihre Umsetzung mittels Raytracing
\item Die Rendergleichung und ihre (ann├Ąhernde) Umsetzung mittels Raytracing
\item Implementierungsgrundlagen eines Raytracers mit Vulkan \& NVIDIA-Erweiterung
%
\item Darstellung von Strahlenb├╝scheln
\begin{enumerate}
\item Physikalische Grundlagen
\item Bisherige Forschung
%
\item Umsetzung durch Raytracing im Medium
%
\begin{enumerate}
......@@ -42,10 +41,4 @@
\end{enumerate}
%
\item Anh├Ąnge, Quellen, etc.
\end{enumerate}
%
% http://graphics.cs.aueb.gr/graphics/docs/papers/GraphiCon09_PapadopoulosPapaioannou.pdf
% https://graphics.stanford.edu/courses/cs348b-03/papers/veach-chapter9.pdf
% http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.671.766&rep=rep1&type=pdf
% https://nvpro-samples.github.io/vk_raytracing_tutorial/vkrt_tuto_intersection.md.html#environmentsetup/intersectionshader
% https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
\ No newline at end of file
\end{enumerate}
\ No newline at end of file
......@@ -12,9 +12,9 @@ extrem bereichern.
\\
Der Effekt l├Ąsst sich auch gut w├Ąhrend der Morgen- und Abendd├Ąmmerung beobachten.
Auch unter Wasser oder wenn die Sonne in einen nebligen Wald scheint, l├Ąsst sich der Effekt
beobachten. Ein k├╝nstlich erzeugtes Beispiel ist die Sichtbarmachung de Verlaufs eines Lasers durch Staub
beobachten. Ein k├╝nstlich erzeugtes Beispiel ist die Sichtbarmachung des Verlaufs eines Lasers durch Staub
oder Puder. Der Effekt l├Ąsst sich auch umgekehrt beobachten, das hei├čt, dass der Gro├čteil eines Mediums von
Strahlenb├╝scheln erf├╝llt ist, dadurch heller aussieht und es aussieht als w├╝rden Objekte Schatten im Medium
Strahlenb├╝scheln erf├╝llt ist, dadurch heller wirkt und es aussieht als w├╝rden Objekte Schatten im Medium
erzeugen. Hieraus folgt auch die ├ťberlegung, dass die Streuung von Licht im Medium praktisch immer auftritt,
jedoch normalerweise unbemerkt bleibt, weil das Licht an jedem Punkt des Mediums ├Ąhnlich gestreut wird.
......@@ -31,4 +31,4 @@ Dieser Effekt soll nun computergrafisch dargestellt, also in eine Szene gerender
nat├╝rlich sehr einfache M├Âglichkeiten, wie eine zuvor erzeugte Textur an einen bestimmten Platz zu rendern und
sehr aufw├Ąndige wie die physikalisch plausible Berechnung von Lichtbrechungen.\\
Das Ziel dieser Arbeit soll die Entwicklung eines Algorithmus' sein, der den oben besprochenen Effekt
physikalisch plausibel in beliebigen Szenen darstellen kann.
\ No newline at end of file
physikalisch plausibel in beliebigen Szenen darstellen kann und dazu prim├Ąr Raytracing nutzt.
\ No newline at end of file
......@@ -43,14 +43,14 @@ Berechnung im Lightspace vorgenommen und nicht mittels Raytracing ausgef├╝hrt.
In diesem Video sagt Eric Haines in Bezug auf grafische Effekte beim Raytracing:
%
\begin{quote}
You can also atmospheric effects, so if, say you have a beam of light, you can do a thing called ray
You can also do atmospheric effects, so if, say you have a beam of light, you can do a thing called ray
marching, where the ray hits the beam, marches through it and light scattering in and light scattering out
and so and you just kind of walk through that thing and sample it as you go. And you can get these nice beams
of light, godrays, kind of effects.
\end{quote}
%
\paragraph{Anmerkung:} Der Begriff \gquote{ray marching} ist nicht eindeutig.
Prinzipiell beschreibt es - wie der Name vermuten l├Ąsst - eine Familie von Techniken, bei denen eine Strahl
Prinzipiell beschreibt es - wie der Name vermuten l├Ąsst - eine Familie von Techniken, bei denen ein Strahl
abgetastet wird, bzw. bei denen entlang eines Strahls eine Funktion berechnet wird. H├Ąufig wird die Technik
genutzt um den Schnittpunkt eines Strahls mit der Szene zu bestimmen (z.B. wenn die Objekte der Szene nicht
als Dreiecke sondern als mathematische Definitionen vorliegen).
......@@ -80,18 +80,36 @@ ausgewertet und f├╝r den gesamten Block genutzt.
%
\subsection{Interactive Volumetric Shadows in Participating Media with Single-Scattering}
\label{interactiveVolumetricShadowsInParticipatingMediaWithSingleScattering}
\paragraph{Quelle:}C. Wyman and S. Ramsey,
\gquote{Interactive volumetric shadows in participating media with single-scattering,} 2008 IEEE Symposium on
\paragraph{Quelle:}C. Wyman and S. Ramsey,
\gquote{Interactive volumetric shadows in participating media with single-scattering,} 2008 IEEE Symposium on
Interactive Ray Tracing, Los Angeles, CA, 2008, pp. 87-92, doi: 10.1109/RT.2008.4634627.
\paragraph{Technik}
Wyman und Ramsey nutzen Raymarching wie T├│th und Umenhoffer (siehe
\ref{ss:realTimeVolumetricLightingInParticipatingMedia}), verbessern das Verfahren jedoch durch den Einsatz
Wyman und Ramsey nutzen Raymarching wie T├│th und Umenhoffer (siehe
\ref{ss:realTimeVolumetricLightingInParticipatingMedia}), verbessern das Verfahren jedoch durch den Einsatz
von Schattenvolumen. Dahinter steht die ├ťberlegung, dass Bereiche im Schatten keinen Beitrag zum eingestreuten
Licht liefern und es daher reicht, die beleuchteten Bereiche zu sampeln. Diese Technik k├Ânnte auch helfen,
Licht liefern und es daher reicht, die beleuchteten Bereiche zu sampeln. Diese Technik k├Ânnte auch helfen,
beim Einsatz mit Raytracing die ben├Âtigten Sampel zu reduzieren. Jedoch erzeugt das Rendern von
Schattenvolumen auch gewisse Kosten und ist bei Szenen mit detaillierten Szenen (wie z.B. Gartenz├Ąune) wenig
n├╝tzlich. In diesem Fall, so Wyman und Ramsey, verkommt der Algorithmus zu herk├Âmmlichem Raymarching. Ein
Schattenvolumen auch gewisse Kosten und ist bei detaillierten Szenen mit vielen abwechselnd beleuchteten und
beschatteten Bereichen (wie z.B. entlang eines Gartenzaunes) wenig
n├╝tzlich. In diesem Fall, so Wyman und Ramsey, verkommt der Algorithmus zu herk├Âmmlichem Raymarching. Ein
anderer Aspekt ist, dass detaillierte Schatten gerade eine St├Ąrke von Raytracing sind und der Einsatz von
Schattenvolumen diesen Vorteil ignorieren w├╝rde. Jedoch l├Ąsst sich dieser Ansatz vielleicht irgendwie
einsetzen um die Sample entlang eines Strahls \gquote{intelligenter} zu verteilen und - wie im Paper
Schattenvolumen diesen Vorteil ignorieren w├╝rde. Jedoch l├Ąsst sich dieser Ansatz vielleicht irgendwie
einsetzen um die Sample entlang eines Strahls \gquote{intelligenter} zu verteilen und - wie im Paper
vorgestellt - weniger redundante Samples auszuwerten.
%
\subsubsection{Raytracing Gems}
\label{ss:RaytracingGems}
\paragraph{Quelle:} Eric Haines and Tomas Akenine-M├Âller (2019). Ray Tracing Gems. Apress.
\paragraph{Homepage:}\url{https://www.realtimerendering.com/raytracinggems/}
\paragraph{Inhalt:}
Das Buch fokussiert sich auf allgemeine (jedoch weit fortgeschrittene) Techniken rund ums Raytracing und
bietet damit eine wichtige Quelle. Nach einem ersten ├ťberfliegen existiert kein Kapitel ├╝ber das Rendern von
Strahlenb├╝scheln. Wichtig sind jedoch die dort aufgef├╝hrten Techniken zur Reduktion der genutzten Strahlen
und diverse Ausf├╝hrungen zu hybriden Rendertechniken. Dabei sticht vor allem die temporale
Reprojektion heraus, dies ist eine Technik, bei der der Inhalt von fr├╝heren Bildern zum Rendern des aktuellen
Bildes genutzt wird. Eine dargestellte Anwendung (Kapitel 13 \gquote{Ray Traced Shadows: Maintaining
Real-Time Frame Rates}) bestand darin, aus alten Bildern zu bestimmen, welche Teile einer Szene im Licht,
im Kernschatten, bzw. im Halbschatten liegen. F├╝r Bereiche, die im Kernschatten oder im Licht liegen reicht
es pro Pixelgruppe einen \gquote{Kontrollstrahl} zu nutzen, f├╝r Pixel im Halbschatten werden mehrere Strahlen
pro Pixel genutzt um diese Bereiche realistischer zu rendern. Eine Technik die sich auch nutzen lie├če
um die Anzahl von Sampeln pro Frame in einem Medium zu reduzieren.
......@@ -55,8 +55,8 @@ Vorgehen ist das folgende:
%
Dabei ist nat├╝rlich vor allem auf die Performance zu achten. Je mehr Schattenf├╝hler genutzt werden, desto
genauer wird das Ergebnis, desto teurer wird jedoch auch die Berechnung. Auch f├╝r die genaue Art der
Verrechnung der einzelnen Samples muss eine Formel gesucht werden. Optimierungspotenzial liegt in redundanten
Schattenf├╝hlern, bzw. viele ├Ąhnliche Schattenf├╝hlern.
Verrechnung der einzelnen Samples muss eine Formel gesucht werden. Optimierungspotenzial liegt in der
Reduzierung redundanter bzw. sehr ├Ąhnlicher Schattenf├╝hler.
\subsection{Umsetzung mittels Berechnung von der Lichtquelle aus}
Der zweite L├Âsungsansatz verfolgt einen ├Ąhnlichen Ansatz wie Photon-Mapping, indem versucht wird die
......
......@@ -24,6 +24,7 @@
#include "VkUtil/TopLevelAccelerationStructure.hpp"
#include "VkUtil/VkUtil.hpp"
#include "VkUtil/Texture.hpp"
#include "VkUtil/RenderTarget.hpp"
#include "imgui_impl_vulkan.h"
namespace lib
......@@ -191,7 +192,6 @@ namespace lib
const uint32_t lightSources = 5;
const uint32_t vertices = 6;
const uint32_t indices = 7;
const uint32_t dummyTexture = 8;
} const descriptorBindings;
struct
......@@ -203,6 +203,9 @@ namespace lib
} shaderOffsets;
std::unique_ptr<lib::Buffer> shaderBindingTableBuffer;
const uint32_t temporalInterpolationCount = 4;
uint32_t temporalInterpolationImageIndex = 0;
std::vector<lib::TemporalInterpolationFrame> temporalInterpolationFrames;
bool modelLoaded;
bool shadersLoaded;
......@@ -288,7 +291,7 @@ namespace lib
bool IsOk() const;
bool IsRecoverable() const;
void UpdateCommandBuffer(uint32_t imageIndex);
void UpdateCommandBuffer(uint32_t imageIndex, uint32_t temporalInterpolationImageIndex);
void BeginFrame();
void DrawFrame(lib::time_diff_t diff);
void EndFrame();
......
......@@ -2,7 +2,7 @@
#include <memory>
#include "VkUtil/Texture.hpp"
#include "VkUtil/RenderTarget.hpp"
#include "GlfwAndVulkan.hpp"
#include "VkUtil/StagedBuffer.hpp"
......@@ -10,18 +10,23 @@ namespace lib
{
struct Frame
{
std::unique_ptr<lib::StagedBuffer> ubo;
vk::CommandPool commandPool;
vk::CommandBuffer commandBuffer;
vk::Fence inFlightFence;
vk::DescriptorSet raytracingDescriptorSet;
vk::DescriptorSet rasterizationDescriptorSet;
vk::Image swapChainImage;
vk::ImageView swapChainImageView;
vk::Framebuffer swapChainFramebufferForRasterizationRenderPass;
vk::Framebuffer swapChainFramebufferForImGui;
};
std::unique_ptr<lib::Texture> raytracingTexture;
struct TemporalInterpolationFrame
{
vk::DescriptorSet raytracingDescriptorSet;
vk::DescriptorSet rasterizationDescriptorSet;
std::unique_ptr<lib::RenderTarget> raytracingRenderTarget;
// TODO geh├Ârt eigentlich zum Frame, nicht zum TemporalInterpolationFrame
std::unique_ptr<lib::StagedBuffer> ubo;
};
} // namespace lib
#pragma once
#include "GlfwAndVulkan.hpp"
#include "VkUtil/Texture.hpp"
#include <vector>
#include <map>
namespace lib
{
class RenderTarget : public lib::Texture
{
private:
std::map<vk::RenderPass, vk::Framebuffer> framebuffersByRenderPass;
vk::Semaphore semaphore;
void CreateFramebufferForRenderPass(vk::RenderPass renderPass);
public:
RenderTarget(CgContext *parent, uint32_t width, uint32_t height, const lib::TextureCreateInfo &textureCreateInfo);
RenderTarget(const RenderTarget &copy) = delete;
RenderTarget(RenderTarget &&move) = delete;
~RenderTarget();
RenderTarget &operator=(const RenderTarget &copy) = delete;
RenderTarget &operator=(RenderTarget &&move) = delete;
const vk::Semaphore &GetSemaphore() const;
const vk::Framebuffer &GetFrameBufferForRenderPass(const vk::RenderPass &renderpass) const;
void CreateFramebuffersForRenderPasses(const std::initializer_list<vk::RenderPass> &renderpasses);
template <typename TForwardIt>
void CreateFramebuffersForRenderPasses(TForwardIt begin, TForwardIt end)
{
for (; begin != end; ++begin)
{
this->CreateFramebufferForRenderPass(*begin);
}
}
};
} // namespace lib
......@@ -69,6 +69,9 @@ namespace lib
vk::DeviceMemory memory;
vk::Sampler sampler;
uint32_t width;
uint32_t height;
protected:
CgContext *parent;
......@@ -137,16 +140,20 @@ namespace lib
Texture(Texture &&) = delete;
Texture(const Texture &) = delete;
~Texture();
Texture &operator=(Texture &&) = delete;
Texture &operator=(const Texture &) = delete;
const vk::Image &GetHandle() const;
const vk::ImageView &GetView() const;
const vk::Sampler &GetSampler() const;
Texture &operator=(Texture &&) = delete;
Texture &operator=(const Texture &) = delete;
uint32_t GetHeight() const;
uint32_t GetWidth() const;
}; // namespace lib
} // namespace lib
......@@ -158,7 +158,7 @@ bool lib::CgContext::TryCreateRasterizerPipeline()
void lib::CgContext::CreateRasterizationDescriptorSets()
{
const auto count = static_cast<uint32_t>(this->frames.size());
const auto count = static_cast<uint32_t>(this->temporalInterpolationFrames.size());
std::vector<vk::DescriptorSetLayout> layouts(count, this->rasterizationStep.descriptorSetLayout);
......@@ -170,27 +170,41 @@ void lib::CgContext::CreateRasterizationDescriptorSets()
auto sets = this->logicalDevice.allocateDescriptorSets(allocateInfo);
auto setsIt = std::begin(sets);
for (auto &frame : this->frames)
for (size_t i = 0; i < count; i++)
{
auto &frame = this->temporalInterpolationFrames[i];
frame.rasterizationDescriptorSet = *setsIt++;
vk::DescriptorImageInfo rtImageInfo;
rtImageInfo.imageLayout = vk::ImageLayout::eGeneral;
rtImageInfo.imageView = frame.raytracingTexture->GetView();
rtImageInfo.sampler = frame.raytracingTexture->GetSampler();
std::vector<vk::DescriptorImageInfo> imageInfos;
std::vector<vk::WriteDescriptorSet> writes;
// rtImageInfo.imageView = this->dummyTexture->GetView();
// rtImageInfo.sampler = this->dummyTexture->GetSampler();
imageInfos.reserve(temporalInterpolationCount + 1);
writes.reserve(temporalInterpolationCount + 1);
vk::WriteDescriptorSet rtImageWrite;
rtImageWrite.descriptorCount = 1;
rtImageWrite.descriptorType = vk::DescriptorType::eCombinedImageSampler;
rtImageWrite.dstArrayElement = 0;
rtImageWrite.dstBinding = 0;
rtImageWrite.pImageInfo = &rtImageInfo;
rtImageWrite.dstSet = frame.rasterizationDescriptorSet;
for (uint32_t j = 0; j < this->temporalInterpolationCount + 1; j++)
{
auto frameIndex = this->temporalInterpolationCount > 0
? (this->temporalInterpolationCount + i - j) % this->temporalInterpolationCount
: i;
auto &backFrame = this->temporalInterpolationFrames[frameIndex];
auto &info = imageInfos.emplace_back();
info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
info.imageView = backFrame.raytracingRenderTarget->GetView();
info.sampler = backFrame.raytracingRenderTarget->GetSampler();
auto &imageWrite = writes.emplace_back();
imageWrite.descriptorCount = 1;
imageWrite.descriptorType = vk::DescriptorType::eCombinedImageSampler;
imageWrite.dstArrayElement = j;
imageWrite.dstBinding = 0;
imageWrite.pImageInfo = &info;
imageWrite.dstSet = frame.rasterizationDescriptorSet;
}
this->logicalDevice.updateDescriptorSets(rtImageWrite, {});
this->logicalDevice.updateDescriptorSets(writes, {});
}
lib::log::Info("Successfully created rasterization descriptor sets!");
......@@ -198,10 +212,10 @@ void lib::CgContext::CreateRasterizationDescriptorSets()
void lib::CgContext::CreateRasterizationDescriptorPool()
{
const auto count = static_cast<uint32_t>(this->frames.size());
const auto count = static_cast<uint32_t>(this->temporalInterpolationFrames.size());
std::vector<vk::DescriptorPoolSize> poolSizes{
{vk::DescriptorType::eCombinedImageSampler, count},
{vk::DescriptorType::eCombinedImageSampler, count * (this->temporalInterpolationCount + 1)},
};
vk::DescriptorPoolCreateInfo createInfo;
......@@ -221,7 +235,7 @@ void lib::CgContext::CreateRasterizationDescriptorSetLayout()
auto &item = layoutBindings.emplace_back();
item.binding = 0;
item.descriptorType = vk::DescriptorType::eCombinedImageSampler;
item.descriptorCount = 1;
item.descriptorCount = this->temporalInterpolationCount + 1;
item.stageFlags = vk::ShaderStageFlagBits::eFragment;
vk::DescriptorSetLayoutCreateInfo createInfo;
......@@ -276,9 +290,7 @@ void lib::CgContext::CreateRasterizationRenderPass()
void lib::CgContext::CreateRasterizationFrameBuffers()
{
const auto count = static_cast<uint32_t>(frames.size());
for (auto &frame : this->frames)
for (auto &frame : this->temporalInterpolationFrames)
{
const lib::TextureCreateInfo textureCreateInfo{
{
......@@ -292,13 +304,16 @@ void lib::CgContext::CreateRasterizationFrameBuffers()
vk::ImageUsageFlagBits::eStorage,
vk::ImageLayout::eGeneral};
auto newTexture = new lib::Texture{this,
this->swapChainExtent.width,
this->swapChainExtent.height,
textureCreateInfo};
auto newTexture = new lib::RenderTarget{this,
this->swapChainExtent.width,
this->swapChainExtent.height,
textureCreateInfo};
frame.raytracingTexture.reset(newTexture);
frame.raytracingRenderTarget.reset(newTexture);
}
for (auto &frame : this->frames)
{
vk::FramebufferCreateInfo createInfo;
createInfo.renderPass = this->rasterizationStep.renderPass;
createInfo.attachmentCount = 1;
......
......@@ -113,13 +113,6 @@ void lib::CgContext::CreateRaytracingDescriptorSetLayout()
layoutBindings.back().descriptorType = vk::DescriptorType::eStorageBuffer;
layoutBindings.back().stageFlags = vk::ShaderStageFlagBits::eClosestHitNV;
// dummy texture
layoutBindings.emplace_back();
layoutBindings.back().binding = this->descriptorBindings.dummyTexture;
layoutBindings.back().descriptorCount = 1;
layoutBindings.back().descriptorType = vk::DescriptorType::eCombinedImageSampler;
layoutBindings.back().stageFlags = vk::ShaderStageFlagBits::eClosestHitNV | vk::ShaderStageFlagBits::eRaygenNV;
vk::DescriptorSetLayoutCreateInfo createInfo;
createInfo.bindingCount = static_cast<uint32_t>(layoutBindings.size());
createInfo.pBindings = layoutBindings.data();
......@@ -131,7 +124,7 @@ void lib::CgContext::CreateRaytracingDescriptorSetLayout()
void lib::CgContext::CreateRaytracingDescriptorPool()
{
auto count = static_cast<uint32_t>(this->frames.size());
auto count = static_cast<uint32_t>(this->temporalInterpolationFrames.size());
std::vector<vk::DescriptorPoolSize> sizes{
//Acceleration structure
vk::DescriptorPoolSize(vk::DescriptorType::eAccelerationStructureNV, count),
......@@ -163,7 +156,7 @@ void lib::CgContext::CreateRaytracingDescriptorPool()
void lib::CgContext::CreateRaytracingDescriptorSets()
{
auto count = static_cast<uint32_t>(this->frames.size());
auto count = static_cast<uint32_t>(this->temporalInterpolationFrames.size());
std::vector<vk::DescriptorSetLayout> layouts(count, this->raytracingStep.descriptorSetLayout);
vk::DescriptorSetAllocateInfo allocateInfo;
......@@ -175,7 +168,7 @@ void lib::CgContext::CreateRaytracingDescriptorSets()
for (size_t i = 0; i < count; i++)
{
auto &frame = this->frames[i];
auto &frame = this->temporalInterpolationFrames[i];
frame.raytracingDescriptorSet = descriptorSets[i];
vk::StructureChain<vk::WriteDescriptorSet, vk::WriteDescriptorSetAccelerationStructureNV> accelerationStructureWrite;
......@@ -189,7 +182,7 @@ void lib::CgContext::CreateRaytracingDescriptorSets()
vk::DescriptorImageInfo outputImageInfo;
outputImageInfo.imageLayout = vk::ImageLayout::eGeneral;
outputImageInfo.imageView = frame.raytracingTexture->GetView();
outputImageInfo.imageView = frame.raytracingRenderTarget->GetView();
vk::WriteDescriptorSet outputImageWrite;
outputImageWrite.dstSet = frame.raytracingDescriptorSet;
......@@ -271,27 +264,15 @@ void lib::CgContext::CreateRaytracingDescriptorSets()
objectInstanceWrite.descriptorCount = 1;
objectInstanceWrite.pBufferInfo = &objectInstanceInfo;
vk::DescriptorImageInfo dummyTextureInfo;
dummyTextureInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
dummyTextureInfo.imageView = this->dummyTexture->GetView();
dummyTextureInfo.sampler = this->dummyTexture->GetSampler();
vk::WriteDescriptorSet dummyTextureWrite;
dummyTextureWrite.dstSet = frame.raytracingDescriptorSet;
dummyTextureWrite.dstBinding = this->descriptorBindings.dummyTexture;
dummyTextureWrite.dstArrayElement = 0;
dummyTextureWrite.descriptorType = vk::DescriptorType::eCombinedImageSampler;
dummyTextureWrite.descriptorCount = 1;
dummyTextureWrite.pImageInfo = &dummyTextureInfo;
this->logicalDevice.updateDescriptorSets({accelerationStructureWrite.get<vk::WriteDescriptorSet>(),
outputImageWrite,
camWrite,
vertexBufferWrite,
indexBufferWrite,
materialBufferWrite,
objectInstanceWrite,
dummyTextureWrite},
this->logicalDevice.updateDescriptorSets({
accelerationStructureWrite.get<vk::WriteDescriptorSet>(),
outputImageWrite,
camWrite,
vertexBufferWrite,
indexBufferWrite,
materialBufferWrite,
objectInstanceWrite,
},
{});
}
......
......@@ -158,10 +158,14 @@ lib::CgContext::~CgContext()
for (auto &frame : this->frames)
{
frame.ubo.reset();
this->logicalDevice.destroyCommandPool(frame.commandPool);
}
for (auto &frame : this->temporalInterpolationFrames)
{
frame.ubo.reset();
}
for (auto &semaphore : this->imageAvailableSemaphores)
{
if (semaphore)
......@@ -286,11 +290,11 @@ void lib::CgContext::CleanupSwapChain()
{
this->logicalDevice.destroyImageView(frame.swapChainImageView);
}
}
if (frame.raytracingTexture)
{
frame.raytracingTexture.reset();
}
for (auto &frame : this->temporalInterpolationFrames)
{
frame.raytracingRenderTarget.reset();
}
if (this->swapChain)
......@@ -696,6 +700,8 @@ void lib::CgContext::CreateSwapChain()
this->frames[i].swapChainImage = swapChainImages[i];
}
this->temporalInterpolationFrames.resize(swapChainImages.size() + this->temporalInterpolationCount);
lib::log::Info("Successfully acquired swap chain images!");
}
......@@ -729,9 +735,10 @@ void lib::CgContext::CreateCommandPool()
lib::log::Info("Successfully created command pools!");
}
void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex, uint32_t temporalInterpolationImageIndex)
{
auto &frame = this->frames[imageIndex];
auto &interpolationFrame = this->temporalInterpolationFrames[temporalInterpolationImageIndex];
this->logicalDevice.resetCommandPool(frame.commandPool, vk::CommandPoolResetFlagBits::eReleaseResources);
this->pushConstant.rngSeed = this->randomDistribution(this->randomEngine);
......@@ -745,16 +752,16 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
frame.commandBuffer.bindPipeline(vk::PipelineBindPoint::eRayTracingNV, this->raytracingStep.pipeline);
frame.commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eRayTracingNV,
this->raytracingStep.pipelineLayout,
0, frame.raytracingDescriptorSet,
0, interpolationFrame.raytracingDescriptorSet,
{});
TransitionImageLayout(frame.commandBuffer,
frame.raytracingTexture->GetHandle(), this->swapChainImageFormat,
interpolationFrame.raytracingRenderTarget->GetHandle(), this->swapChainImageFormat,
vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral,
vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eRayTracingShaderNV);
frame.ubo->ScheduleTransfer(frame.commandBuffer);
interpolationFrame.ubo->ScheduleTransfer(frame.commandBuffer);
frame.commandBuffer.pushConstants(this->raytracingStep.pipelineLayout,
vk::ShaderStageFlagBits::eRaygenNV | vk::ShaderStageFlagBits::eClosestHitNV,
......@@ -768,10 +775,12 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
this->shaderBindingTableBuffer->GetBufferHandle(), this->shaderOffsets.hitGroup * sbtEntrySize, sbtEntrySize,
this->shaderBindingTableBuffer->GetBufferHandle(), 0, 0,
this->swapChainExtent.width, this->swapChainExtent.height, 1);
}
TransitionImageLayout(frame.commandBuffer,
interpolationFrame.raytracingRenderTarget->GetHandle(), this->swapChainImageFormat,
vk::ImageLayout::eGeneral, vk::ImageLayout::eShaderReadOnlyOptimal,
vk::PipelineStageFlagBits::eRayTracingShaderNV, vk::PipelineStageFlagBits::eAllGraphics);
if (this->IsOk())
{
vk::RenderPassBeginInfo ppBeginInfo;
ppBeginInfo.renderPass = this->rasterizationStep.renderPass;
ppBeginInfo.framebuffer = frame.swapChainFramebufferForRasterizationRenderPass;
......@@ -782,7 +791,7 @@ void lib::CgContext::UpdateCommandBuffer(uint32_t imageIndex)
frame.commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, this->rasterizationStep.pipeline);
frame.commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
this->rasterizationStep.pipelineLayout,
0, frame.rasterizationDescriptorSet, {});
0, interpolationFrame.rasterizationDescriptorSet, {});
frame.commandBuffer.draw(3, 1, 0, 0);
frame.commandBuffer.endRenderPass();
}
......@@ -962,7 +971,7 @@ vk::ShaderModule lib::CgContext::LoadShader(const ShaderInfo &info)
void lib::CgContext::UpdateUniformBuffer(uint32_t imageIndex, lib::time_diff_t delta)
{
this->camera.UpdateMatrices();
this->frames[imageIndex].ubo->BufferDataHostOnly(SceneDescription{
this->temporalInterpolationFrames[imageIndex].ubo->BufferDataHostOnly(SceneDescription{
this->camera.GetModel(),
this->lightSources,
this->clearColor});
......@@ -1009,11 +1018,12 @@ void lib::CgContext::DrawFrame(lib::time_diff_t delta)
this->logicalDevice.waitForFences(this->frames[imageIndex].inFlightFence, VK_TRUE, std::numeric_limits<uint64_t>::max());
}
this->UpdateCommandBuffer(imageIndex);
this->UpdateCommandBuffer(imageIndex, imageIndex);
this->frames[imageIndex].inFlightFence = this->inFlightFences[this->frameIndex];
vk::PipelineStageFlags waitStages[] = {vk::PipelineStageFlagBits::eColorAttachmentOutput};
vk::SubmitInfo submitInfo;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &this->imageAvailableSemaphores[this->frameIndex];
......@@ -1208,7 +1218,7 @@ void lib::CgContext::CreateUniformBuffers()
int i = 0;
for (auto &frame : this->frames)
for (auto &frame : this->temporalInterpolationFrames)
{
const auto name = "UBO" + std::to_string(i);
......
#include "Core/CgContext.hpp"
#include "VkUtil/RenderTarget.hpp"
lib::RenderTarget::RenderTarget(CgContext *parent, uint32_t width, uint32_t height, const lib::TextureCreateInfo &textureCreateInfo)
: lib::Texture(parent, width, height, textureCreateInfo)
{
this->semaphore = this->parent->GetLogicalDevice().createSemaphore({});
}
lib::RenderTarget::~RenderTarget()
{
auto logicalDevice = this->parent->GetLogicalDevice();
if (this->semaphore)
{
logicalDevice.destroySemaphore(this->semaphore);
}
for (auto [_, framebuffer] : this->framebuffersByRenderPass)
{
if (framebuffer)
{
logicalDevice.destroyFramebuffer(framebuffer);
}
}
}
void lib::RenderTarget::CreateFramebufferForRenderPass(vk::RenderPass renderPass)
{
auto logicalDevice = this->parent->GetLogicalDevice();
auto existing = this->framebuffersByRenderPass.find(renderPass);
if (existing != this->framebuffersByRenderPass.end())
{
logicalDevice.destroyFramebuffer(existing->second);
}
vk::FramebufferCreateInfo createInfo;
createInfo.attachmentCount = 1;
createInfo.height = this->GetHeight();
createInfo.width = this->GetWidth();
createInfo.layers = 1;
createInfo.renderPass = renderPass;
this->framebuffersByRenderPass[renderPass] = logicalDevice.createFramebuffer(createInfo);
}
const vk::Semaphore &lib::RenderTarget::GetSemaphore() const
{
return this->semaphore;
}
const vk::Framebuffer &lib::RenderTarget::GetFrameBufferForRenderPass(const vk::RenderPass &renderPass) const
{
return this->framebuffersByRenderPass.at(renderPass);
}
void lib::RenderTarget::CreateFramebuffersForRenderPasses(const std::initializer_list<vk::RenderPass> &renderpasses)
{
this->CreateFramebuffersForRenderPasses(std::begin(renderpasses), std::end(renderpasses));
}
......@@ -67,6 +67,9 @@ lib::Texture::~Texture()
void lib::Texture::LoadData(uint32_t width, uint32_t height, const void *data, uint8_t pixelByteCount, const TextureCreateInfo &createInfo)
{
this->width = width;
this->height = height;
auto queueFamilyIndices = createInfo.queueFamilyIndices;
lib::FilterUnique(queueFamilyIndices);
......@@ -181,4 +184,13 @@ const vk::ImageView &lib::Texture::GetView() const
const vk::Sampler &lib::Texture::GetSampler() const
{
return this->sampler;
}
\ No newline at end of file
}
uint32_t lib::Texture::GetHeight() const
{
return this->height;
}
uint32_t lib::Texture::GetWidth() const
{
return this->width;
}