给纯色单调的图片增加一层明暗纹理的shader

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
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments