unity ugui自定义Text字体描边优化性能

在unity的ugui的用于Text描边的组件outline中,其中的实现是将字体copy出几份往外放置形成背景黑边,随之带来的是性能的高消耗。如果是一两个Text描边还好,如果同屏有大量Text在使用其在描边时,其性能消耗提高十分明显,甚至直接影响到了游戏FPS。
因此,同屏Text描边多时有必要优化一下,因此写一个可以实现Text描边的shader。
一样的道理,shader中有2个Pass,但多个Text在使用其描边时,Unity会自动进行批处理,所以整体上只会多出一个drawcall,相比ugui内置的outline组件,此shader性能提升巨大,效果明显!

用法: 1,导入此TextOutline.shader,

2,Project视窗下右键Create->Material,命名为TextOutline,然后它选中在 Inspector视窗中最上端Shader属性选择Custom->TextOutline。

3,将2步骤的TextOutline Material赋给需要描边的ugui Text控件即可。

效果:

unity ugui自定义Text字体描边优化性能

代码:

TextOutline.shader :


Shader "Custom/TextOutline" {
    Properties {
        _MainTex ("Font Texture", 2D) = "white" {}
        _Color ("Text Color", Color) = (1,1,1,1)
        _OutlineColor ("Outline Color", Color) = (0,0,0,1)
    }

    SubShader {

        Tags {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
        }
        Lighting Off Cull Off ZTest Always ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

		//第一个Pass,实现Text内容背景颜色,并向外扩大_OutlineWidth
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                //UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            uniform float4 _MainTex_ST;
            uniform float4 _MainTex_TexelSize;
            uniform fixed4 _Color;
            uniform fixed4 _OutlineColor;


            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.color = v.color * _Color;
                o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
			//确定每个像素周围8个像素的坐标。
            static const float2 dirList[9]={
                float2(-1,-1),float2(0,-1),float2(1,-1),
                float2(-1,0),float2(0,0),float2(1,0),
                float2(-1,1),float2(0,1),float2(1,1)
            };
			//谋取dirList第dirIndex个方位的透明度值。
            float getDirPosAlpha(float index, float2 xy){
				float2 curPos = xy;
                float2 dir = dirList[index];
				float2 dirPos = curPos + dir * _MainTex_TexelSize.xy * 0.6;
                return tex2D(_MainTex, dirPos).a;
            };
			//对于每个像素,传入片元参数v2f i ,获取次像素周围和自身的共9个像素进行透明度叠加。
			//那么得出的结果就是非透明的区域被放大了,形成了黑边。
            float getShadowAlpha(float2 xy){
                float a = 0;
				float index = 0;
                a += getDirPosAlpha(index, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a += getDirPosAlpha(index++, xy);
                a = clamp(a,0,1);
                return a;
            }


            //由于渲染Text内容时,Text字上没有被渲染的区域是透明的,也就是透明度a值是0,
			//所以只要将有内容的区域往外透明度为0的区域扩展一些像素将就能够形成描边效果。
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = _OutlineColor;
				float2 xy = i.texcoord.xy;
                col.a *= getShadowAlpha(xy);
                return col;
            }
            ENDCG
        }
		//第二个Pass,常规渲染Text内容。
				
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float4 texcoord : TEXCOORD0;
                //UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            uniform float4 _MainTex_ST;
            uniform float4 _MainTex_TexelSize;
            uniform fixed4 _Color;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.color = v.color * _Color;
                step(v.texcoord, v.vertex.xy);
                o.texcoord = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = i.color;
				col.a = tex2D(_MainTex, i.texcoord).a;
                return col;
            }
            ENDCG
        }
    }
}