# Superior texture filter for dynamic pixel art upscaling

This article is an extension to a previously discussed topic: How to perform large texture magnification for pixelated games without aliasing between texels. My first post described a method to achieve this by assuming that, during the whole time, your polygons remain approximately at the same size after they are rendered.

## Constant pixels with variable α

The ideal value for the α parameter will depend on how many pixels are filling each texel after the texture is rendered. To have a smooth transition between texels without blurring them under extreme magnifications, nor aliasing them under small magnifications, we can have the number of pixels at the edge of each texel being constant, regardless of how far the polygon is.

The derivative $\frac{wdu}{dx}$ gives how many texels there are for each screen pixel, which is smaller than 1.0 when the texture is magnified. Therefore, if you want to have k pixels at the edge of your texels, your α must be $k\frac{wdu}{dx}$. Since we also have the v texture coordinate, the same will apply to it, which means α will be a 2D vector:

$k\langle\frac{wdu}{dx},\frac{hdv}{dy}\rangle$

This should give you an antialiased magnification that works independently of the polygon position, as shows the figure below:

## WebGL implementation

The derivatives with respect to screen space can be calculated by functions dFdx and dFdy, but in OpenGL ES/WebGL they require the extension GL_OES_standard_derivatives. As of Three.js r84, this extension can be activated by setting the derivatives property of your shader material object to true.

Our vertex shader remains the same as in our previous post:

varying vec2 vUv;

void main()
{
const float w = 32.0;
const float h = 64.0;

vUv = uv * vec2(w, h);
gl_Position = projectionMatrix * modelViewMatrix *
vec4(position, 1.0 );
}


The few modifications will come in the fragment shader:

precision highp float;

varying vec2 vUv;
uniform sampler2D texSampler;

void main(void) {
const float w = 32.0;
const float h = 64.0;

// I chose this k because it looked nice in
// my demo
vec2 alpha = 0.7 * vec2(dFdx(vUv.x),
dFdy(vUv.y));
vec2 x = fract(vUv);
vec2 x_ = clamp(0.5 / alpha * x, 0.0, 0.5) +
clamp(0.5 / alpha * (x - 1.0) + 0.5,
0.0, 0.5);

vec2 texCoord = (floor(vUv) + x_) / vec2(w, h);
gl_FragColor = texture2D(texSampler, texCoord);
}