Edges on an alpha-test material ("Unlit/Tranparent Cutout" from Unity)
Alpha test edges are beautifully smooth, and extremely desirable in many cases, try telling one of your artists they can't use it for the project, see how that goes! Here's an example with a standard alpha blend:
Alpha blend, eww, gross ("Unlit/Transparent" from Unity)
There's really just no substitute for that crisp edge, but fortunately, you don't have to settle for one! If you think about it, it's really just a sharp edge where the alpha goes straight from 0.0->1.0, if we can replicate that, then we should be all set! Math to the rescue, and simple math at that!
Using the plain old y = mx + b algorithm, we can create a graph that does exactly that! With a super steep slope, and a small offset to x, take a look at the graph for y = 10,000(x-0.5):
I love Google
So check that out! Looks pretty much like an on/off switch to me, all that's missing is to clamp it between 0.0 and 1.0 with a call to saturate, and we should be all set! We can attach that 0.5 to a variable, and expose it to users as a cutoff slider.
Custom alpha blend shader with our awesome math function.
I'm honestly not sure I can actually tell the difference here! And that's pretty awesome. The code for it is super simple, but the results look great! I haven't actually tested all this on mobile just yet, but if what I hear is correct, this could be a better solution than alpha testing. Although, I honestly wouldn't be surprised to see that change from device to device. If people are interested, I can try and have some stats on that in the future!
Here's the code, CG, in the format of a Unity shader, or you can download it here.
Shader "Custom/AlphaBlend Cutout" {
Properties {
_Tex ("Texture (RGB)", 2D ) = "white" {}
_Cutoff("Alpha cutoff", Float) = 0.5
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
LOD 200
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _Tex;
float _Cutoff;
struct VS_OUT {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
VS_OUT vert (appdata_full input) {
VS_OUT result;
result.position = mul (UNITY_MATRIX_MVP, input.vertex);
result.uv = input.texcoord;
return result;
}
half4 frag (VS_OUT input) : COLOR {
half4 color = tex2D(_Tex, input.uv);
float alpha = saturate(10000*(color.a-_Cutoff));
return half4(color.rgb,alpha);
}
ENDCG
}
}
}