From 7aded7d53366442941272da756b64b9d52a29a2b Mon Sep 17 00:00:00 2001 From: Alexander Gauggel <agauggel@uni-koblenz.de> Date: Tue, 17 Aug 2021 15:49:04 +0200 Subject: [PATCH] [#106] Correct handling of motion blur motion vectors according to paper --- .../resources/shaders/motionBlur.comp | 26 +++++++++++++------ .../resources/shaders/motionBlurConfig.inc | 1 + .../resources/shaders/motionVectorMax.comp | 3 +-- projects/indirect_dispatch/src/App.cpp | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 projects/indirect_dispatch/resources/shaders/motionBlurConfig.inc diff --git a/projects/indirect_dispatch/resources/shaders/motionBlur.comp b/projects/indirect_dispatch/resources/shaders/motionBlur.comp index 62bae130..5c196016 100644 --- a/projects/indirect_dispatch/resources/shaders/motionBlur.comp +++ b/projects/indirect_dispatch/resources/shaders/motionBlur.comp @@ -1,5 +1,6 @@ #version 440 #extension GL_GOOGLE_include_directive : enable +#include "motionBlurConfig.inc" layout(set=0, binding=0) uniform texture2D inColor; layout(set=0, binding=1) uniform texture2D inDepth; @@ -10,7 +11,7 @@ layout(set=0, binding=4, r11f_g11f_b10f) uniform image2D outImage; layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout( push_constant ) uniform constants{ - float motionFactor; // computed from delta time and shutter speed + float motionScaleFactor; // computed from delta time and shutter speed float minVelocity; // camera planes are needed to linearize depth float cameraNearPlane; @@ -64,11 +65,26 @@ float computeSampleWeigth(SampleData mainPixel, SampleData samplePixel){ return weight; } +// see "A Reconstruction Filter for Plausible Motion Blur", section 2.2 +vec2 rescaleMotion(vec2 motion){ + // every frame a pixel should blur over the distance it moves + // as we blur in two directions (where it was and where it will be) we must half the motion + vec2 motionHalf = motion * 0.5; + vec2 motionScaled = motionHalf * motionScaleFactor; // scale factor contains shutter speed and delta time + + // pixels are anisotropic so the smaller dimension is used, so the clamping is conservative + float pixelSize = 1.f / max(imageSize(outImage).x, imageSize(outImage).y); + float velocity = length(motionScaled); + float epsilon = 0.0001; + // this clamps the motion to not exceed the radius given by the motion tile size + return motionScaled * max(0.5 * pixelSize, min(velocity, motionTileSize * pixelSize)) / (velocity + epsilon); +} + SampleData loadSampleData(vec2 uv){ SampleData data; data.uv = uv; - data.motion = texture(sampler2D(inMotion, nearestSampler), uv).rg * motionFactor; + data.motion = rescaleMotion(texture(sampler2D(inMotion, nearestSampler), uv).rg); data.velocity = length(data.motion); data.depthLinear = texture(sampler2D(inDepth, nearestSampler), uv).r; data.depthLinear = linearizeDepth(data.depthLinear, cameraNearPlane, cameraFarPlane); @@ -105,12 +121,6 @@ void main(){ imageStore(outImage, coord, vec4(color, 0.f)); return; } - - // TODO: check if a max velocity is necessary - // // TODO: should be configurable by user or computed by velocity tile sizes - // const float maxBlurDistance = 0.075; - // if(mainPixel.velocity > maxBlurDistance) - // motion *= maxBlurDistance / velocity; vec3 color = vec3(0); float weightSum = 0; diff --git a/projects/indirect_dispatch/resources/shaders/motionBlurConfig.inc b/projects/indirect_dispatch/resources/shaders/motionBlurConfig.inc new file mode 100644 index 00000000..fdd915c8 --- /dev/null +++ b/projects/indirect_dispatch/resources/shaders/motionBlurConfig.inc @@ -0,0 +1 @@ +const int motionTileSize = 20; \ No newline at end of file diff --git a/projects/indirect_dispatch/resources/shaders/motionVectorMax.comp b/projects/indirect_dispatch/resources/shaders/motionVectorMax.comp index 725fc3f4..65a6186c 100644 --- a/projects/indirect_dispatch/resources/shaders/motionVectorMax.comp +++ b/projects/indirect_dispatch/resources/shaders/motionVectorMax.comp @@ -1,5 +1,6 @@ #version 440 #extension GL_GOOGLE_include_directive : enable +#include "motionBlurConfig.inc" layout(set=0, binding=0) uniform texture2D inMotion; layout(set=0, binding=1) uniform sampler textureSampler; @@ -7,8 +8,6 @@ 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 = 20; - void main(){ ivec2 outImageRes = imageSize(outMotionMax); diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp index 88fdca59..3b9992ed 100644 --- a/projects/indirect_dispatch/src/App.cpp +++ b/projects/indirect_dispatch/src/App.cpp @@ -89,7 +89,7 @@ void App::run() { float objectVerticalSpeed = 5; float motionBlurMinVelocity = 0.001; - int cameraShutterSpeedInverse = 30; + int cameraShutterSpeedInverse = 24; float motionVectorVisualisationRange = 0.008; glm::mat4 mvpPrevious = glm::mat4(1.f); -- GitLab