Remove overlap of circles with shaders

I was talking on IRC in #unity-chat on freenode.net when I got an idea to make a shader to remove the overlapping area of multiple circles. Here is the result:

It uses 2 passes. Essentially it is a depthmask combined with the drawing of a circle. The first pass ‘draws’ a circle which z is offset a 1000 towards the camera. For the drawing itself it blends with a zero one factor so that the framebuffer stays the same. Only the z buffer will change. The second pass draws a circle normally but because of the previous pass the inner circle will stay empty. Even on places where the circles overlap.

The rendering queue is set to geometry + 1 because it needs to be drawn after the normal geometry. If you don’t, then you get strange artifacts in the scene because of the altered depth values.

Here is the shader:

Shader "Custom/CircleOverlap" {
  Properties {
  }
  SubShader {
    Tags { "Queue"="Geometry+1" }
    LOD 200
    pass
    {
      Blend ZERO ONE
      Offset 1,-1000
      ZTest off
      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      #include "UnityCG.cginc"
  
      struct VIn {
        float4 vertex : POSITION;
        float2 texcoord : TEXCOORD0;
      };
      
      struct VOut {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
      };
  
      VOut vert (VIn vin) {
        VOut vout;
        vout.vertex = mul(UNITY_MATRIX_MVP, vin.vertex);
        vout.uv = vin.texcoord;
        return vout;
      }
      
      float4 frag(VOut vout) : COLOR
      {
        float circle = distance(float2(0.5,0.5),vout.uv)*2;
        float innerCircle = step(0.9,circle);
        clip(-innerCircle);
        return float4(0,0,0,1);
      }
      
      ENDCG
    }
    pass
    {
      //Blend SrcAlpha OneMinusSrcAlpha
      ZTest LEqual
      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      #include "UnityCG.cginc"
  
      struct VIn {
        float4 vertex : POSITION;
        float2 texcoord : TEXCOORD0;
      };
      
      struct VOut {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
      };
  
      VOut vert (VIn vin) {
        VOut vout;
        vout.vertex = mul(UNITY_MATRIX_MVP, vin.vertex);
        vout.uv = vin.texcoord;
        return vout;
      }
      
      float4 frag(VOut vout) : COLOR
      {
        //return float4(1,1,1,1);
        float circle = distance(float2(0.5,0.5),vout.uv)*2;
        float outerCircle = step(1,circle);
        clip(-outerCircle);
        return float4(1,1,1,1);
      }
      
      ENDCG
    }
  } 
  FallBack "Diffuse"
}

									

Leave a Reply

Your email address will not be published. Required fields are marked *