«

Godot - Blue Noise Distance Fading

August 25, 2024

Blue Noise vs Interleaved Gradient Noise

Blue Noise vs Interleaved Gradient Noise

A quick Godot shader for using blue noise instead of interleaved gradient noise for the material distance fade option. The blue noise texture is from: momentsingraphics.de I'm using the red channel with the LDR_RGB1_0.png 512px file, but the smaller images also work, such as HDR_RGB_0.png in 128px or 256px. Ensure that compression is disabled in the Godot import settings otherwise the results are blocky.

Shader Code Download

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;

uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap, repeat_enable;

// Bluenoise texture from: http://momentsingraphics.de/BlueNoise.html
// Ensure compression is disabled.
uniform sampler2D texture_blue_noise : hint_default_white, filter_nearest, repeat_enable;
uniform float distance_fade_min : hint_range(0.0, 4096.0, 0.01);
uniform float distance_fade_max : hint_range(0.0, 4096.0, 0.01);
uniform float point_size : hint_range(0.1, 128.0, 0.1);

uniform float roughness : hint_range(0.0, 1.0);
uniform sampler2D texture_metallic : hint_default_white, filter_linear_mipmap, repeat_enable;
uniform vec4 metallic_texture_channel;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap, repeat_enable;

uniform float specular : hint_range(0.0, 1.0, 0.01);
uniform float metallic : hint_range(0.0, 1.0, 0.01);

uniform vec3 uv1_scale;
uniform vec3 uv1_offset;
uniform vec3 uv2_scale;
uniform vec3 uv2_offset;


void vertex() {
  UV = UV * uv1_scale.xy + uv1_offset.xy;
}

void fragment() {
  vec2 base_uv = UV;

  vec4 albedo_tex = texture(texture_albedo, base_uv);
  ALBEDO = albedo.rgb * albedo_tex.rgb;

  float metallic_tex = dot(texture(texture_metallic, base_uv), metallic_texture_channel);
  METALLIC = metallic_tex * metallic;
  SPECULAR = specular;

  vec4 roughness_texture_channel = vec4(1.0, 0.0, 0.0, 0.0);
  float roughness_tex = dot(texture(texture_roughness, base_uv), roughness_texture_channel);
  ROUGHNESS = roughness_tex * roughness;


  {
    float ratio = VIEWPORT_SIZE.x / VIEWPORT_SIZE.y;
    ivec2 blue_size = textureSize(texture_blue_noise,0);
    vec2 frag_screen_uv = vec2(mix(0.5, FRAGCOORD.x/float(blue_size.x), ratio),FRAGCOORD.y/float(blue_size.y));
    vec4 blue_tex = texture(texture_blue_noise, frag_screen_uv);

    // Distance Fade: Blue Noise Dither
    float fade_distance = length(VERTEX);
    float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);
    // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
    if (fade < 0.001 || fade < blue_tex.r) {
      discard;
    }
    ALPHA = 1.0;
  }
}

License: Zero-Clause BSD