Search Unity

Trying to draw a circle, but I'm getting an ellipse

Discussion in 'Shaders' started by Deleted User, Aug 24, 2018.

  1. Deleted User

    Deleted User

    Guest

    I need to draw a circle with a shader, I'm trying in this way:
    Code (CSharp):
    1.  
    2.             struct v2f
    3.             {
    4.                 float2 uv : TEXCOORD0;
    5.                 float4 vertex : SV_POSITION;
    6.                 float4 screenPos : TEXCOORD1;
    7.            };
    8.  
    9.             v2f vert (appdata v)
    10.             {
    11.                 v2f o;
    12.                 o.vertex = UnityObjectToClipPos(v.vertex);
    13.                 o.uv = v.uv;
    14.                 o.screenPos = ComputeScreenPos(o.vertex);
    15.                 return o;
    16.             }
    17.          
    18.             sampler2D _MainTex;
    19.             float2 _PlayerPosition;
    20.  
    21.             fixed4 frag (v2f i) : SV_Target
    22.             {
    23.                 fixed4 col = tex2D(_MainTex, i.uv);
    24.                 float2 playerPos;
    25.                 float2 screenPos;
    26.  
    27.                 playerPos.x = _PlayerPosition.x;
    28.                 playerPos.y = _PlayerPosition.y;
    29.  
    30.                 float dis = distance(playerPos,float2(i.screenPos.x,i.screenPos.y));
    31.                 float radius = 0.20;
    32.  
    33.                 if(dis < radius)
    34.                 {
    35.                     col.a = 0;
    36.                 }
    37.          
    38.                 return col;
    39.  
    40.             }
    _PlayerPosition is a normal vector2 fed by normalized screen coord of the player.

    upload_2018-8-23_23-10-59.png
     
    Last edited by a moderator: Aug 24, 2018
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    A normalized screen coord means one corner of the screen is 0.0,0.0 and the opposite corner is 1.0,1.0. If your screen is two times as wide as it is tall, a circle in normalized space will be drawn two times as wide as well. So you need to scale the coordinates along one axis to be not normalized, but match how it’ll appear on screen.

    You can use the _ScreenParams variable to get the screen resolution, and from that the aspect ratio.

    Code (CSharp):
    1. Shader "Unlit/ScreenAspect"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.         _PlayerPosition ("Player Position", Vector) = (0.5, 0.5, 0, 0)
    7.         _Radius ("Radius", Float) = 0.2
    8.     }
    9.     SubShader
    10.     {
    11.         Tags { "RenderType"="Opaque" }
    12.         LOD 100
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             // make fog work
    20.             #pragma multi_compile_fog
    21.            
    22.             #include "UnityCG.cginc"
    23.  
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.                 float2 uv : TEXCOORD0;
    28.             };
    29.  
    30.             struct v2f
    31.             {
    32.                 float2 uv : TEXCOORD0;
    33.                 float4 vertex : SV_POSITION;
    34.                 float4 screenPos : TEXCOORD1;
    35.            };
    36.             v2f vert (appdata v)
    37.             {
    38.                 v2f o;
    39.                 o.vertex = UnityObjectToClipPos(v.vertex);
    40.                 o.uv = v.uv;
    41.                 o.screenPos = ComputeScreenPos(o.vertex);
    42.                 return o;
    43.             }
    44.        
    45.             sampler2D _MainTex;
    46.             float2 _PlayerPosition;
    47.             float _Radius;
    48.             fixed4 frag (v2f i) : SV_Target
    49.             {
    50.                 fixed4 col = tex2D(_MainTex, i.uv);
    51.  
    52.                 // apply perspective divide
    53.                 float2 screenPos = i.screenPos.xy / i.screenPos.w;
    54.                 // get position relative to the player position, aka the circle's center
    55.                 float2 circlePos = screenPos - _PlayerPosition;
    56.  
    57.                 // apply aspect ratio correction, adjusting the horizontal
    58.                 circlePos.x *= _ScreenParams.x / _ScreenParams.y;
    59.                 // get distance from center
    60.                 float dist = length(circlePos);
    61.                 // clip
    62.                 clip(dist - _Radius);
    63.        
    64.                 return col;
    65.             }
    66.             ENDCG
    67.         }
    68.     }
    69. }
     
  3. Deleted User

    Deleted User

    Guest

    Works, thanks ! :)
     
  4. heeroyuy54

    heeroyuy54

    Joined:
    Aug 30, 2017
    Posts:
    2
    nice solution!