Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Question 2D circle hole with antialiasing on object

Discussion in 'Shader Graph' started by JuZ-index, Mar 10, 2021.

  1. JuZ-index

    JuZ-index

    Joined:
    Feb 2, 2021
    Posts:
    10
    I'd like to add a hole inside an empty object with sprites inside. This hole has a circle shape.

    To achieve that, I added a shader to a material and the material to a Sprite Renderer component to the empty object.

    Here is my Shader :
    Code (CSharp):
    1. Shader "Sprite/XRay Effect"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _ObjPos ("Object Position", Vector) = (1,1,1,1)
    7.         _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    8.         _Radius ("Hole Radius", Range(0.1,10)) = 2
    9.     }
    10.  
    11.     SubShader
    12.     {
    13.         Pass
    14.         {
    15.             Cull Off
    16.  
    17.             CGPROGRAM
    18.  
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.  
    22.             uniform sampler2D _MainTex;
    23.             float _Radius;
    24.             float4 _ObjPos;
    25.  
    26.             struct vertexInput {
    27.                 float4 vertex : POSITION;
    28.                 float4 texcoord : TEXCOORD0;
    29.             };
    30.             struct vertexOutput {
    31.                 float4 pos : SV_POSITION;
    32.                 float4 worldPos : POSITION1;
    33.                 float4 tex : TEXCOORD0;
    34.             };
    35.  
    36.             vertexOutput vert(vertexInput input)
    37.             {
    38.                 vertexOutput output;
    39.  
    40.                 output.tex = input.texcoord;
    41.                 output.pos = UnityObjectToClipPos(input.vertex);
    42.                 output.worldPos = mul(input.vertex, unity_ObjectToWorld);
    43.                 return output;
    44.             }
    45.  
    46.             float4 frag(vertexOutput input) : COLOR
    47.             {
    48.                 float4 textureColor = tex2D(_MainTex, input.tex.xy);
    49.                 float dis = distance(input.worldPos.xyz, _ObjPos);
    50.  
    51.                 if (dis > _Radius)
    52.                 {
    53.                     discard;
    54.                 }
    55.  
    56.                 return textureColor;
    57.             }
    58.  
    59.             ENDCG
    60.         }
    61.     }
    62.  
    63.     FallBack "Diffuse"
    64. }
    The problem with this method is that there is no antialiasing for the circle...

    So I tried to add a Sprite mask to the empty object instead, but there is no antialiasing nether...

    I think the shader is the good solution to achieve that but really don't know how!

    Any help would be perfect!!!
     
  2. JuZ-index

    JuZ-index

    Joined:
    Feb 2, 2021
    Posts:
    10
    The way to do that is to control opacity of pixels...

    Outside of the radius, opacity is 1 Inside, it's 0. And between, I could use lerp and the distance to decrease opacity from 1 (outside) to 0 (inside) to add an antialiasing...

    The problem is that in this function

    Code (CSharp):
    1. float4 frag(vertexOutput input) : COLOR
    2.               {
    3.                   float4 textureColor = tex2D(_MainTex, input.tex.xy);
    4.                   float dis = distance(input.worldPos.xyz, _ObjPos);
    5.  
    6.                   if (dis > _Radius)
    7.                   {
    8.                       discard;
    9.                   }
    10.  
    11.                   return textureColor;
    12.               }
    I can only define 'true' or 'false' (return or discard) :(
     
  3. JuZ-index

    JuZ-index

    Joined:
    Feb 2, 2021
    Posts:
    10
    Finally I found it!!

    I applied a material with a shader to the sprites of the object where I want to see the circle.

    Here is my shader:
    Code (CSharp):
    1. Shader "Sprites/XRay Effect"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.      
    7.         _PlayerPos ("Player Position", Vector) = (0,0,0,0)
    8.         _Radius ("Hole Radius", Range(0.1,100)) = 2
    9.         _Border ("Border", Range(0.001,1)) = 0.05
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags
    15.         {
    16.             "Queue"="Transparent"
    17.             "IgnoreProjector"="True"
    18.             "RenderType"="Transparent"
    19.             "PreviewType"="Plane"
    20.             "CanUseSpriteAtlas"="True"
    21.         }
    22.      
    23.         Cull Off
    24.         Lighting Off
    25.         ZWrite Off
    26.         ZTest [unity_GUIZTestMode]
    27.         Blend SrcAlpha OneMinusSrcAlpha
    28.  
    29.         Pass
    30.         {
    31.             CGPROGRAM
    32.  
    33.             #pragma vertex vert
    34.             #pragma fragment frag
    35.  
    36.             #include "UnityCG.cginc"
    37.             #include "UnityUI.cginc"
    38.          
    39.             struct vertexInput
    40.             {
    41.                 float4 vertex   : POSITION;
    42.                 float4 color    : COLOR;
    43.                 float2 texCoord : TEXCOORD0;
    44.             };
    45.  
    46.             struct vertexOutput
    47.             {
    48.                 float4 vertex   : SV_POSITION;
    49.                 fixed4 color    : COLOR;
    50.                 half2 texCoord  : TEXCOORD0;
    51.                 float3 worldPosition : TEXCOORD1;
    52.             };
    53.          
    54.             sampler2D _MainTex;
    55.          
    56.             float4 _PlayerPos;
    57.             float _Radius;
    58.             float _Border;
    59.  
    60.             vertexOutput vert(vertexInput IN)
    61.             {
    62.                 vertexOutput OUT;
    63.  
    64.                 OUT.vertex = UnityObjectToClipPos(IN.vertex);
    65.                 OUT.texCoord = IN.texCoord;
    66.                 OUT.worldPosition = mul(unity_ObjectToWorld, IN.vertex);
    67.                 OUT.color = IN.color;
    68.  
    69.                 return OUT;
    70.             }
    71.  
    72.             fixed4 frag(vertexOutput IN) : SV_Target
    73.             {
    74.                 half4 color = tex2D(_MainTex, IN.texCoord) * IN.color;
    75.              
    76.                 // Adding the circle hole
    77.                 float dis = distance(IN.worldPosition.xyz, _PlayerPos.xyz);
    78.                 color.a = lerp(0, color.a, color.a * (dis - _Radius) / _Border);
    79.  
    80.                 return color;
    81.             }
    82.          
    83.             ENDCG
    84.         }
    85.     }
    86.     FallBack "UI/Default"
    87. }
    You can modify the part
    lerp(0, color.a, color.a * (dis - _Radius) / _Border)
    to your needs.