#version 300 es precision highp float; // highp: fullscreen UV addressing (mediump fp16 is not enough on mobile) in vec2 vTexCoord; uniform mediump sampler2D u_tex; uniform vec2 u_direction; // (texelSize.x, 0) for H, (0, texelSize.y) for V out vec4 fragColor; // 9-tap Gaussian (sigma ≈ 2) in 5 fetches: each side-tap pair collapses into one bilinear fetch // at the weight-averaged offset — requires GL_LINEAR filtering on the source const float w0 = 0.2270270270; const float w1 = 0.3162162162; // taps 1+2 combined const float w2 = 0.0702702703; // taps 3+4 combined const float o1 = 1.3846153846; const float o2 = 3.2307692308; void main() { vec3 result = texture(u_tex, vTexCoord).rgb * w0; vec2 d = u_direction; result += texture(u_tex, vTexCoord + d * o1).rgb * w1; result += texture(u_tex, vTexCoord - d * o1).rgb * w1; result += texture(u_tex, vTexCoord + d * o2).rgb * w2; result += texture(u_tex, vTexCoord - d * o2).rgb * w2; fragColor = vec4(result, 1.0); }