关于unity shader描边的一二事(顶点挤出式描边的探讨)

shader描边的方式很多,我们这里重点考虑其中一种。
一个pass沿着顶点法线挤出,剔除正面
一个pass正常渲染,剔除背面

第一种

下面贴出只是单纯的沿着将顶点沿着法线挤出的代码和效果(只贴出顶点挤出pass)


        Tags { "RenderType" = "Opaque" }
        LOD 100
        
        pass
        {
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite On
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            float _Outline;
            float _Factor;
            struct v2f
            {
                float4 pos: SV_POSITION;
            };
            v2f vert(appdata_full v)
            {
                v2f o;
                float4 pos = v.vertex; //转换到视图空间
                float3 normal = v.normal;//将法线转换到视图空间
                pos = pos + float4(normalize(normal), 0) * _Outline;//将顶点沿着法线方向延伸或者收缩
                o.pos = UnityObjectToClipPos(pos);
                
                return o;
            }
            float4 frag(v2f i): COLOR
            {
                return float4(1, 0, 0, 0);
            }
            ENDCG
            
        }

就像下图看到的那样,cube的描边会有很严重的割裂现象,这是因为只是单纯的沿着法线挤出,效果就好像将他的面往顶点的Z方向拉出去,这种效果显然不是很不好。


效果图1

第二种

既然会出现这种事情,那么我们就会想到想发现往回缩一点是不是就能让他们铆合起来呢。

pass
       {
           Tags { "LightMode" = "Always" }
           Cull Front
           ZWrite On
           CGPROGRAM
           
           #pragma vertex vert
           #pragma fragment frag
           #include "UnityCG.cginc"
           float _Outline;
           float _SubNormal;
           struct v2f
           {
               float4 pos: SV_POSITION;
           };
           v2f vert(appdata_full v)
           {
               v2f o;
               float4 pos = mul(UNITY_MATRIX_MV, v.vertex); //转换到视图空间
               float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);//将法线转换到视图空间
               normal.z = -_SubNormal;//将Z轴进行收缩
               pos = pos + float4(normalize(normal), 0) * _Outline;//将顶点沿着法线方向延伸或者收缩
               o.pos = mul(UNITY_MATRIX_P, pos);
               
               return o;
           }
           float4 frag(v2f i): COLOR
           {
               return float4(1, 0, 0, 0);
           }
           ENDCG
           
       }

效果也不是很好,描边部分隔裂感依旧很重。


效果

第三种

既然我们一开始描边是顺着法线方向挤出,那如果朝着顶点的方向会不会好一点,于是就想到了让挤出方向顺着顶点的方向和法线的方向做过度。

        pass
        {
            Tags { "LightMode" = "Always" }
            Cull Front
            ZWrite On
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            float _Outline;
            float _Factor;
            struct v2f
            {
                float4 pos: SV_POSITION;
            };
            v2f vert(appdata_full v)
            {
                v2f o;
                float3 dir = normalize(v.vertex.xyz);
                float3 dir2 = v.normal;
                float D = dot(dir, dir2);
                dir = dir * sign(D);
                dir = dir * _Factor + dir2 * (1 - _Factor);
                v.vertex.xyz += dir * _Outline;
                o.pos = UnityObjectToClipPos(v.vertex);
                return o;
            }
            float4 frag(v2f i): COLOR
            {
                return float4(1, 0, 0, 0);
            }
            ENDCG
            
        }
        

效果来看差不多满足我们的需求了。


最终效果

你可能感兴趣的:(关于unity shader描边的一二事(顶点挤出式描边的探讨))