Skip to content
Snippets Groups Projects
Commit 2da564d5 authored by Alexander Gauggel's avatar Alexander Gauggel
Browse files

[#106] Naive motion blur implementation

parent 0fa26d45
No related branches found
No related tags found
1 merge request!89Resolve "Indirect Dispatch"
#version 440
#extension GL_GOOGLE_include_directive : enable
layout(set=0, binding=0) uniform texture2D inColor;
layout(set=0, binding=1) uniform texture2D inMotion;
layout(set=0, binding=2) uniform sampler textureSampler;
layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D outImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main(){
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage))))
return;
ivec2 textureRes = textureSize(sampler2D(inColor, textureSampler), 0);
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(coord) / textureRes;
vec2 motion = texture(sampler2D(inMotion, textureSampler), uv).rg;
float blurFactor = 5;
motion *= blurFactor;
vec3 color = vec3(0);
const int sampleCount = 16;
vec2 uvStart = uv - motion;
vec2 uvEnd = uv + motion;
for(int i = 0; i < sampleCount; i++){
vec2 sampleUV = mix(uvStart, uvEnd, i / float(sampleCount - 1));
color += texture(sampler2D(inColor, textureSampler), sampleUV).rgb;
}
color /= sampleCount;
imageStore(outImage, coord, vec4(color, 0.f));
}
\ No newline at end of file
vec2 computeMotionVector(vec4 NDC, vec4 NDCPrevious){
vec2 ndc = NDC.xy / NDC.w;
vec2 ndcPrevious = NDCPrevious.xy / NDCPrevious.w;
vec2 uv = ndc * 0.5 + 0.5;
vec2 uvPrevious = ndcPrevious * 0.5 + 0.5;
return uvPrevious - uv;
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "motionVector.inc"
layout(location = 0) in vec4 passNDC;
layout(location = 1) in vec4 passNDCPrevious;
......@@ -7,12 +10,5 @@ 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;
outMotion = computeMotionVector(passNDC, passNDCPrevious);
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "motionVector.inc"
layout(location = 0) out vec2 outMotion;
layout(location = 0) in vec4 passNDC;
layout(location = 1) in vec4 passNDCPrevious;
void main() {
outMotion = computeMotionVector(passNDC, passNDCPrevious);
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 inPosition;
layout( push_constant ) uniform constants{
mat4 viewProjection;
mat4 viewProjectionPrevious;
};
layout(location = 0) out vec4 passNDC;
layout(location = 1) out vec4 passNDCPrevious;
void main() {
gl_Position = viewProjection * vec4(inPosition, 0.0);
gl_Position.w = gl_Position.z;
passNDC = gl_Position;
passNDCPrevious = viewProjectionPrevious * vec4(inPosition, 0.0);
passNDCPrevious.w = passNDCPrevious.z;
}
\ No newline at end of file
......@@ -23,18 +23,24 @@ App::App() :
bool App::initialize() {
if (!loadMeshPass(m_core, &m_meshPassHandles))
if (!loadMeshPass(m_core, &m_meshPass))
return false;
if (!loadSkyPass(m_core, &m_skyPassHandles))
if (!loadSkyPass(m_core, &m_skyPass))
return false;
if (!loadPrePass(m_core, &m_prePassHandles))
if (!loadPrePass(m_core, &m_prePass))
false;
if (!loadSkyPrePass(m_core, &m_skyPrePass))
return false;
if (!loadComputePass(m_core, "resources/shaders/gammaCorrection.comp", &m_gammaCorrectionPass))
return false;
if(!loadComputePass(m_core, "resources/shaders/motionBlurDummy.comp", &m_motionBlurDummyPass))
return false;
if (!loadMesh(m_core, "resources/models/sphere.gltf", & m_sphereMesh))
return false;
......@@ -106,8 +112,17 @@ void App::run() {
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_prePassHandles.renderPass,
m_prePassHandles.pipeline,
m_prePass.renderPass,
m_prePass.pipeline,
prepassPushConstants,
{ sphereDrawcall },
prepassRenderTargets);
// sky prepass
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_skyPrePass.renderPass,
m_skyPrePass.pipeline,
prepassPushConstants,
{ sphereDrawcall },
prepassRenderTargets);
......@@ -122,8 +137,8 @@ void App::run() {
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_meshPassHandles.renderPass,
m_meshPassHandles.pipeline,
m_meshPass.renderPass,
m_meshPass.pipeline,
meshPushConstants,
{ sphereDrawcall },
renderTargets);
......@@ -134,14 +149,42 @@ void App::run() {
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_skyPassHandles.renderPass,
m_skyPassHandles.pipeline,
m_skyPass.renderPass,
m_skyPass.pipeline,
skyPushConstants,
{ cubeDrawcall },
renderTargets);
// motion blur
vkcv::DescriptorWrites motionBlurDescriptorWrites;
motionBlurDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, m_renderTargets.colorBuffer),
vkcv::SampledImageDescriptorWrite(1, m_renderTargets.motionBuffer) };
motionBlurDescriptorWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(2, m_linearSampler) };
motionBlurDescriptorWrites.storageImageWrites = {
vkcv::StorageImageDescriptorWrite(3, m_renderTargets.motionBlurOutput) };
m_core.writeDescriptorSet(m_motionBlurDummyPass.descriptorSet, motionBlurDescriptorWrites);
uint32_t fullScreenImageDispatch[3] = {
static_cast<uint32_t>((m_windowWidth + 7) / 8),
static_cast<uint32_t>((m_windowHeight + 7) / 8),
static_cast<uint32_t>(1) };
m_core.prepareImageForStorage(cmdStream, m_renderTargets.motionBlurOutput);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.colorBuffer);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.motionBuffer);
m_core.recordComputeDispatchToCmdStream(
cmdStream,
m_motionBlurDummyPass.pipeline,
fullScreenImageDispatch,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_motionBlurDummyPass.descriptorSet).vulkanHandle) },
vkcv::PushConstants(0));
// gamma correction
vkcv::ImageHandle gammaCorrectionInput = m_renderTargets.colorBuffer;
vkcv::ImageHandle gammaCorrectionInput = m_renderTargets.motionBlurOutput;
if (drawMotionVectors) {
gammaCorrectionInput = m_renderTargets.motionBuffer;
}
......@@ -159,15 +202,10 @@ void App::run() {
m_core.prepareImageForSampling(cmdStream, gammaCorrectionInput);
m_core.prepareImageForStorage (cmdStream, swapchainInput);
uint32_t gammaCorrectionDispatch[3] = {
static_cast<uint32_t>((m_windowWidth + 7) / 8),
static_cast<uint32_t>((m_windowHeight + 7) / 8),
static_cast<uint32_t>(1) };
m_core.recordComputeDispatchToCmdStream(
cmdStream,
m_gammaCorrectionPass.pipeline,
gammaCorrectionDispatch,
fullScreenImageDispatch,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_gammaCorrectionPass.descriptorSet).vulkanHandle) },
vkcv::PushConstants(0));
......
......@@ -21,11 +21,13 @@ private:
MeshResources m_sphereMesh;
MeshResources m_cubeMesh;
GraphicPassHandles m_meshPassHandles;
GraphicPassHandles m_skyPassHandles;
GraphicPassHandles m_prePassHandles;
GraphicPassHandles m_meshPass;
GraphicPassHandles m_skyPass;
GraphicPassHandles m_prePass;
GraphicPassHandles m_skyPrePass;
ComputePassHandles m_gammaCorrectionPass;
ComputePassHandles m_motionBlurDummyPass;
RenderTargets m_renderTargets;
vkcv::SamplerHandle m_linearSampler;
......
......@@ -180,6 +180,28 @@ bool loadPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) {
outHandles);
}
bool loadSkyPrePass(vkcv::Core& core, GraphicPassHandles* outHandles) {
assert(outHandles);
vkcv::AttachmentDescription motionAttachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::LOAD,
AppConfig::motionBufferFormat);
vkcv::AttachmentDescription depthAttachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::LOAD,
AppConfig::depthBufferFormat);
return loadGraphicPass(
core,
"resources/shaders/skyPrepass.vert",
"resources/shaders/skyPrepass.frag",
vkcv::PassConfig({ motionAttachment, depthAttachment }),
vkcv::DepthTest::LessEqual,
outHandles);
}
bool loadComputePass(vkcv::Core& core, const std::filesystem::path& path, ComputePassHandles* outComputePass) {
assert(outComputePass);
......@@ -230,6 +252,14 @@ RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const
false,
true).getHandle();
targets.motionBlurOutput = core.createImage(
AppConfig::colorBufferFormat,
width,
height,
1,
false,
true).getHandle();
targets.motionBuffer = core.createImage(
AppConfig::motionBufferFormat,
width,
......
......@@ -4,6 +4,7 @@
struct RenderTargets {
vkcv::ImageHandle depthBuffer;
vkcv::ImageHandle colorBuffer;
vkcv::ImageHandle motionBlurOutput;
vkcv::ImageHandle motionBuffer;
};
......@@ -34,9 +35,10 @@ bool loadGraphicPass(
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 loadMeshPass (vkcv::Core& core, GraphicPassHandles* outHandles);
bool loadSkyPass (vkcv::Core& core, GraphicPassHandles* outHandles);
bool loadPrePass (vkcv::Core& core, GraphicPassHandles* outHandles);
bool loadSkyPrePass(vkcv::Core& core, GraphicPassHandles* outHandles);
bool loadComputePass(vkcv::Core& core, const std::filesystem::path& path, ComputePassHandles* outComputePass);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment