2016-09-22 2 views
7

Я нарисовал круг шейдером, но я не могу заставить сглаживание работать.Как нарисовать круг в единстве с помощью шейдера и сглаживания

Я попытался найти ответ здесь http://answers.unity3d.com/questions/521984/how-do-you-draw-2d-circles-and-primitives.html, но я должен использовать discard для рисования круга.

Вот фотография моего текущего результата шейдера и код шейдера:

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-(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) { 
        discard; 
       } else { 
        float innerRadius = (_ComponentWidth * 0.5 - _BoundWidth)/_ComponentWidth; 
        if (dis > innerRadius) { 
         c = _BoundColor; 
         //c.a = c.a*antialias(_BoundWidth, dis, innerRadius); 
        } 
        else { 
         c = _BgColor; 
        } 
       } 
       return c; 
      } 
      ENDCG 
      } 
} 
} 
+0

жир Баунти для Shader что Черти дисков! :) – Fattie

ответ

3

Попробуйте это:

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

       return c; 
      } 
       ENDCG 

     } 
    } 
} 

После первого прохода я GrabPass результат и применять анти- псевдоним во втором проходе путем усреднения пограничных пикселей.

+0

человек, какой первоклассный шейдер ....... спасибо! – Fattie

+0

Ah - вы знаете, к сожалению, я думаю, что этот шейдер не работает на современных устройствах iOS - вы получаете эффект «калейдоскопа», который вы знаете? Невезение! – Fattie

+0

Что вы имеете в виду? можете ли вы предоставить скриншот? – Krajca

4

На самом деле очень легко применять анти-псевдоним к кругу.

. Для начала вам понадобятся переменные 3. Получите radius, distance круга. Также создайте значение float (давайте назовем это borderSize), который может использоваться для определения того, насколько далеко должен пройти анти-псевдоним. radius, distance и borderSize являются тремя переменными.

.find функция t с smoothstep, используя эти 3 переменные из # 1.

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

.mix цвет перед его возвращением.

Предположим, что _BoundColor - цвет заполнения круга, а _BgColor - цвет фона.

При использовании GLSL с использованием функции mix. При использовании Unity используйте функцию lerp. Обе функции взаимозаменяемы, а параметры являются одинаковыми.

col = lerp(_BoundColor, _BgColor, t); 

t от # 2. Теперь вы можете вернуть col в функцию фрагмента.


Эти 3 шага вместе взятые:

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; 

ВЫХОД БЕЗ сглаживанием:

enter image description here

ВЫХОД со сглаживанием (4 ,5 Threshold):

enter image description here


Наконец, весь код (испытан на ПК и Android, но должен работать на прошивке тоже)

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 
     } 
    } 
} 
+1

фантастический @Programmer, спасибо – Fattie

Смежные вопросы