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控件即可。
效果:
代码:
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
}
}
}