shader_type canvas_item; render_mode unshaded; uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap; uniform float motion_blur_amount : hint_range(0.0, 0.03) = 0.0; uniform float chromatic_aberration : hint_range(0.0, 0.02) = 0.0; uniform float vignette_strength : hint_range(0.0, 1.0) = 0.22; vec4 motion_sample(vec2 uv) { // A restrained centre-directed velocity smear. The camera script scales it // with ship speed/turbo; mipmapped screen reads soften the outer samples. if (motion_blur_amount < 0.0001) { return textureLod(screen_texture, uv, 0.0); } vec2 step_uv = (uv - vec2(0.5)) * motion_blur_amount; vec4 color = textureLod(screen_texture, uv, 0.0) * 0.36; color += textureLod(screen_texture, uv - step_uv * 0.35, 0.5) * 0.25; color += textureLod(screen_texture, uv - step_uv * 0.7, 1.0) * 0.21; color += textureLod(screen_texture, uv - step_uv, 1.5) * 0.18; return color; } void fragment() { vec2 radial = UV - vec2(0.5); vec2 chroma = radial * chromatic_aberration; vec4 center = motion_sample(UV); vec3 color = center.rgb; // The branch is driven by one uniform for the whole draw, so non-turbo // frames avoid eight redundant screen taps without causing warp divergence. if (chromatic_aberration > 0.0001) { color.r = motion_sample(UV + chroma).r; color.b = motion_sample(UV - chroma).b; } // Aspect-correct vignette, always subtle and tightened slightly on turbo. vec2 aspect_radial = radial; aspect_radial.x *= SCREEN_PIXEL_SIZE.y / SCREEN_PIXEL_SIZE.x; float vignette = smoothstep(0.38, 0.78, length(aspect_radial)); color *= 1.0 - vignette * vignette_strength; COLOR = vec4(color, 1.0); }