Subpixel Rendering
When rendering small textures and scaling them up (as done with assets in pixel art games), a problem arises when using simple nearest neighbour sampling at scaling levels that are not multiples of 2.
When this problem occurs, you can notice a shimmering effect when zooming in/out or moving the camera around. This happens because some texels in the fragment shader get oversampled while others get undersampled.
Solution
"The idea (courtesy d7) is to interpolate the texture position along the pixel to create subpixel motion, with the help of linear blending To get nice results, you need to pad everything it applies to (it can't interpolate the edge of a primitive), and it only works on zoomed-in things (because, if you weren't using "fat pixels" zoomed-in art, the edge getting antialiased is just art, rather than the edge of a pixel) It also works in pixel space, rather than normalized texture coordinates"
vec2 subpixelAA(vec2 pixel, vec2 zoom) { vec2 uv = floor(pixel) + 0.5; uv += 1.0 - clamp((1.0 - fract(pixel)) * zoom, 0.0, 1.0); return uv; } vec2 uv = subpixelAA(inputUV, inputTextureScale); outColor = texture(uniformTexture, uv / uniformTextureSize);
I calculate texture scale in the vertex shader because I do some instancing tricks with quads; it lets me calculate the final zoom by the products of the primitive's scale and view zoom, divided by the actual width of the art
vec2 size = vec2(textureSize(your_texture_sampler, 0)); uv = uv * size; vec2 duv = fwidth(uv); uv = floor(uv) + vec2(0.5) + clamp((fract(uv) - vec2(0.5) + duv)/duv, 0, 1); uv /= size;
uv is input and output
PSEUDO-CODE
if (/* pixel is entirely in one texel */) { // floor uv coordinates to be exactly in the texel center }