diff --git a/projects/indirect_dispatch/resources/shaders/gammaCorrection.comp b/projects/indirect_dispatch/resources/shaders/gammaCorrection.comp index d3d1ee72546595fa0c260f7c5493b76beaf2012c..59540806f84d4683f1ded003d05ddb98d970fe69 100644 --- a/projects/indirect_dispatch/resources/shaders/gammaCorrection.comp +++ b/projects/indirect_dispatch/resources/shaders/gammaCorrection.comp @@ -17,6 +17,10 @@ void main(){ vec2 uv = vec2(coord) / textureRes; vec3 linearColor = texture(sampler2D(inTexture, textureSampler), uv).rgb; + + // in case of motion vector visualisation negative values are possible + linearColor = abs(linearColor); + vec3 gammaCorrected = pow(linearColor, vec3(1 / 2.2)); imageStore(outImage, coord, vec4(gammaCorrected, 0.f)); diff --git a/projects/indirect_dispatch/resources/shaders/prepass.frag b/projects/indirect_dispatch/resources/shaders/prepass.frag new file mode 100644 index 0000000000000000000000000000000000000000..e9030883b9db701ae9c8ac34006b52dbcd492c64 --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/prepass.frag @@ -0,0 +1,18 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec4 passNDC; +layout(location = 1) in vec4 passNDCPrevious; + +layout(location = 0) out vec2 outMotion; + +void main() { + + vec2 ndc = passNDC.xy / passNDC.w; + vec2 ndcPrevious = passNDCPrevious.xy / passNDCPrevious.w; + + vec2 uv = ndc * 0.5 + 0.5; + vec2 uvPrevious = ndcPrevious * 0.5 + 0.5; + + outMotion = uvPrevious - uv; +} \ No newline at end of file diff --git a/projects/indirect_dispatch/resources/shaders/prepass.vert b/projects/indirect_dispatch/resources/shaders/prepass.vert new file mode 100644 index 0000000000000000000000000000000000000000..00b47280bd832e55718535c4f39879051a526eca --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/prepass.vert @@ -0,0 +1,19 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; + +layout(location = 0) out vec4 passNDC; +layout(location = 1) out vec4 passNDCPrevious; + +layout( push_constant ) uniform constants{ + mat4 mvp; + mat4 mvpPrevious; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); + passNDC = gl_Position; + passNDCPrevious = mvpPrevious * vec4(inPosition, 1.0); +} \ No newline at end of file diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index e53c86efb8513a54d0b7b84bf35c1c5c838e7c3b..c74ffe2b966c0d0b8aac8b610290a52499c973b8 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -1,6 +1,7 @@ #include "App.hpp" #include "AppConfig.hpp" #include <chrono> +#include <vkcv/gui/GUI.hpp> App::App() : m_applicationName("Indirect Dispatch"), @@ -18,10 +19,7 @@ App::App() : { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, {}, { "VK_KHR_swapchain" })), - m_cameraManager(m_window){ - - m_isInitialized = false; -} + m_cameraManager(m_window){} bool App::initialize() { @@ -31,6 +29,9 @@ bool App::initialize() { if (!loadSkyPass(m_core, &m_skyPassHandles)) return false; + if (!loadPrePass(m_core, &m_prePassHandles)) + false; + if (!loadComputePass(m_core, "resources/shaders/gammaCorrection.comp", &m_gammaCorrectionPass)) return false; @@ -50,24 +51,20 @@ bool App::initialize() { const int cameraIndex = m_cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); m_cameraManager.getCamera(cameraIndex).setPosition(glm::vec3(0, 0, -3)); - - m_isInitialized = true; } void App::run() { - if (!m_isInitialized) { - vkcv_log(vkcv::LogLevel::WARNING, "Application is not initialized, app should be initialized explicitly to check for errors"); - if (!initialize()) { - vkcv_log(vkcv::LogLevel::ERROR, "Emergency initialization failed, exiting"); - return; - } - } - auto frameStartTime = std::chrono::system_clock::now(); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); const vkcv::DrawcallInfo sphereDrawcall(m_sphereMesh.mesh, {}, 1); - const vkcv::DrawcallInfo cubeDrawcall(m_cubeMesh.mesh, {}, 1); + const vkcv::DrawcallInfo cubeDrawcall(m_cubeMesh.mesh, {}, 1); + + vkcv::gui::GUI gui(m_core, m_window); + + bool drawMotionVectors = false; + + glm::mat4 previousFrameViewProjection = m_cameraManager.getActiveCamera().getMVP(); while (m_window.isWindowOpen()) { vkcv::Window::pollEvents(); @@ -94,12 +91,32 @@ void App::run() { m_cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); const glm::mat4 viewProjection = m_cameraManager.getActiveCamera().getMVP(); + const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics); + + // prepass + glm::mat4 prepassMatrices[2] = { + viewProjection, + previousFrameViewProjection }; + vkcv::PushConstants prepassPushConstants(sizeof(glm::mat4)*2); + prepassPushConstants.appendDrawcall(prepassMatrices); + + const std::vector<vkcv::ImageHandle> prepassRenderTargets = { + m_renderTargets.motionBuffer, + m_renderTargets.depthBuffer }; + + m_core.recordDrawcallsToCmdStream( + cmdStream, + m_prePassHandles.renderPass, + m_prePassHandles.pipeline, + prepassPushConstants, + { sphereDrawcall }, + prepassRenderTargets); + + // main pass const std::vector<vkcv::ImageHandle> renderTargets = { m_renderTargets.colorBuffer, m_renderTargets.depthBuffer }; - const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics); - vkcv::PushConstants meshPushConstants(sizeof(glm::mat4)); meshPushConstants.appendDrawcall(viewProjection); @@ -111,6 +128,7 @@ void App::run() { { sphereDrawcall }, renderTargets); + // sky vkcv::PushConstants skyPushConstants(sizeof(glm::mat4)); skyPushConstants.appendDrawcall(viewProjection); @@ -122,9 +140,15 @@ void App::run() { { cubeDrawcall }, renderTargets); + // gamma correction + vkcv::ImageHandle gammaCorrectionInput = m_renderTargets.colorBuffer; + if (drawMotionVectors) { + gammaCorrectionInput = m_renderTargets.motionBuffer; + } + vkcv::DescriptorWrites gammaCorrectionDescriptorWrites; gammaCorrectionDescriptorWrites.sampledImageWrites = { - vkcv::SampledImageDescriptorWrite(0, m_renderTargets.colorBuffer) }; + vkcv::SampledImageDescriptorWrite(0, gammaCorrectionInput) }; gammaCorrectionDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, m_linearSampler) }; gammaCorrectionDescriptorWrites.storageImageWrites = { @@ -132,7 +156,7 @@ void App::run() { m_core.writeDescriptorSet(m_gammaCorrectionPass.descriptorSet, gammaCorrectionDescriptorWrites); - m_core.prepareImageForSampling(cmdStream, m_renderTargets.colorBuffer); + m_core.prepareImageForSampling(cmdStream, gammaCorrectionInput); m_core.prepareImageForStorage (cmdStream, swapchainInput); uint32_t gammaCorrectionDispatch[3] = { @@ -149,6 +173,15 @@ void App::run() { m_core.prepareSwapchainImageForPresent(cmdStream); m_core.submitCommandStream(cmdStream); + + gui.beginGUI(); + ImGui::Begin("Settings"); + ImGui::Checkbox("View motion vectors", &drawMotionVectors); + ImGui::End(); + gui.endGUI(); + m_core.endFrame(); + + previousFrameViewProjection = viewProjection; } } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/App.hpp b/projects/indirect_dispatch/src/App.hpp index ea889108cf59bc1ff1ac897cf492b41134426f16..78fe382b5d95db0b3b936df2b97820c4ee07183e 100644 --- a/projects/indirect_dispatch/src/App.hpp +++ b/projects/indirect_dispatch/src/App.hpp @@ -10,7 +10,6 @@ public: void run(); private: const char* m_applicationName; - bool m_isInitialized; int m_windowWidth; int m_windowHeight; @@ -24,6 +23,7 @@ private: GraphicPassHandles m_meshPassHandles; GraphicPassHandles m_skyPassHandles; + GraphicPassHandles m_prePassHandles; ComputePassHandles m_gammaCorrectionPass; diff --git a/projects/indirect_dispatch/src/AppConfig.hpp b/projects/indirect_dispatch/src/AppConfig.hpp index 2ff3d28e350ea55b200211cf1839fdcb338d7868..e727efa62579a0e48972b2803dbf687a567cd2c9 100644 --- a/projects/indirect_dispatch/src/AppConfig.hpp +++ b/projects/indirect_dispatch/src/AppConfig.hpp @@ -6,4 +6,5 @@ namespace AppConfig{ const int defaultWindowHeight = 720; const vk::Format depthBufferFormat = vk::Format::eD32Sfloat; const vk::Format colorBufferFormat = vk::Format::eB10G11R11UfloatPack32; + const vk::Format motionBufferFormat = vk::Format::eR16G16Sfloat; } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index 687d8863a02f64cd1b479855f274c40482831846..f827ae15ebdd57aae67daaea8930e3c8142a4367 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -60,6 +60,7 @@ bool loadGraphicPass( const std::filesystem::path vertexPath, const std::filesystem::path fragmentPath, const vkcv::PassConfig& passConfig, + const vkcv::DepthTest depthTest, GraphicPassHandles* outPassHandles) { assert(outPassHandles); @@ -92,7 +93,7 @@ bool loadGraphicPass( const vkcv::VertexLayout vertexLayout(bindings); - const vkcv::PipelineConfig pipelineConfig{ + vkcv::PipelineConfig pipelineConfig{ shaderProgram, UINT32_MAX, UINT32_MAX, @@ -100,7 +101,8 @@ bool loadGraphicPass( { vertexLayout }, {}, true }; - outPassHandles->pipeline = core.createGraphicsPipeline(pipelineConfig); + pipelineConfig.m_depthTest = depthTest; + outPassHandles->pipeline = core.createGraphicsPipeline(pipelineConfig); if (!outPassHandles->pipeline) { vkcv_log(vkcv::LogLevel::ERROR, "Error: Could not create graphics pipeline"); @@ -116,19 +118,20 @@ bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles) { vkcv::AttachmentDescription colorAttachment( vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::DONT_CARE, AppConfig::colorBufferFormat); vkcv::AttachmentDescription depthAttachment( vkcv::AttachmentOperation::STORE, - vkcv::AttachmentOperation::CLEAR, + vkcv::AttachmentOperation::LOAD, AppConfig::depthBufferFormat); return loadGraphicPass( - core, - "resources/shaders/mesh.vert", - "resources/shaders/mesh.frag", - vkcv::PassConfig({ colorAttachment, depthAttachment }), + core, + "resources/shaders/mesh.vert", + "resources/shaders/mesh.frag", + vkcv::PassConfig({ colorAttachment, depthAttachment }), + vkcv::DepthTest::Equal, outHandles); } @@ -142,7 +145,7 @@ bool loadSkyPass(vkcv::Core& core, GraphicPassHandles* outHandles) { AppConfig::colorBufferFormat); vkcv::AttachmentDescription depthAttachment( - vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::LOAD, AppConfig::depthBufferFormat); @@ -151,6 +154,29 @@ bool loadSkyPass(vkcv::Core& core, GraphicPassHandles* outHandles) { "resources/shaders/sky.vert", "resources/shaders/sky.frag", vkcv::PassConfig({ colorAttachment, depthAttachment }), + vkcv::DepthTest::Equal, + outHandles); +} + +bool loadPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) { + assert(outHandles); + + vkcv::AttachmentDescription motionAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + AppConfig::motionBufferFormat); + + vkcv::AttachmentDescription depthAttachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + AppConfig::depthBufferFormat); + + return loadGraphicPass( + core, + "resources/shaders/prepass.vert", + "resources/shaders/prepass.frag", + vkcv::PassConfig({ motionAttachment, depthAttachment }), + vkcv::DepthTest::LessEqual, outHandles); } @@ -204,5 +230,14 @@ RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const false, true).getHandle(); + targets.motionBuffer = core.createImage( + AppConfig::motionBufferFormat, + width, + height, + 1, + false, + false, + true).getHandle(); + return targets; } \ No newline at end of file diff --git a/projects/indirect_dispatch/src/AppSetup.hpp b/projects/indirect_dispatch/src/AppSetup.hpp index 892701aa4e57027f0eaf3904a195b7046d66b785..aa7be2fd50be2705fb05286cc3cb1b88fb12d09e 100644 --- a/projects/indirect_dispatch/src/AppSetup.hpp +++ b/projects/indirect_dispatch/src/AppSetup.hpp @@ -4,6 +4,7 @@ struct RenderTargets { vkcv::ImageHandle depthBuffer; vkcv::ImageHandle colorBuffer; + vkcv::ImageHandle motionBuffer; }; struct GraphicPassHandles { @@ -30,10 +31,12 @@ bool loadGraphicPass( const std::filesystem::path vertexPath, const std::filesystem::path fragmentPath, const vkcv::PassConfig& passConfig, + const vkcv::DepthTest depthTest, GraphicPassHandles* outPassHandles); bool loadMeshPass(vkcv::Core& core, GraphicPassHandles* outHandles); bool loadSkyPass (vkcv::Core& core, GraphicPassHandles* outHandles); +bool loadPrePass (vkcv::Core& core, GraphicPassHandles* outHandles); bool loadComputePass(vkcv::Core& core, const std::filesystem::path& path, ComputePassHandles* outComputePass);