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

[#106] Add motion vector max and neighbourhood max options for motion blur

parent 2da564d5
No related branches found
No related tags found
1 merge request!89Resolve "Indirect Dispatch"
Pipeline #26700 passed
......@@ -9,13 +9,13 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main(){
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage))))
ivec2 outImageRes = imageSize(outImage);
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
if(any(greaterThanEqual(coord, outImageRes)))
return;
ivec2 textureRes = textureSize(sampler2D(inTexture, textureSampler), 0);
ivec2 coord = ivec2(gl_GlobalInvocationID.xy);
vec2 uv = vec2(coord) / textureRes;
vec2 uv = vec2(coord) / outImageRes;
vec3 linearColor = texture(sampler2D(inTexture, textureSampler), uv).rgb;
// in case of motion vector visualisation negative values are possible
......
......@@ -2,9 +2,11 @@
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 passNormal;
layout(location = 1) in vec3 passPos;
layout(location = 0) out vec3 outColor;
void main() {
outColor = passNormal * 0.5 + 0.5;
// outColor = passNormal * 0.5 + 0.5;
outColor = vec3(sin(passPos.y * 100) * 0.5 + 0.5);
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNormal;
layout(location = 0) out vec3 passNormal;
layout(location = 1) out vec3 passPos;
layout( push_constant ) uniform constants{
mat4 mvp;
......@@ -13,4 +14,5 @@ layout( push_constant ) uniform constants{
void main() {
gl_Position = mvp * vec4(inPosition, 1.0);
passNormal = inNormal;
passPos = inPosition;
}
\ No newline at end of file
......@@ -18,8 +18,6 @@ void main(){
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;
......
#version 440
#extension GL_GOOGLE_include_directive : enable
layout(set=0, binding=0) uniform texture2D inMotion;
layout(set=0, binding=1) uniform sampler textureSampler;
layout(set=0, binding=2, rgba8) uniform image2D outMotionMax;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
const int motionTileSize = 8;
void main(){
ivec2 outImageRes = imageSize(outMotionMax);
ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy);
if(any(greaterThanEqual(motionTileCoord, outImageRes)))
return;
float velocityMax = 0;
vec2 motionMax = vec2(0);
ivec2 motionBufferBaseCoord = motionTileCoord * motionTileSize;
for(int x = 0; x < motionTileSize; x++){
for(int y = 0; y < motionTileSize; y++){
ivec2 sampleCoord = motionBufferBaseCoord + ivec2(x, y);
vec2 motionSample = texelFetch(sampler2D(inMotion, textureSampler), sampleCoord, 0).rg;
float velocitySample = length(motionSample);
if(velocitySample > velocityMax){
velocityMax = velocitySample;
motionMax = motionSample;
}
}
}
imageStore(outMotionMax, motionTileCoord, vec4(motionMax, 0, 0));
}
\ No newline at end of file
#version 440
#extension GL_GOOGLE_include_directive : enable
layout(set=0, binding=0) uniform texture2D inMotionMax;
layout(set=0, binding=1) uniform sampler textureSampler;
layout(set=0, binding=2, rgba8) uniform image2D outMotionMaxNeighbourhood;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
const int motionTileSize = 8;
void main(){
ivec2 outImageRes = imageSize(outMotionMaxNeighbourhood);
ivec2 motionTileCoord = ivec2(gl_GlobalInvocationID.xy);
if(any(greaterThanEqual(motionTileCoord, outImageRes)))
return;
float velocityMax = 0;
vec2 motionMax = vec2(0);
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 1; y++){
ivec2 sampleCoord = motionTileCoord + ivec2(x, y);
vec2 motionSample = texelFetch(sampler2D(inMotionMax, textureSampler), sampleCoord, 0).rg;
float velocitySample = length(motionSample);
if(velocitySample > velocityMax){
velocityMax = velocitySample;
motionMax = motionSample;
}
}
}
imageStore(outMotionMaxNeighbourhood, motionTileCoord, vec4(motionMax, 0, 0));
}
\ No newline at end of file
......@@ -41,6 +41,12 @@ bool App::initialize() {
if(!loadComputePass(m_core, "resources/shaders/motionBlurDummy.comp", &m_motionBlurDummyPass))
return false;
if (!loadComputePass(m_core, "resources/shaders/motionVectorMax.comp", &m_motionVectorMaxPass))
return false;
if (!loadComputePass(m_core, "resources/shaders/motionVectorMaxNeighbourhood.comp", &m_motionVectorMaxNeighbourhoodPass))
return false;
if (!loadMesh(m_core, "resources/models/sphere.gltf", & m_sphereMesh))
return false;
......@@ -62,15 +68,43 @@ bool App::initialize() {
void App::run() {
auto frameStartTime = std::chrono::system_clock::now();
const auto appStartTime = 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);
vkcv::gui::GUI gui(m_core, m_window);
bool drawMotionVectors = false;
glm::mat4 previousFrameViewProjection = m_cameraManager.getActiveCamera().getMVP();
enum class eDebugView : int {
None = 0,
MotionVector = 1,
MotionVectorMaxTile = 2,
MotionVectorMaxTileNeighbourhood = 3,
OptionCount = 4 };
const char* debugViewLabels[] = {
"None",
"Motion vectors",
"Motion vector max tiles",
"Motion vector tile neighbourhood max" };
enum class eMotionBlurInput : int {
MotionVector = 0,
MotionVectorMaxTile = 1,
MotionVectorMaxTileNeighbourhood = 2,
OptionCount = 3 };
const char* motionInputLabels[] = {
"Motion vectors",
"Motion vector max tiles",
"Motion vector tile neighbourhood max" };
eDebugView debugView = eDebugView::None;
eMotionBlurInput motionBlurInput = eMotionBlurInput::MotionVectorMaxTileNeighbourhood;
float objectVerticalSpeed = 0.005;
glm::mat4 mvpPrevious = glm::mat4(1.f);
glm::mat4 viewProjectionPrevious = m_cameraManager.getActiveCamera().getMVP();
while (m_window.isWindowOpen()) {
vkcv::Window::pollEvents();
......@@ -97,12 +131,18 @@ void App::run() {
m_cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
const glm::mat4 viewProjection = m_cameraManager.getActiveCamera().getMVP();
const auto time = frameEndTime - appStartTime;
const float fCurrentTime = std::chrono::duration_cast<std::chrono::milliseconds>(time).count();
const float currentHeight = glm::sin(fCurrentTime * objectVerticalSpeed);
const glm::mat4 modelMatrix = glm::translate(glm::mat4(1), glm::vec3(0, currentHeight, 0));
const glm::mat4 mvp = viewProjection * modelMatrix;
const vkcv::CommandStreamHandle cmdStream = m_core.createCommandStream(vkcv::QueueType::Graphics);
// prepass
glm::mat4 prepassMatrices[2] = {
viewProjection,
previousFrameViewProjection };
mvp,
mvpPrevious };
vkcv::PushConstants prepassPushConstants(sizeof(glm::mat4)*2);
prepassPushConstants.appendDrawcall(prepassMatrices);
......@@ -119,21 +159,74 @@ void App::run() {
prepassRenderTargets);
// sky prepass
glm::mat4 skyPrepassMatrices[2] = {
viewProjection,
viewProjectionPrevious };
vkcv::PushConstants skyPrepassPushConstants(sizeof(glm::mat4) * 2);
skyPrepassPushConstants.appendDrawcall(skyPrepassMatrices);
m_core.recordDrawcallsToCmdStream(
cmdStream,
m_skyPrePass.renderPass,
m_skyPrePass.pipeline,
prepassPushConstants,
{ sphereDrawcall },
skyPrepassPushConstants,
{ cubeDrawcall },
prepassRenderTargets);
// motion vector max tiles
vkcv::DescriptorWrites motionVectorMaxTilesDescriptorWrites;
motionVectorMaxTilesDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, m_renderTargets.motionBuffer) };
motionVectorMaxTilesDescriptorWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, m_linearSampler) };
motionVectorMaxTilesDescriptorWrites.storageImageWrites = {
vkcv::StorageImageDescriptorWrite(2, m_renderTargets.motionMax)};
m_core.writeDescriptorSet(m_motionVectorMaxPass.descriptorSet, motionVectorMaxTilesDescriptorWrites);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.motionBuffer);
m_core.prepareImageForStorage(cmdStream, m_renderTargets.motionMax);
const uint32_t motionTileDispatchCounts[3] = {
(m_core.getImageWidth( m_renderTargets.motionMax) + 7) / 8,
(m_core.getImageHeight(m_renderTargets.motionMax) + 7) / 8,
1 };
m_core.recordComputeDispatchToCmdStream(
cmdStream,
m_motionVectorMaxPass.pipeline,
motionTileDispatchCounts,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_motionVectorMaxPass.descriptorSet).vulkanHandle) },
vkcv::PushConstants(0));
// motion vector max neighbourhood
vkcv::DescriptorWrites motionVectorMaxNeighbourhoodDescriptorWrites;
motionVectorMaxNeighbourhoodDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, m_renderTargets.motionMax) };
motionVectorMaxNeighbourhoodDescriptorWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, m_linearSampler) };
motionVectorMaxNeighbourhoodDescriptorWrites.storageImageWrites = {
vkcv::StorageImageDescriptorWrite(2, m_renderTargets.motionMaxNeighbourhood) };
m_core.writeDescriptorSet(m_motionVectorMaxNeighbourhoodPass.descriptorSet, motionVectorMaxNeighbourhoodDescriptorWrites);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.motionMax);
m_core.prepareImageForStorage(cmdStream, m_renderTargets.motionMaxNeighbourhood);
m_core.recordComputeDispatchToCmdStream(
cmdStream,
m_motionVectorMaxNeighbourhoodPass.pipeline,
motionTileDispatchCounts,
{ vkcv::DescriptorSetUsage(0, m_core.getDescriptorSet(m_motionVectorMaxNeighbourhoodPass.descriptorSet).vulkanHandle) },
vkcv::PushConstants(0));
// main pass
const std::vector<vkcv::ImageHandle> renderTargets = {
m_renderTargets.colorBuffer,
m_renderTargets.depthBuffer };
vkcv::PushConstants meshPushConstants(sizeof(glm::mat4));
meshPushConstants.appendDrawcall(viewProjection);
meshPushConstants.appendDrawcall(mvp);
m_core.recordDrawcallsToCmdStream(
cmdStream,
......@@ -145,7 +238,7 @@ void App::run() {
// sky
vkcv::PushConstants skyPushConstants(sizeof(glm::mat4));
skyPushConstants.appendDrawcall(viewProjection);
skyPushConstants.appendDrawcall(viewProjectionPrevious);
m_core.recordDrawcallsToCmdStream(
cmdStream,
......@@ -156,10 +249,22 @@ void App::run() {
renderTargets);
// motion blur
vkcv::ImageHandle motionBuffer;
if (motionBlurInput == eMotionBlurInput::MotionVector)
motionBuffer = m_renderTargets.motionBuffer;
else if (motionBlurInput == eMotionBlurInput::MotionVectorMaxTile)
motionBuffer = m_renderTargets.motionMax;
else if (motionBlurInput == eMotionBlurInput::MotionVectorMaxTileNeighbourhood)
motionBuffer = m_renderTargets.motionMaxNeighbourhood;
else {
vkcv_log(vkcv::LogLevel::ERROR, "Unknown eMotionInput enum value");
motionBuffer = m_renderTargets.motionBuffer;
}
vkcv::DescriptorWrites motionBlurDescriptorWrites;
motionBlurDescriptorWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, m_renderTargets.colorBuffer),
vkcv::SampledImageDescriptorWrite(1, m_renderTargets.motionBuffer) };
vkcv::SampledImageDescriptorWrite(1, motionBuffer) };
motionBlurDescriptorWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(2, m_linearSampler) };
motionBlurDescriptorWrites.storageImageWrites = {
......@@ -174,7 +279,7 @@ void App::run() {
m_core.prepareImageForStorage(cmdStream, m_renderTargets.motionBlurOutput);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.colorBuffer);
m_core.prepareImageForSampling(cmdStream, m_renderTargets.motionBuffer);
m_core.prepareImageForSampling(cmdStream, motionBuffer);
m_core.recordComputeDispatchToCmdStream(
cmdStream,
......@@ -184,9 +289,18 @@ void App::run() {
vkcv::PushConstants(0));
// gamma correction
vkcv::ImageHandle gammaCorrectionInput = m_renderTargets.motionBlurOutput;
if (drawMotionVectors) {
vkcv::ImageHandle gammaCorrectionInput;
if (debugView == eDebugView::None)
gammaCorrectionInput = m_renderTargets.motionBlurOutput;
else if (debugView == eDebugView::MotionVector)
gammaCorrectionInput = m_renderTargets.motionBuffer;
else if (debugView == eDebugView::MotionVectorMaxTile)
gammaCorrectionInput = m_renderTargets.motionMax;
else if (debugView == eDebugView::MotionVectorMaxTileNeighbourhood)
gammaCorrectionInput = m_renderTargets.motionMaxNeighbourhood;
else {
vkcv_log(vkcv::LogLevel::ERROR, "Unknown eDebugView enum value");
gammaCorrectionInput = m_renderTargets.motionBlurOutput;
}
vkcv::DescriptorWrites gammaCorrectionDescriptorWrites;
......@@ -214,12 +328,27 @@ void App::run() {
gui.beginGUI();
ImGui::Begin("Settings");
ImGui::Checkbox("View motion vectors", &drawMotionVectors);
ImGui::Combo(
"Debug view",
reinterpret_cast<int*>(&debugView),
debugViewLabels,
static_cast<int>(eDebugView::OptionCount));
ImGui::Combo(
"Motion blur input",
reinterpret_cast<int*>(&motionBlurInput),
motionInputLabels,
static_cast<int>(eMotionBlurInput::OptionCount));
ImGui::InputFloat("Object movement speed", &objectVerticalSpeed);
ImGui::End();
gui.endGUI();
m_core.endFrame();
previousFrameViewProjection = viewProjection;
viewProjectionPrevious = viewProjection;
mvpPrevious = mvp;
}
}
\ No newline at end of file
......@@ -28,6 +28,8 @@ private:
ComputePassHandles m_gammaCorrectionPass;
ComputePassHandles m_motionBlurDummyPass;
ComputePassHandles m_motionVectorMaxPass;
ComputePassHandles m_motionVectorMaxNeighbourhoodPass;
RenderTargets m_renderTargets;
vkcv::SamplerHandle m_linearSampler;
......
......@@ -269,5 +269,26 @@ RenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const
false,
true).getHandle();
const uint32_t motionTileSize = 8;
// divide and ceil to int
const uint32_t motionMaxWidth = (width + (motionTileSize - 1)) / motionTileSize;
const uint32_t motionMaxheight = (height + (motionTileSize - 1)) / motionTileSize;
targets.motionMax = core.createImage(
AppConfig::motionBufferFormat,
motionMaxWidth,
motionMaxheight,
1,
false,
true).getHandle();
targets.motionMaxNeighbourhood = core.createImage(
AppConfig::motionBufferFormat,
motionMaxWidth,
motionMaxheight,
1,
false,
true).getHandle();
return targets;
}
\ No newline at end of file
......@@ -6,6 +6,8 @@ struct RenderTargets {
vkcv::ImageHandle colorBuffer;
vkcv::ImageHandle motionBlurOutput;
vkcv::ImageHandle motionBuffer;
vkcv::ImageHandle motionMax;
vkcv::ImageHandle motionMaxNeighbourhood;
};
struct GraphicPassHandles {
......
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