Waving Chequered Flag

Waving flag with adjustable check size, colours, wave parameters, edge softness and psuedo specular shading.

Just apply shader to ColorRect or similar.

Shader code
shader_type canvas_item;

uniform vec4 color_dark : source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform vec4 color_light : source_color = vec4(1.0, 1.0, 1.0, 1.0);

uniform int checks_horizontal : hint_range(2, 32) = 12;
uniform int checks_vertical : hint_range(2, 32) = 7;

uniform float wave_amplitude_y : hint_range(0.0, 0.25) = 0.05;
uniform float wave_frequency_y : hint_range(0.1, 5.0) = 1.2;
uniform float wave_speed_y : hint_range(0.0, 5.0) = 1.8;

uniform float wave_amplitude_x : hint_range(0.0, 0.25) = 0.01;
uniform float wave_frequency_x : hint_range(0.1, 5.0) = 2.5;
uniform float wave_speed_x : hint_range(0.0, 5.0) = 2.0;

uniform float specular_strength : hint_range(0.0, 0.5) = 0.5;
uniform float specular_falloff : hint_range(0.1, 2.0) = 1.5;

uniform float edge_softness : hint_range(0.001, 0.02) = 0.008;

void fragment() {
    vec2 uv = UV;
    

    float phase_y = uv.x * wave_frequency_y * 6.28318 + TIME * wave_speed_y;
    float wave_y = sin(phase_y);
    float wave_offset_y = wave_y * wave_amplitude_y;
    

    float phase_x = uv.y * wave_frequency_x * 6.28318 + TIME * wave_speed_x;
    float wave_x = sin(phase_x);
    float wave_offset_x = wave_x * wave_amplitude_x;
    

    float margin_y = wave_amplitude_y + 0.05;
    float margin_x = wave_amplitude_x + 0.05;
    float flag_height = 1.0 - (margin_y * 2.0);
    float flag_width = 1.0 - (margin_x * 2.0);
    

    float flag_y = (uv.y - margin_y) / flag_height;
    float flag_x = (uv.x - margin_x) / flag_width;
    

    float warped_y = flag_y + wave_offset_y;
    float warped_x = flag_x + wave_offset_x;
    
    // Check if we're within flag bounds
    float top_edge = smoothstep(0.0 - edge_softness, 0.0 + edge_softness, warped_y);
    float bottom_edge = smoothstep(1.0 + edge_softness, 1.0 - edge_softness, warped_y);
    float left_edge = smoothstep(0.0 - edge_softness, 0.0 + edge_softness, warped_x);
    float right_edge = smoothstep(1.0 + edge_softness, 1.0 - edge_softness, warped_x);
    float alpha = top_edge * bottom_edge * left_edge * right_edge;
    

    if (alpha < 0.01) {
        discard;
    }
    
    float dist_from_peak_y = 1.0 - wave_y; 
    float dist_from_peak_x = 1.0 - wave_x;
    

    float highlight_y = exp(-dist_from_peak_y / specular_falloff);
    float highlight_x = exp(-dist_from_peak_x / specular_falloff);
  
    float specular = (highlight_y + highlight_x) * 0.5 * specular_strength;
    
    vec2 checker_uv = vec2(warped_x, warped_y);
    float check_x = floor(checker_uv.x * float(checks_horizontal));
    float check_y = floor(checker_uv.y * float(checks_vertical));
    float checker = mod(check_x + check_y, 2.0);
    
    vec4 base_color = mix(color_dark, color_light, checker);

    vec3 final_rgb = base_color.rgb + vec3(specular);
    
    COLOR = vec4(final_rgb, base_color.a * alpha);
}
Tags
check, Checkered flag, flag
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 beebster

Player Vignette

Related shaders

Waving Particles

2D simple animated flag shader

3D simple animated flag shader

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments