Skip to content

Instantly share code, notes, and snippets.

@TheoBendixson
Last active June 14, 2021 23:19
Show Gist options
  • Save TheoBendixson/d1acee917ba7dbec8cec3b5d0fe2f389 to your computer and use it in GitHub Desktop.
Save TheoBendixson/d1acee917ba7dbec8cec3b5d0fe2f389 to your computer and use it in GitHub Desktop.
2D Scaling Pixel Art Fragment Shader (Metal)
fragment float4
pixelArtFragmentShader(RasterizerData in [[stage_in]],
texture2d_array<half> texture_atlas [[ texture(0) ]])
{
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear);
// This is the alpha value from the graph, or the size of the margin where you
// want to apply bilinear filtering around a texel
float2 alpha = float2(0.07);
// As noted in the article, this is x from the graph, or the fractional
// portion of the (width/height) scaled uv coordinates.
float2 x = fract(in.vUv);
// xprime is the adjusted fractional portion of the scaled uv coordinate,
// and it is the value matching the desired output
float2 xprime = clamp(0.5/(alpha*x), 0.0, 0.5) +
clamp((0.5/(alpha*(x - 1.0))) + 0.5, 0.0, 0.5);
// This just maps from our invented coordinate system back to standard
// uv coordinates
float2 textureCoordinate = (floor(in.vUv) + xprime)/in.textureSize;
// NOTE: This assumes you are using the first texture in the texture array. Hence
// zero for the last parameter. I tend to pass that in with the RasterizerData
// struct when working with 2D texture arrays in Metal.
const half4 colorSample = texture_atlas.sample(textureSampler,
textureCoordinate, 0);
float4 Result = float4(colorSample[0], colorSample[1],
colorSample[2], colorSample[3]);
// return the color of the texture
return Result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment