Shader code
shader_type canvas_item;
// Base layer
uniform bool use_base_texture = true;
uniform sampler2D base_texture : source_color;
uniform vec4 base_color : source_color = vec4(0.22, 0.24, 0.28, 1.0);
// Pattern layer
uniform bool use_pattern_texture = true;
uniform sampler2D pattern_texture : repeat_enable;
uniform float pattern_scale = 12.0;
uniform float pattern_strength : hint_range(0.0, 1.0, 0.001) = 0.18;
uniform float pattern_bias : hint_range(0.0, 1.0, 0.001) = 0.5;
uniform float pattern_rotation : hint_range(-180.0, 180.0, 0.1) = 0.0; // degrees
uniform vec2 pattern_scroll = vec2(0.0, 0.0);
// Blending controls
uniform bool use_dual_tone_pattern = true;
uniform float darken_strength : hint_range(0.0, 2.0, 0.001) = 0.9;
uniform float lighten_strength : hint_range(0.0, 2.0, 0.001) = 0.6;
// Extra controls
uniform float edge_fade_strength : hint_range(0.0, 1.0, 0.001) = 0.25;
uniform float brightness_response : hint_range(0.0, 2.0, 0.001) = 0.6;
uniform float alpha_strength : hint_range(0.0, 1.0, 0.001) = 0.0;
float luminance(vec3 c) {
return dot(c, vec3(0.2126, 0.7152, 0.0722));
}
vec2 rotate_uv(vec2 uv, float deg) {
float rad = radians(deg);
float s = sin(rad);
float c = cos(rad);
mat2 m = mat2(vec2(c, -s), vec2(s, c));
return m * uv;
}
void fragment() {
// 1) Build base color from base texture (optional) + base_color tint
vec4 sampled_base = vec4(1.0);
if (use_base_texture) {
sampled_base = texture(base_texture, UV);
}
vec4 base = sampled_base * base_color;
// 2) Pattern sampling (optional). Neutral value around pattern_bias.
float pattern_value = pattern_bias;
if (use_pattern_texture) {
vec2 p = UV - vec2(0.5);
p = rotate_uv(p, pattern_rotation);
vec2 pattern_uv = p * max(pattern_scale, 0.0001) + vec2(0.5) + pattern_scroll;
pattern_value = texture(pattern_texture, pattern_uv).r;
}
// 3) Convert pattern to signed perturbation around bias
float denom = max(pattern_bias, 1.0 - pattern_bias);
float signed_delta = (pattern_value - pattern_bias) / max(denom, 0.0001);
float dark_part = max(0.0, -signed_delta);
float light_part = max(0.0, signed_delta);
// 4) Edge fade to avoid clashing with frame borders
vec2 d = abs(UV - vec2(0.5)) * 2.0;
float edge_metric = clamp(max(d.x, d.y), 0.0, 1.0);
float edge_fade = mix(1.0, 1.0 - edge_metric, edge_fade_strength);
// 5) Brightness response: bright zones usually need weaker grain
float luma = luminance(base.rgb);
float brightness_factor = mix(1.0, 1.0 - luma, brightness_response);
float influence = pattern_strength * edge_fade * brightness_factor;
float darken = dark_part * darken_strength * influence;
float lighten = light_part * lighten_strength * influence;
vec3 shaded = base.rgb;
if (use_dual_tone_pattern) {
shaded = shaded * (1.0 - darken) + (1.0 - shaded) * lighten;
} else {
shaded = shaded * (1.0 - darken);
}
// Keep alpha readable; optionally let pattern affect alpha slightly
float alpha_mod = mix(1.0, 1.0 - darken + lighten * 0.5, alpha_strength);
float out_alpha = clamp(base.a * alpha_mod, 0.0, 1.0);
COLOR = vec4(clamp(shaded, 0.0, 1.0), out_alpha);
}
Live Preview
Tags
texture