splatmap_tile_V2

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;
}
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.

More from buddhanomad

best 2d fire

3D wind sway shader with wind mask texture controll

simple static shader optimized for lowpoly game

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments