I have drawn a circle by shader, but I can't get anti-aliasing to work.
I tried finding an answer here http://answers.unity3d.com/questions/521984/how-do-you-draw-2d-circles-and-primitives.html, but I have to use discard to draw circle.
Here is a picture of my current shader result and the shader code:
Shader "Unlit/CircleSeletor"
{
Properties
{
_BoundColor("Bound Color", Color) = (1,1,1,1)
_BgColor("Background Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_BoundWidth("BoundWidth", float) = 10
_ComponentWidth("ComponentWidth", float) = 100
}
SubShader{
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag Lambert alpha
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
sampler2D _MainTex;
float _BoundWidth;
fixed4 _BoundColor;
fixed4 _BgColor;
float _ComponentWidth;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
float antialias(float w, float d, float r) {
return 1-(d-r-w/2)/(2*w);
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 c = tex2D(_MainTex,i.uv);
float x = i.uv.x;
float y = i.uv.y;
float dis = sqrt(pow((0.5 - x), 2) + pow((0.5 - y), 2));
if (dis > 0.5) {
discard;
} else {
float innerRadius = (_ComponentWidth * 0.5 - _BoundWidth) / _ComponentWidth;
if (dis > innerRadius) {
c = _BoundColor;
//c.a = c.a*antialias(_BoundWidth, dis, innerRadius);
}
else {
c = _BgColor;
}
}
return c;
}
ENDCG
}
}
}
It's really easy to apply anti-alias to a circle.
1.First, you need 3
variables to do this. Get the radius
, distance
of the circle. Also create a float
value(let's called that borderSize
) that can be used to determine how far the anti-alias should go. The radius
, distance
and borderSize
are the three variables.
2.Find the t
with smoothstep
function using those 3 variables from #1.
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
3.Mix the color before returning it.
Let's say that _BoundColor
is the circle fill color and _BgColor
is the background color.
If using GLSL using the mix
function. If using Unity, use the lerp
function. Both function are interchanging and the parameters are the-same.
col = lerp(_BoundColor, _BgColor, t);
The t
is from #2. You can now return col
in the fragment function.
These are the 3 steps put together:
if (dis > radius) {
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
col = lerp(_BoundColor, _BgColor, t);
}
else {
float t = smoothstep(radius + borderSize, radius - borderSize, distance);
col = lerp(_BoundColor, _BgColor, t);
}
return col;
OUTPUT WITHOUT ANTI-ALIASING:
OUTPUT WITH ANTI-ALIASING(4.5 Threshold):
Finally, the whole code(Tested on PC and Android but should work on iOS too)
Shader "Unlit/Circle Anti-Aliasing"
{
Properties
{
_BoundColor("Bound Color", Color) = (0,0.5843137254901961,1,1)
_BgColor("Background Color", Color) = (0.1176470588235294,0,0.5882352941176471,1)
_circleSizePercent("Circle Size Percent", Range(0, 100)) = 50
_border("Anti Alias Border Threshold", Range(0.00001, 5)) = 0.01
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
float _border;
fixed4 _BoundColor;
fixed4 _BgColor;
float _circleSizePercent;
struct v2f
{
float2 uv : TEXCOORD0;
};
v2f vert(
float4 vertex : POSITION, // vertex position input
float2 uv : TEXCOORD0, // texture coordinate input
out float4 outpos : SV_POSITION // clip space position output
)
{
v2f o;
o.uv = uv;
outpos = UnityObjectToClipPos(vertex);
return o;
}
float2 antialias(float radius, float borderSize, float dist)
{
float t = smoothstep(radius + borderSize, radius - borderSize, dist);
return t;
}
fixed4 frag(v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
{
float4 col;
float2 center = _ScreenParams.xy / 2;
float maxradius = length(center);
float radius = maxradius*(_circleSizePercent / 100);
float dis = distance(screenPos.xy, center);
if (dis > radius) {
float aliasVal = antialias(radius, _border, dis);
col = lerp(_BoundColor, _BgColor, aliasVal); //NOT needed but incluse just incase
}
else {
float aliasVal = antialias(radius, _border, dis);
col = lerp(_BoundColor, _BgColor, aliasVal);
}
return col;
}
ENDCG
}
}
}