shader_type canvas_item; varying vec2 quad_uv; uniform vec2 ball_0; uniform vec2 ball_1; uniform vec2 ball_2; uniform vec2 rect_size = vec2(1920, 1080); uniform float ball_radius = 12.0; uniform float cam_zoom = 1.0; uniform vec2 cam_pos = vec2(0.0); uniform float threshold : hint_range(0.0, 1.0) = 0.5; uniform vec4 color : source_color = vec4(0.3, 0.5, 0.2, 1.0); uniform sampler2D noise_tex : repeat_enable; void vertex() { quad_uv = UV; } float field(vec2 pos) { return (ball_radius * cam_zoom) / max(length(quad_uv * rect_size - pos), 1.0); } void fragment() { float sum = field(ball_0) + field(ball_1) + field(ball_2); float a = smoothstep(threshold - 0.05, threshold, sum); vec2 screen_px = quad_uv * rect_size; vec2 world_px = (screen_px - rect_size * 0.5) / cam_zoom + cam_pos; float n1 = texture(noise_tex, world_px * 0.0005).r; float n2 = texture(noise_tex, world_px * 0.0008 + 0.33).r; float hue_shift = (n1 - 0.5) * 0.12; float value_shift = (n2 - 0.5) * 0.15; vec3 shifted = color.rgb + vec3(hue_shift * 0.5, hue_shift, -hue_shift * 0.5) + value_shift; COLOR = vec4(shifted, a * color.a); }