-
-
Save hippocoder/5e96985fcab802d81ab509529f4baa14 to your computer and use it in GitHub Desktop.
Pixel Art Antialiasing UVs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ANTIALIASED PIXEL ART SAMPLING EXAMPLE | |
| //old code by Robert Cummings, thanks to Ben Golus for the original techniques + the internets etc (this isn't copyrighted code!) | |
| //all this code is considered open source - do what you want, just don't bother charging for it, share with people | |
| //each texel is a flat plateau of solid colour. | |
| //blending occurs at transition band at texel borders, sized to cover one screen pixel, no shimmer/blur/crawl etc... | |
| //this effectively turns the bilinear filter into a box filter exactly one screen pixel wide, centered on the texel boundary. | |
| //texture and sampler should use BILINEAR filtering + CLAMP or WRAP as needed, no mipmaps!!! | |
| //point filtering will NOT work | |
| //should work with on UE (custom nodes), Unity, Godot / most engines with a few tweaks | |
| //haven't tested it in a long time and will not support you :P | |
| //--- | |
| float2 PixelArtUV(float2 uv, float2 textureSize) | |
| { | |
| //UV in texel space (0..textureSize) | |
| float2 texelUV = uv * textureSize; | |
| float2 dxUV = ddx(texelUV); | |
| float2 dyUV = ddy(texelUV); | |
| float2 filterWidth = max( | |
| float2(length(float2(dxUV.x, dyUV.x)), | |
| length(float2(dxUV.y, dyUV.y))), | |
| // Clamp to a minimum to avoid division by zero at extreme close-ups | |
| float2(1.0e-5, 1.0e-5) | |
| ); | |
| float2 texelCenter = floor(texelUV - 0.5) + 0.5; //center of nearest texel | |
| float2 frac_ = texelUV - texelCenter; // -.5 .. +.5 from center | |
| float2 halfPixel = 0.5 * filterWidth; | |
| float2 snapped = clamp(frac_ / halfPixel, -1.0, 1.0); | |
| // Remap from [-1,1] back to [-0.5, 0.5] | |
| snapped = snapped * 0.5; | |
| //reconstruct the UV | |
| float2 newTexelUV = texelCenter + snapped; | |
| //convert back | |
| return newTexelUV / textureSize; | |
| } | |
| //-- example | |
| Texture2D _SpriteTexture : register(t0); | |
| SamplerState _SpriteSampler : register(s0); //bilinear, Clamp | |
| struct PSInput | |
| { | |
| float4 position : SV_POSITION; | |
| float2 uv : TEXCOORD0; | |
| }; | |
| float4 PSMain(PSInput input) : SV_TARGET | |
| { | |
| // textureSize = (width, height) of _SpriteTexture in texels | |
| float2 textureSize; | |
| _SpriteTexture.GetDimensions(textureSize.x, textureSize.y); | |
| float2 aaUV = PixelArtUV(input.uv, textureSize); | |
| return _SpriteTexture.Sample(_SpriteSampler, aaUV); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment