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 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 . Since we also have the **v** texture coordinate, the same will apply to it, which means α will be a 2D vector:

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); }

To see the WebGL demo in action, click here.

## Final thoughts

We have presented a more general approach to the manual texture filter previously discussed. Despite its advantage of automatically detecting the best α for the polygon being rendered, it depends on an OpenGL ES extension that might not be available on certain devices. Add that to the performance impact of the dFdx/dFdy functions, the previous method will certainly be preferred should your polygon not change in size during your game.

It’s also important to notice that, under small magnifications, the texture can look a bit blurry depending on the value **k** that was chosen.