The Code Therapy

Fast Denoiser

Fast GLSL Denoiser test

Created by marcogomez on Sun, 06 Oct 2024 18:08:12 GMT.


#version 300 es
precision highp float;

uniform sampler2D eTexture0; // https://i.imgur.com/4n0yu8z.jpeg
uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;

in vec2 vUv;
out vec4 fragColor;

const float PI = acos(-1.0);
const float goldenAngle = 3.0 * PI - sqrt(5.0) * PI;
const float pixelMultiplier = 1.5;
const float inverseHUETolerance = 20.0;
const int samples = 20;
const float distBias = 0.6;

#define pow(a,b) pow(max(a,0.0), b)

mat2 rotate = mat2(
  cos(goldenAngle),
  sin(goldenAngle),
  -sin(goldenAngle),
  cos(goldenAngle)
);

vec3 denoise(in sampler2D tex, in vec2 uv, in vec2 res) {
  vec3 denoised = vec3(0.0);
  const float sampleRadius = sqrt(float(samples));
  const float sampleTrueRadius = 0.5 / (sampleRadius * sampleRadius);
  vec2 samplePixel = vec2(1.0 / res.x, 1.0 / res.y);
  vec3 sampleCenter = texture(tex, uv).rgb;
  vec3 sampleCenterNorm = normalize(sampleCenter);
  float sampleCenterSat = length(sampleCenter);
  float influenceSum = 0.0;
  float brightnessSum = 0.0;
  vec2 pixelRotated = vec2(0.0, 1.0);

  for (float x = 0.0; x <= float(samples); x++) {
    pixelRotated *= rotate;
    vec2 offset = pixelMultiplier * pixelRotated * sqrt(x) * 0.5;
    float influence = 1.0 - sampleTrueRadius * pow(dot(offset, offset), distBias);
    offset *= samplePixel;
    vec3 denoisedCol = texture(tex, uv + offset).rgb;
    influence *= influence * influence;
    influence *= (
      pow(0.5 + 0.5 * dot(sampleCenterNorm, normalize(denoisedCol)), inverseHUETolerance) *
      pow(1.0 - abs(length(denoisedCol) - length(sampleCenterSat)), 8.0)
    );
    influenceSum += influence;
    denoised += denoisedCol * influence;
  }
  return denoised / influenceSum;
}

float osc(float s, float e, float t) {
  return (e - s) * 0.5 + s + sin(t) * (e - s) * 0.5;
}

void main(void) {
  vec2 uv = vUv;
  vec3 col = texture(eTexture0, uv).rgb;
  float m = mouse.x * 0.5 + 0.5;
  float o = osc(0.0, 1.0, time * 0.5);
  // o = m;
  if (uv.x < o) {
    col = denoise(eTexture0, uv, vec2(512, 512)).rgb;
  }
  if (abs(uv.x - o) < 1.0 / resolution.x) {
    col = vec3(0.0, 1.0, 0.0);
  }
  fragColor = vec4(col, 1.0);
}