precision highp float; #define MEAN_SAMPLE 8 // quality setting: 2, 4 or 8 varying vec2 v_TexCoords; uniform sampler2D u_Texture; uniform vec2 u_RenderSize; // tweakable parameters uniform float uSmoothing; void main() { const int kernelSize = 15; int smallKernelSize = ((kernelSize + 1) / MEAN_SAMPLE) + 1; float smallKernelSizeRcp = 1.0 / (float(smallKernelSize) * float(smallKernelSize)); vec2 uv = vec2(v_TexCoords.x, 1.0 - v_TexCoords.y); vec2 duv = 1.0 / u_RenderSize; vec2 uv0 = uv - 0.5 * duv * float(smallKernelSize - 1); vec4 meanIp = vec4(0.0); vec4 corrIp = vec4(0.0); for (int j = 0; j < smallKernelSize; j++) { for (int i = 0; i < smallKernelSize; i++) { vec2 texc = uv0 + duv * vec2(float(i), float(j)); vec4 tex = texture2D(u_Texture, texc); meanIp += tex; corrIp += tex.w * tex; } } meanIp *= smallKernelSizeRcp; corrIp *= smallKernelSizeRcp; vec4 varIp = corrIp - meanIp.w * meanIp; float epsilon = uSmoothing; float epsilon2 = epsilon * epsilon; float a = varIp.w / (varIp.w + epsilon2); // clamp to prevent negative values a = max(a, 0.0); vec3 b = meanIp.xyz - a * meanIp.xyz; gl_FragColor = vec4(b, a); }