I'd like to create a frosted glass UI effect, similar to MacOS, Forza Horizon and others:

I can't find any shaders that work well. The best I could find was this, which is far from what I want:

shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;

const int samples = 32;
const int LOD = 2;          // gaussian done on MIPmap at scale LOD
const int sLOD = 1 << LOD;  // tile size = 2^LOD
const float sigma = float(samples) * 0.25;

float gaussian(vec2 i) {
    return exp(-0.5 * dot(i/sigma, i/sigma)) / (6.28 * sigma * sigma);
}

vec4 blur(sampler2D sp, vec2 uv, vec2 scale) {
    vec4 color = vec4(0.0);
    float total_weight = 0.0;
    int s = samples/sLOD;
    
    for (int i = 0; i < s*s; i++) {
        vec2 d = vec2(float(i%s), float(i/s)) * float(sLOD) - float(samples)/2.0;
        float weight = gaussian(d);
        color += textureLod(sp, uv + scale * d, float(LOD)) * weight;
        total_weight += weight;
    }
    
    // Normalize by total weight instead of alpha
    return color / total_weight;
}

void fragment() {
    vec2 uv = SCREEN_UV;
    vec2 texture_pixel_size = 1.0/vec2(textureSize(screen_texture, 0));
    
    COLOR = blur(screen_texture, uv, texture_pixel_size);
}

It shifts the blurred image and it does not blur the environment skybox.

Can anyone help?

  • xyz replied to this.
  • CryptoMares This is the effect of your 3 line shader I'm getting:

    How about now?

    shader_type canvas_item; uniform sampler2D t: hint_screen_texture, filter_linear_mipmap;
    void fragment(){COLOR = vec4(textureLod(t, SCREEN_UV, 4.0).rgb, 1.0);}

    CryptoMares it does not blur the environment skybox

    It should. Post a screenshot and your scene setup.

      xyz It's a debug panel inside of my character controller:

      Also as you can see, the blurred image is misaligned slightly:

      • xyz replied to this.

        CryptoMares Misalignment likely just a trivial issue of uv transformation. I'm more interested in environment not being affected, although that's not really visible in the screenshots.

        Where did you get that shader code?

          xyz On Shadertoy.

          This is the result of a few attempts to convert it for Godot 4 with AI. This is the original code:

          const int samples = 32,
                    LOD = 2,         // gaussian done on MIPmap at scale LOD
                    sLOD = 1 << LOD; // tile size = 2^LOD
          const float sigma = float(samples) * 0.25;
          float gaussian(vec2 i) {
              return exp( -.5* dot(i/=sigma,i) ) / ( 6.28 * sigma*sigma );
          }
          vec4 blur(sampler2D sp, vec2 U, vec2 scale) {
              vec4 O = vec4(0);  
              int s = samples/sLOD;
              
              for ( int i = 0; i < s*s; i++ ) {
                  vec2 d = vec2(i%s, i/s)*float(sLOD) - float(samples)/2.;
                  O += gaussian(d) * textureLod( sp, U + scale * d , float(LOD) );
              }
              
              return O / O.a;
          }
          void mainImage(out vec4 O, vec2 U) {
              O = blur( iChannel0, U/iResolution.xy, 1./iChannelResolution[0].xy );
          }
          • xyz replied to this.

            CryptoMares If this is for backgrounds, you may even not need to do any gaussian averaging. Just sample a small mipmap and let the bilinear filtering do the blur. Might be good enough.

            CryptoMares

            shader_type canvas_item; uniform sampler2D t: hint_screen_texture, filter_linear_mipmap;
            void fragment(){COLOR.rgb *= textureLod(t, SCREEN_UV, 4.0).rgb;}

              xyz

              I'm pretty happy with the blur here:

              shader_type canvas_item;
              
              uniform float blur_strength = 1.0; // Blur strength
              
              uniform float blur_amount : hint_range(0.0, 5.0) = 2.0;
              uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
              
              // Gaussian weight calculation
              float gaussian(vec2 i, float sigma) {
                  return exp(-0.5 * dot(i/sigma, i/sigma)) / (6.28318530718 * sigma * sigma);
              }
              
              void fragment() {
                  vec2 pixel_size = blur_strength / SCREEN_PIXEL_SIZE;
                  vec4 blur_color = vec4(0.0);
                  float total_weight = 0.0;
                  
                  // Sample size - adjust for quality vs performance
                  const int SAMPLE_COUNT = 15;
                  float sigma = blur_amount;
                  
                  // Perform blur
                  for (int x = -SAMPLE_COUNT; x <= SAMPLE_COUNT; x++) {
                      for (int y = -SAMPLE_COUNT; y <= SAMPLE_COUNT; y++) {
                          vec2 offset = vec2(float(x), float(y)) / pixel_size;
                          float weight = gaussian(offset, sigma);
                          blur_color += texture(SCREEN_TEXTURE, SCREEN_UV + offset) * weight;
                          total_weight += weight;
                      }
                  }
                  
                  // Normalize the result
                  COLOR = blur_color / total_weight;
              }

              The only problem now is misalignment:

              You said it would be easy to correct?

              EDIT: It turns out that the misalignment occurs because of the lens distortion post processing shader I have applied to the whole screen. I wonder if it's possible to make this blur shader to affect the already post-processed frames?

              • xyz replied to this.

                CryptoMares I'm pretty happy with the blur here:

                Why use 3 lines of code when you can use 30 eh? 😃

                  xyz It didn't work on my end, unfortunately. Don't know why.

                  This is the effect of your 3 line shader I'm getting:

                  • xyz replied to this.

                    CryptoMares It didn't work
                    CryptoMares Don't know why

                    If you want success in making computer programs, you need to cultivate active curiosity and hands-on problem solving skills.
                    The above statements reflect an attitude that's kinda opposite of that 🙁

                      CryptoMares This is the effect of your 3 line shader I'm getting:

                      How about now?

                      shader_type canvas_item; uniform sampler2D t: hint_screen_texture, filter_linear_mipmap;
                      void fragment(){COLOR = vec4(textureLod(t, SCREEN_UV, 4.0).rgb, 1.0);}

                      xyz If you want success in making computer programs, you need to cultivate active curiosity and hands-on problem solving skills. The above statements reflect an attitude that's kinda opposite of that 🙁

                      My brain is small - I'm simply working with what I've got 🤤

                      How about now?

                      Yes, this works well:

                      Thank you!