From 51330d76cd6388804ee96b59a3d7339d30016b7b Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Mon, 16 Aug 2021 21:32:34 +0200
Subject: [PATCH] [#106] Add motion blur filter jitter to reduce banding

---
 .../resources/shaders/motionBlur.comp         | 23 +++++++++++++++++--
 projects/indirect_dispatch/src/App.cpp        |  6 +++--
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/projects/indirect_dispatch/resources/shaders/motionBlur.comp b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
index 713a8775..233947d1 100644
--- a/projects/indirect_dispatch/resources/shaders/motionBlur.comp
+++ b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
@@ -15,6 +15,7 @@ layout( push_constant ) uniform constants{
     // camera planes are needed to linearize depth
     float cameraNearPlane;
     float cameraFarPlane;
+    float time;
 };
 
 float linearizeDepth(float depth, float near, float far){
@@ -76,6 +77,21 @@ SampleData loadSampleData(vec2 uv){
     return data;
 }
 
+// simple hash/noise function from: https://www.shadertoy.com/view/ttc3zr
+uint murmurHash12(uvec2 src) {
+    const uint M = 0x5bd1e995u;
+    uint h = 1190494759u;
+    src *= M; src ^= src>>24u; src *= M;
+    h *= M; h ^= src.x; h *= M; h ^= src.y;
+    h ^= h>>13u; h *= M; h ^= h>>15u;
+    return h;
+}
+
+float hash12(vec2 src) {
+    uint h = murmurHash12(floatBitsToUint(src));
+    return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
+}
+
 void main(){
 
     if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage))))
@@ -89,7 +105,7 @@ void main(){
     
     // early out on little movement
     if(mainPixel.velocity <= minVelocity){
-        vec3 color = texture(sampler2D(inColor, nearestSampler), uv).rgb;
+        vec3 color = texture(sampler2D(inColor, nearestSampler), uv).rgb;        
         imageStore(outImage, coord, vec4(color, 0.f));
         return;
     }
@@ -109,8 +125,11 @@ void main(){
     vec2 uvStart    = clamp(uv - mainPixel.motion, 0, 1);
     vec2 uvEnd      = clamp(uv + mainPixel.motion, 0, 1);
     
+    // samples are placed evenly, but the entire filter is jittered
+    float random = hash12(uv + time) - 0.5; // in range [-0.5, 0.5]
+    
     for(int i = 0; i < sampleCount; i++){
-        vec2    sampleUV    = mix(uvStart, uvEnd, i / float(sampleCount - 1));
+        vec2    sampleUV    = mix(uvStart, uvEnd, (i + random + 1) / float(sampleCount + 1));
         vec3    sampleColor = texture(sampler2D(inColor, nearestSampler), sampleUV).rgb;
         
         SampleData  samplePixel     = loadSampleData(sampleUV);
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index 69b5db3e..0856173a 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -305,6 +305,7 @@ void App::run() {
 			float minVelocity;
 			float cameraNearPlane;
 			float cameraFarPlane;
+			float time;
 		};
 		MotionBlurConstantData motionBlurConstantData;
 
@@ -320,8 +321,9 @@ void App::run() {
 
 		float cameraNear, cameraFar;
 		m_cameraManager.getActiveCamera().getNearFar(cameraNear, cameraFar);
-		motionBlurConstantData.cameraNearPlane = cameraNear;
-		motionBlurConstantData.cameraFarPlane  = cameraFar;
+		motionBlurConstantData.cameraNearPlane  = cameraNear;
+		motionBlurConstantData.cameraFarPlane   = cameraFar;
+		motionBlurConstantData.time             = fCurrentTime;
 
 		vkcv::PushConstants motionBlurPushConstants(sizeof(motionBlurConstantData));
 		motionBlurPushConstants.appendDrawcall(motionBlurConstantData);
-- 
GitLab