Shader code
shader_type canvas_item;
// Red channel overlays
uniform sampler2D overlay_tex_red : repeat_enable, filter_nearest;
uniform sampler2D another_overlay_tex_red : repeat_enable, filter_nearest;
// Green channel overlays
uniform sampler2D overlay_tex_green : repeat_enable, filter_nearest;
uniform sampler2D another_overlay_tex_green : repeat_enable, filter_nearest;
// Blue channel overlays
uniform sampler2D overlay_tex_blue : repeat_enable, filter_nearest;
uniform sampler2D another_overlay_tex_blue : repeat_enable, filter_nearest;
// Individual noise textures for each channel
uniform sampler2D noise_tex_red : repeat_enable, filter_nearest;
uniform sampler2D noise_tex_green : repeat_enable, filter_nearest;
uniform sampler2D noise_tex_blue : repeat_enable, filter_nearest;
// Scale and rotation uniforms
uniform vec2 scale_r = vec2(0.02, 0.02);
uniform float angle_r = 0.0;
uniform vec2 scale_g = vec2(0.02, 0.02);
uniform float angle_g = 0.0;
uniform vec2 scale_b = vec2(0.02, 0.02);
uniform float angle_b = 0.0;
uniform vec2 global_scale = vec2(1.0, 1.0);
uniform float scale_multiplier = 1.0;
varying vec2 world_position;
varying vec2 tile_uv;
// Rotate UV coordinates by a given angle
vec2 rotateUV(vec2 uv, float angle) {
float s = sin(angle);
float c = cos(angle);
return vec2(c * uv.x - s * uv.y, s * uv.x + c * uv.y);
}
void vertex() {
world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0, 1.0)).xy;
tile_uv = UV;
}
void fragment() {
// Combine scales with global scale and multiplier
vec2 combined_scale_r = (scale_r * global_scale) / scale_multiplier;
vec2 combined_scale_g = (scale_g * global_scale) / scale_multiplier;
vec2 combined_scale_b = (scale_b * global_scale) / scale_multiplier;
// Sample base texture and compute its size for snapping
vec4 base_color = texture(TEXTURE, tile_uv);
vec2 base_tex_size = 1.0 / TEXTURE_PIXEL_SIZE;
vec2 snapped_world_pos = floor(world_position * base_tex_size) / base_tex_size;
// Compute overlay UVs for each channel
vec2 overlay_uv_r = snapped_world_pos * combined_scale_r;
vec2 overlay_uv_g = snapped_world_pos * combined_scale_g;
vec2 overlay_uv_b = snapped_world_pos * combined_scale_b;
// Apply individual rotations
overlay_uv_r = rotateUV(overlay_uv_r, angle_r);
overlay_uv_g = rotateUV(overlay_uv_g, angle_g);
overlay_uv_b = rotateUV(overlay_uv_b, angle_b);
// Snap UVs to texel centers for red overlay
ivec2 red_tex_size_i = textureSize(overlay_tex_red, 0);
vec2 red_tex_size = vec2(red_tex_size_i);
overlay_uv_r = (floor(overlay_uv_r * red_tex_size) + 0.5) / red_tex_size;
// Snap UVs for green overlay
ivec2 green_tex_size_i = textureSize(overlay_tex_green, 0);
vec2 green_tex_size = vec2(green_tex_size_i);
overlay_uv_g = (floor(overlay_uv_g * green_tex_size) + 0.5) / green_tex_size;
// Snap UVs for blue overlay
ivec2 blue_tex_size_i = textureSize(overlay_tex_blue, 0);
vec2 blue_tex_size = vec2(blue_tex_size_i);
overlay_uv_b = (floor(overlay_uv_b * blue_tex_size) + 0.5) / blue_tex_size;
// Sample individual noise textures for each channel
vec2 noise_uv_red = tile_uv * vec2(10.0, 10.0); // Adjust scale as needed
float noise_value_red = texture(noise_tex_red, noise_uv_red).r;
vec2 noise_uv_green = tile_uv * vec2(10.0, 10.0); // Adjust scale as needed
float noise_value_green = texture(noise_tex_green, noise_uv_green).r;
vec2 noise_uv_blue = tile_uv * vec2(10.0, 10.0); // Adjust scale as needed
float noise_value_blue = texture(noise_tex_blue, noise_uv_blue).r;
// Blend overlays for each channel using their respective noise values
vec4 overlay_red_1 = texture(overlay_tex_red, overlay_uv_r);
vec4 overlay_red_2 = texture(another_overlay_tex_red, overlay_uv_r);
vec4 mixed_overlay_red = mix(overlay_red_1, overlay_red_2, noise_value_red);
vec4 overlay_green_1 = texture(overlay_tex_green, overlay_uv_g);
vec4 overlay_green_2 = texture(another_overlay_tex_green, overlay_uv_g);
vec4 mixed_overlay_green = mix(overlay_green_1, overlay_green_2, noise_value_green);
vec4 overlay_blue_1 = texture(overlay_tex_blue, overlay_uv_b);
vec4 overlay_blue_2 = texture(another_overlay_tex_blue, overlay_uv_b);
vec4 mixed_overlay_blue = mix(overlay_blue_1, overlay_blue_2, noise_value_blue);
// Define strict channel masks based on the base texture
float mask_r = step(0.9, base_color.r) * (1.0 - step(1.0, base_color.g + base_color.b));
float mask_g = step(0.9, base_color.g) * (1.0 - step(1.0, base_color.r + base_color.b));
float mask_b = step(0.9, base_color.b) * (1.0 - step(1.0, base_color.r + base_color.g));
// Apply the blended overlays based on the channel masks
vec4 final_color = base_color;
final_color = mix(final_color, mixed_overlay_red, mask_r);
final_color = mix(final_color, mixed_overlay_green, mask_g);
final_color = mix(final_color, mixed_overlay_blue, mask_b);
// Handle alpha thresholding
final_color.a *= step(0.5, base_color.a);
if (final_color.a < 0.01) discard;
COLOR = final_color;
}