How to draw a circle in unity using shaders and smoothing

I drew a circle with a shader, but I canโ€™t get the smoothing to work.

I tried to find the answer here http://answers.unity3d.com/questions/521984/how-do-you-draw-2d-circles-and-primitives.html , but I need to use discard to draw a circle.

Here is an image of my current shader result and shader code:

picture

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-(drw/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; //ca = ca*antialias(_BoundWidth, dis, innerRadius); } else { c = _BgColor; } } return c; } ENDCG } } } 
+7
unity3d shader antialiasing
source share
2 answers

It is very easy to apply an anti-alias to a circle.

1 . First, for this you need 3 variables. Get the radius , distance circle. Also create a float value (let it be called borderSize ) that you can use to determine how far the anti-alias should go. radius , distance and borderSize are three variables.

2 . Find t using the smoothstep function using these 3 variables from # 1.

 float t = smoothstep(radius + borderSize, radius - borderSize, distance); 

3 . Mix color before return.

Say that _BoundColor is the fill color of the circle, and _BgColor is the background color.

When using GLSL using the mix function. When using Unity, use the lerp function. Both functions are interchangeable, and the parameters are the same.

 col = lerp(_BoundColor, _BgColor, t); 

t - from # 2. Now you can return col to the fragment function.


These are the three steps:

 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; 

EXIT WITHOUT ANTIALIZATION :

enter image description here

EXIT WITH ANTIALIZATION (4.5 Threshold) :

enter image description here


Finally, all the code (tested on PC and Android, but should work on iOS)

 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 } } } 
+4
source share

Try the following:

 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) { ca = 0; discard; } else { float innerRadius = (_ComponentWidth * 0.5 - _BoundWidth) / _ComponentWidth; if (dis > innerRadius) { c = _BoundColor; //ca = ca*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; ca = (ca + up.a + down.a + left.a + right.a) / 5; return c; } ENDCG } } } 

After the first pass, I GrabPass the result and apply anti-alias in the second pass by averaging the border pixels.

+3
source share

All Articles