2D circle hole with antialiasing inside object

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 :

Shader "Sprite/Hole Effect"
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _ObjPos ("Object Position", Vector) = (1,1,1,1)
        _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
        _Radius ("Hole Radius", Range(0.1,10)) = 2
    }

    SubShader
    {
        Pass
        {
            Cull Off 

            CGPROGRAM

            #pragma vertex vert  
            #pragma fragment frag 

            uniform sampler2D _MainTex;
            float _Radius;
            float4 _ObjPos;

            struct vertexInput {
                float4 vertex : POSITION;
                float4 texcoord : TEXCOORD0;
            };
            struct vertexOutput {
                float4 pos : SV_POSITION;
                float4 worldPos : POSITION1;
                float4 tex : TEXCOORD0;
            };

            vertexOutput vert(vertexInput input)
            {
                vertexOutput output;

                output.tex = input.texcoord;
                output.pos = UnityObjectToClipPos(input.vertex);
                output.worldPos = mul(input.vertex, unity_ObjectToWorld);
                return output;
            }

            float4 frag(vertexOutput input) : COLOR
            {
                float4 textureColor = tex2D(_MainTex, input.tex.xy);
                float dis = distance(input.worldPos.xyz, _ObjPos);

                if (dis > _Radius)
                {
                    discard;
                }

                return textureColor;
            }

            ENDCG
        }
    }
    
    FallBack "Diffuse"
}

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!!!

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

float4 frag(vertexOutput input) : COLOR
             {
                 float4 textureColor = tex2D(_MainTex, input.tex.xy);
                 float dis = distance(input.worldPos.xyz, _ObjPos);
 
                 if (dis > _Radius)
                 {
                     discard;
                 }
 
                 return textureColor;
             }

I can only define ‘true’ or ‘false’ (return or discard) :frowning:

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:

Shader "Sprites/XRay Effect"
{
	Properties
	{
		[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
		
		_PlayerPos ("Player Position", Vector) = (0,0,0,0)
        _Radius ("Hole Radius", Range(0.1,100)) = 2
        _Border ("Border", Range(0.001,1)) = 0.05
	}

	SubShader
	{
		Tags
		{ 
			"Queue"="Transparent" 
			"IgnoreProjector"="True" 
			"RenderType"="Transparent" 
			"PreviewType"="Plane"
			"CanUseSpriteAtlas"="True"
		}
		
		Cull Off
		Lighting Off
		ZWrite Off
		ZTest [unity_GUIZTestMode]
		Blend SrcAlpha OneMinusSrcAlpha

		Pass
		{
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "UnityUI.cginc"
			
			struct vertexInput
			{
				float4 vertex   : POSITION;
				float4 color    : COLOR;
				float2 texCoord : TEXCOORD0;
			};

			struct vertexOutput
			{
				float4 vertex   : SV_POSITION;
				fixed4 color    : COLOR;
				half2 texCoord  : TEXCOORD0;
				float3 worldPosition : TEXCOORD1;
			};
			
			sampler2D _MainTex;
            
			float4 _PlayerPos;
            float _Radius;
            float _Border;

			vertexOutput vert(vertexInput IN)
			{
				vertexOutput OUT;

				OUT.vertex = UnityObjectToClipPos(IN.vertex);
				OUT.texCoord = IN.texCoord;
				OUT.worldPosition = mul(unity_ObjectToWorld, IN.vertex);
				OUT.color = IN.color;

				return OUT;
			}

			fixed4 frag(vertexOutput IN) : SV_Target
			{
				half4 color = tex2D(_MainTex, IN.texCoord) * IN.color;
				
				// Adding the circle hole
				float dis = distance(IN.worldPosition.xyz, _PlayerPos.xyz);
				color.a = lerp(0, color.a, color.a * (dis - _Radius) / _Border);

				return color;
			}
			
			ENDCG
		}
	}
	FallBack "UI/Default"
}

You can modify the part lerp(0, color.a, color.a * (dis - _Radius) / _Border) to your needs.