【问题标题】:How to draw circle in unity by shader and anti-aliasing如何通过着色器和抗锯齿统一绘制圆
【发布时间】:2017-01-30 19:29:00
【问题描述】:

我已经通过着色器绘制了一个圆圈,但我无法让抗锯齿工作。

我尝试在这里http://answers.unity3d.com/questions/521984/how-do-you-draw-2d-circles-and-primitives.html寻找答案,但我必须使用丢弃来绘制圆圈。

这是我当前着色器结果和着色器代码的图片:

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

【问题讨论】:

  • 为绘制磁盘的着色器提供丰厚的奖励! :)

标签: unity3d shader antialiasing


【解决方案1】:

对圆应用消除锯齿真的很容易。

1。首先,您需要3 变量来执行此操作。获取圈子的radius、distance。还要创建一个float 值(我们称之为borderSize),它可用于确定抗锯齿应该走多远。 radius、distance 和 borderSize 是三个变量。

2。使用 #1 中的这 3 个变量找到 t 和 smoothstep 函数。

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

3.在返回之前混合颜色。

假设_BoundColor 是圆形填充颜色,_BgColor 是背景颜色。

如果使用 GLSL,则使用 mix 函数。如果使用 Unity,请使用 lerp 函数。两个功能互换,参数相同。

col = lerp(_BoundColor, _BgColor, t);

t 来自 #2。您现在可以在片段函数中返回col。


这三个步骤放在一起:

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;

没有抗锯齿的输出:

抗锯齿输出(4.5 阈值):


最后,整个代码(在 PC 和 Android 上测试,但应该也可以在 iOS 上运行)

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

【讨论】:

  • 您将持有此着色器的材质附加在哪个组件上?
  • @Wipster 我不记得太多了,但它要么是一个 3D 对象 (MeshRenderer) 要么 * 到相机。我相信这是连接到主摄像头的屏幕着色器。两者都试一下,让我知道
【解决方案2】:

试试这个:

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 结果并通过平均边界像素在第二次通过应用抗锯齿。

【讨论】:

  • 啊——很遗憾,我认为这个着色器在现代 iOS 设备上不起作用——你得到了“万花筒”效果,你知道吗?运气不好!
  • 什么意思?可以提供截图吗?
  • 当然@Krajca,我会这样做的。无论如何,我可能已经塞了一些东西......等待
  • 绝对不是 - 只是一张带抗锯齿的光盘!谢谢!!
  • 让我感到困惑的是,当您单击“2d Sprite”时,它没有..“大小”。它非常抽象。那里没有网格,什么都没有。我认为@Krajca 出色的着色器可能遇到的一个问题是,我刚刚去了...... 2dSprite .. 然后我设置了一个材质(简单地说,就是 Krajca 的着色器)。我得到了我提到的打破边界效应。我认为在着色器中它应该“制作”一个大小......或其他东西。 (自然尺寸是“1 个单位直径”。)
猜你喜欢
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2010-12-19
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
相关资源
最近更新 更多