Earthbound Background Shader

Setup:

Create any base node (2D Nodes, like control and Node2D)
Create a TextureRect
Apply your texture, set to tile (it should be a looping background or else itll kinda screw itself), and attach the shader as a material
set the viewport size or else it will literally not work, tweak the settings then kaboom, earthbound background

Shader code
//Shader created by roteroam

shader_type canvas_item;

uniform float horizontal_oscillation : hint_range(0.0, 1, 0.001) = 0.01;
uniform float vertical_oscillation : hint_range(0.0, 1, 0.001) = 0.01;
uniform float scanline_wave_frequency : hint_range(1.0, 100.0, 0.1) = 40.0;
uniform float scanline_wave_speed : hint_range(0.0, 10.0, 0.1) = 2.0;
uniform bool alternate_direction = true;

uniform vec2 viewport_size;

uniform float hue_shift_speed : hint_range(0.0, 5.0, 0.01) = 0.5;
uniform float hue_strength : hint_range(0.0, 1.0, 0.01) = 1.0;

vec3 rgb2hsv(vec3 c) {
    vec4 K = vec4(0., -1./3., 2./3., -1.);
    vec4 p = mix(vec4(c.bg, K.wz),
                 vec4(c.gb, K.xy),
                 step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r),
                 vec4(c.r, p.yzx),
                 step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1e-10;
    return vec3(abs((q.w - q.y) / (6. * d + e)),
                d / (q.x + e),
                q.x);
}

vec3 hsv2rgb(vec3 c) {
    vec3 rgb = clamp(abs(mod(c.x * 6. + vec3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.);
    return c.z * mix(vec3(1.), rgb, c.y);
}

void fragment() {
    vec2 uv = UV;
    float pixel_y = SCREEN_UV.y * viewport_size.y;
    int scanline = int(floor(pixel_y));
    float wave = sin(pixel_y / scanline_wave_frequency + TIME * scanline_wave_speed);
    float x_offset = wave * horizontal_oscillation;
    if (alternate_direction && (scanline % 2 == 1)) {
        x_offset = -x_offset;
    }
    float y_offset = wave * vertical_oscillation;

    uv.x += x_offset;
    uv.y += y_offset;

    vec4 tex_color = texture(TEXTURE, uv);
    if (tex_color.a == 0.0) {
        COLOR = tex_color;
    }
    vec3 hsv = rgb2hsv(tex_color.rgb);
    hsv.x = mod(hsv.x + TIME * hue_shift_speed * hue_strength, 1.0);
    vec3 scrolled_color = hsv2rgb(hsv);

    COLOR = vec4(scrolled_color, tex_color.a);
}
Tags
background, earthbound, godot 4, Oscillation, Scanline
The shader code and all code snippets in this post are under GNU GPL v.3 license and can be used freely. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Earthbound-like battle background shader w/scroll effect and palette cycling

Earthbound color swap, double elice

2D Water Themed Background Shader

guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Milet
3 months ago

holy shit this one is so cool