From d3c4a125845cc1d5767bd86e11ba23c64b70ec89 Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Fri, 20 Aug 2021 17:28:55 +0200
Subject: [PATCH] [#106] Replace motion tile offset noise with unaligned dither
 for less visible noise

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

diff --git a/projects/indirect_dispatch/resources/shaders/motionBlur.comp b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
index 804c0ceb..503a7afa 100644
--- a/projects/indirect_dispatch/resources/shaders/motionBlur.comp
+++ b/projects/indirect_dispatch/resources/shaders/motionBlur.comp
@@ -113,34 +113,18 @@ SampleData loadSampleData(vec2 uv){
     return data;
 }
 
+const int ditherSize = 4;
+
 // simple binary dither pattern
 // could be optimized to avoid modulo and branch
 float dither(ivec2 coord){
     
-    int ditherSize = 4;
-    
     bool x = coord.x % ditherSize < (ditherSize / 2);
     bool y = coord.y % ditherSize < (ditherSize / 2);
     
     return x ^^ y ? 1 : 0;
 }
 
-// from https://www.shadertoy.com/view/ttc3zr
-uvec2 murmurHash22(uvec2 src) {
-    const uint M = 0x5bd1e995u;
-    uvec2 h = uvec2(1190494759u, 2147483647u);
-    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;
-}
-
-vec2 hash22(vec2 src) {
-    uvec2 h = murmurHash22(floatBitsToUint(src));
-    return uintBitsToFloat(h & 0x007fffffu | 0x3f800000u) - 1.0;
-}
-
-
 void main(){
 
     if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outImage))))
@@ -151,7 +135,8 @@ void main(){
     vec2    uv          = vec2(coord + 0.5) / textureRes;   // + 0.5 to shift uv into pixel center
     
     // the motion tile lookup is jittered, so the hard edges in the blur are replaced by noise
-    vec2 motionOffset           = motionTileOffsetLength * (hash22(coord) * 2 - 1) / textureRes;
+    // dither is shifted, so it does not line up with motion tiles
+    vec2 motionOffset           = motionTileOffsetLength * (dither(coord + ivec2(ditherSize / 2)) * 2 - 1) / textureRes;
     vec2 motionNeighbourhoodMax = processMotionVector(texture(sampler2D(inMotionNeighbourhoodMax, nearestSampler), uv + motionOffset).rg);
     
     SampleData mainPixel = loadSampleData(uv);
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index 230ef92c..cc7bff04 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -97,7 +97,7 @@ void App::run() {
 	eMotionVectorMode               motionBlurMotionMode            = eMotionVectorMode::MaxTileNeighbourhood;
 
 	bool    freezeFrame                     = false;
-	float   motionBlurTileOffsetLength      = 10;
+	float   motionBlurTileOffsetLength      = 3;
 	float   objectVerticalSpeed             = 5;
 	float   objectAmplitude                 = 0;
 	float   objectMeanHeight                = 1;
-- 
GitLab