From 3d19a3cd561cda7263d55808b5dc3c3b28d2da5c Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Wed, 18 Aug 2021 12:06:56 +0200
Subject: [PATCH] [#106] Adjusted velocity clamping, removed manual settings
 for min velocity and motion blur delta time limit

---
 .../resources/shaders/motionBlur.comp         | 20 ++++++++++---------
 projects/indirect_dispatch/src/App.cpp        |  7 ++-----
 projects/indirect_dispatch/src/MotionBlur.cpp |  7 ++-----
 projects/indirect_dispatch/src/MotionBlur.hpp |  3 +--
 .../src/MotionBlurConfig.hpp                  |  8 +-------
 5 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/projects/indirect_dispatch/resources/shaders/motionBlur.comp b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
index 58f95854..43981689 100644
--- a/projects/indirect_dispatch/resources/shaders/motionBlur.comp
+++ b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
@@ -12,8 +12,8 @@ layout(set=0, binding=5, 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 motionScaleFactor;  // computed from delta time and shutter speed
-    float minVelocity;
+    // computed from delta time and shutter speed
+    float motionScaleFactor;
     // camera planes are needed to linearize depth
     float cameraNearPlane;
     float cameraFarPlane;
@@ -76,12 +76,14 @@ vec2 processMotionVector(vec2 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;
+    float velocityPixels    = length(motionScaled * imageSize(outImage));
+    float epsilon           = 0.0001;
+    
+    // pixels are anisotropic, so the ratio for clamping the velocity is computed in pixels instead of uv coordinates
+    vec2 motionPixel = motionScaled * imageSize(outImage);
+    
     // 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);
+    return motionScaled * max(0.5, min(velocityPixels, motionTileSize)) / (velocityPixels + epsilon);
 }
 
 SampleData loadSampleData(vec2 uv){
@@ -122,8 +124,8 @@ void main(){
     
     SampleData mainPixel = loadSampleData(uv);
     
-    // early out on little movement
-    if(length(motionNeighbourhoodMax) <= minVelocity){
+    // early out on movement less than half a pixel
+    if(length(motionNeighbourhoodMax * imageSize(outImage)) <= 0.5){
         imageStore(outImage, coord, vec4(mainPixel.color, 0.f));
         return;
     }
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index 60c3a075..b27798b6 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -94,7 +94,6 @@ void App::run() {
 	float   objectVerticalSpeed             = 5;
 	float   objectAmplitude                 = 1;
 	float   objectMeanHeight                = 1;
-	float   motionBlurMinVelocity           = 0.001;
 	int     cameraShutterSpeedInverse       = 24;
 	float   motionVectorVisualisationRange  = 0.008;
 
@@ -114,7 +113,7 @@ void App::run() {
 	sceneObjects.push_back(ground);
 
 	Object sphere;
-	sphere.meshResources = m_sphereMesh;
+	sphere.meshResources = m_cubeMesh;
 	sphere.modelMatrixUpdate = [&](float time, Object& obj) {
 		const float currentHeight   = objectMeanHeight + objectAmplitude * glm::sin(time * objectVerticalSpeed);
 		obj.modelMatrix             = glm::translate(glm::mat4(1), glm::vec3(0, currentHeight, 0));
@@ -249,8 +248,7 @@ void App::run() {
 				cameraNear,
 				cameraFar,
 				fDeltaTimeSeconds,
-				cameraShutterSpeedInverse,
-				motionBlurMinVelocity);
+				cameraShutterSpeedInverse);
 		}
 		else {
 			eMotionVectorMode debugViewMode;
@@ -320,7 +318,6 @@ void App::run() {
 			static_cast<int>(eMotionVectorMode::OptionCount));
 
 		ImGui::InputInt("Camera shutter speed inverse", &cameraShutterSpeedInverse);
-		ImGui::DragFloat("Motion blur min velocity", &motionBlurMinVelocity, 0.01, 0, 1);
 
 		ImGui::InputFloat("Object movement speed",      &objectVerticalSpeed);
 		ImGui::InputFloat("Object movement amplitude",  &objectAmplitude);
diff --git a/projects/indirect_dispatch/src/MotionBlur.cpp b/projects/indirect_dispatch/src/MotionBlur.cpp
index cc1bbc82..a731b8b9 100644
--- a/projects/indirect_dispatch/src/MotionBlur.cpp
+++ b/projects/indirect_dispatch/src/MotionBlur.cpp
@@ -58,8 +58,7 @@ vkcv::ImageHandle MotionBlur::render(
 	const float                     cameraNear,
 	const float                     cameraFar,
 	const float                     deltaTimeSeconds,
-	const float                     cameraShutterSpeedInverse,
-	const float                     motionBlurMinVelocity) {
+	const float                     cameraShutterSpeedInverse) {
 
 	computeMotionTiles(cmdStream, motionBufferFullRes);
 
@@ -92,16 +91,14 @@ vkcv::ImageHandle MotionBlur::render(
 	// must match layout in "motionBlur.comp"
 	struct MotionBlurConstantData {
 		float motionFactor;
-		float minVelocity;
 		float cameraNearPlane;
 		float cameraFarPlane;
 	};
 	MotionBlurConstantData motionBlurConstantData;
 
-	const float deltaTimeMotionBlur = std::max(deltaTimeSeconds, MotionBlurConfig::timeScaleMax);
+	const float deltaTimeMotionBlur = deltaTimeSeconds;
 
 	motionBlurConstantData.motionFactor     = 1 / (deltaTimeMotionBlur * cameraShutterSpeedInverse);
-	motionBlurConstantData.minVelocity      = motionBlurMinVelocity;
 	motionBlurConstantData.cameraNearPlane  = cameraNear;
 	motionBlurConstantData.cameraFarPlane   = cameraFar;
 
diff --git a/projects/indirect_dispatch/src/MotionBlur.hpp b/projects/indirect_dispatch/src/MotionBlur.hpp
index ba72ea64..a6232125 100644
--- a/projects/indirect_dispatch/src/MotionBlur.hpp
+++ b/projects/indirect_dispatch/src/MotionBlur.hpp
@@ -31,8 +31,7 @@ public:
 		const float                     cameraNear,
 		const float                     cameraFar,
 		const float                     deltaTimeSeconds,
-		const float                     cameraShutterSpeedInverse,
-		const float                     motionBlurMinVelocity);
+		const float                     cameraShutterSpeedInverse);
 
 	vkcv::ImageHandle renderMotionVectorVisualisation(
 		const vkcv::CommandStreamHandle cmdStream,
diff --git a/projects/indirect_dispatch/src/MotionBlurConfig.hpp b/projects/indirect_dispatch/src/MotionBlurConfig.hpp
index ecd7f8f8..bdeb8acf 100644
--- a/projects/indirect_dispatch/src/MotionBlurConfig.hpp
+++ b/projects/indirect_dispatch/src/MotionBlurConfig.hpp
@@ -4,11 +4,5 @@
 namespace MotionBlurConfig {
 	const vk::Format    motionVectorTileFormat  = vk::Format::eR16G16Sfloat;
 	const vk::Format    outputColorFormat       = vk::Format::eB10G11R11UfloatPack32;
-	const uint32_t      maxMotionTileSize       = 20;	// must match "motionTileSize" in motionVectorMax.comp
-
-	// small mouse movements are restricted to pixel level and therefore quite unprecise
-	// therefore extrapolating movement at high framerates results in big jerky movements
-	// this results in wide sudden motion blur, which looks quite bad
-	// as a workaround the time scale is limited to a maximum value
-	const float timeScaleMax = 1.f / 60;
+	const uint32_t      maxMotionTileSize       = 20;	// must match "motionTileSize" in motionBlurConfig.inc
 }
\ No newline at end of file
-- 
GitLab