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
}
}
}
In Unity a Shader Graph Asset appears as a normal shader. To create a Shader Graph Asset you click the create menu in the Project Window and select Shader from the dropdown. From here you can create either a PBR or Unlit Shader Graph Asset. This will create a Shader Graph Asset in the project.
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
}
}
}
Try this:
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) {
c.a = 0;
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
}
GrabPass{
"_MainTex2"
}
Pass
{
Blend One zero
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
fixed4 color : COLOR;
};
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
float4 scrPos : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.scrPos = ComputeScreenPos(o.pos);
o.color = v.color;
return o;
}
sampler2D _MainTex2;
float4 _MainTex2_TexelSize;
fixed4 frag(v2f i) : SV_Target
{
float2 uv = (i.scrPos.xy / i.scrPos.w);
fixed4 c = tex2D(_MainTex2, uv );
fixed4 up = tex2D(_MainTex2, uv + fixed2(0, _MainTex2_TexelSize.y));
fixed4 down = tex2D(_MainTex2, uv - fixed2(0, _MainTex2_TexelSize.y));
fixed4 left = tex2D(_MainTex2, uv - fixed2(_MainTex2_TexelSize.x, 0));
fixed4 right = tex2D(_MainTex2, uv + fixed2(_MainTex2_TexelSize.x, 0));
c.rgb = (c.rgb + up.rgb + down.rgb + left.rgb + right.rgb) / 5;
c.a = (c.a + up.a + down.a + left.a + right.a) / 5;
return c;
}
ENDCG
}
}
}
After first pass I GrabPass result and apply anti-alias in second pass by averaging border pixels.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With