前言
描边和阴影,Unity本来是由自带的组件的(Outline和Shadow)。Unity自己的实现方式如下:
Outline:把原文字/图片以往的网格复制4份,然后上下左右各偏移一点距离(相当于多绘制了4遍)。
Shadow:把原文字/图片的网格复制1份,然后往某个方向偏移一点(相当于多绘制了1遍)。
我觉得是挺蛋疼的,所以就突发奇想干脆用Shader来实现会不会好一点。
正文:
由于本人水平有限,所以大部分代码都是参考网上的,代码放最后了。
代码里实现的效果如下所示:
其实发现本来想写描边的,结果搞成阴影了。不过问题不大,可以来分析一下:
这个Shader的思路就是写2个Pass,第一个Pass把原输入的网格扩大一点(注意调整扩大后的偏移),然后把他的颜色调整为黑色。然后再写1个Pass正常绘制,叠加在黑色的文字上面。但是这种实现方法有局限性:在设置阴影与原文字差别不大的时候可以 (_OutlineWidth的值大概是 0.01左右),一旦把阴影(或者说描边)的宽度扩大就会出现问题:
可以看到,这个Shader会导致文字的整体放大(而且还有网格漂移的问题),最后没法和原有文本很好地叠加在一起。我觉得是不行的,这种和我预想的描边/阴影效果差别挺大的。如果继续按照这个思路来搞,按实现秒表就再加4个Pass,前后左右各偏移一丢丢就可以了。Pass里面的内容倒是都大同小异。
结论:
我这个方法能做个参考吧,但是我觉得这个Shader不行,没有达到我想要的效果。
照这个思路的话,无论是描边还是阴影都只能描一条很细的边。目前我实现的效果更像是阴影,如果要写描边其实也比较容易,最笨的就是再写4个Pass。思路和Unity原有的是一样的,都是上下左右各偏移一点点。但是如果这么搞的话,那描边+阴影+原本的文字绘制就有6个Pass了。你说和原有的Unity方法性能相差几何?我觉得其实优势不大了……
而且这个思路最后做完,其实效果和Unity自带的组件效果是差不多的,或者说没什么大的区别。
我觉得是无用功了~
不过是不是有能用1个Pass就把描边+阴影效果都实现,而且还能解决描边不重合的方法呢?我觉得是有的,不过我目前没找到什么好的思路。
代码:
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "UI/UI_ShadowOutline"
{Properties{[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}_Color("Tint", Color) = (1,1,1,1)_StencilComp("Stencil Comparison", Float) = 8_Stencil("Stencil ID", Float) = 0_StencilOp("Stencil Operation", Float) = 0_StencilWriteMask("Stencil Write Mask", Float) = 255_StencilReadMask("Stencil Read Mask", Float) = 255_ColorMask("Color Mask", Float) = 15_OutlineWidth("描边宽度",range(0,1)) = 1_Offset("描边偏移",Vector) = (200,0,100,0)[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0}SubShader{Tags{"Queue" = "Transparent""IgnoreProjector" = "True""RenderType" = "Transparent""PreviewType" = "Plane""CanUseSpriteAtlas" = "True"}Stencil{Ref[_Stencil]Comp[_StencilComp]Pass[_StencilOp]ReadMask[_StencilReadMask]WriteMask[_StencilWriteMask]}Cull OffLighting OffZWrite OffZTest[unity_GUIZTestMode]Blend SrcAlpha OneMinusSrcAlphaColorMask[_ColorMask]Pass{Name "Default"CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 2.0#include "UnityCG.cginc"#include "UnityUI.cginc"#pragma multi_compile __ UNITY_UI_CLIP_RECT#pragma multi_compile __ UNITY_UI_ALPHACLIPstruct appdata_t{float4 vertex : POSITION;float4 color : COLOR;float2 texcoord : TEXCOORD0;UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float4 vertex : SV_POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;float4 worldPosition : TEXCOORD1;UNITY_VERTEX_OUTPUT_STEREO};sampler2D _MainTex;fixed4 _Color;fixed4 _TextureSampleAdd;float4 _ClipRect;float4 _MainTex_ST;float _OutlineWidth;float4 _Offset;v2f vert(appdata_t v){v2f OUT;UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);OUT.worldPosition = v.vertex;OUT.color = v.color * _Color;OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);//描边;_OutlineWidth += 1;float3 targetPosition = OUT.worldPosition * _OutlineWidth;targetPosition.z = v.vertex.z;targetPosition.x -= (_OutlineWidth - 1) * _Offset.x + _Offset.y;targetPosition.y -= (_OutlineWidth - 1) * _Offset.z + _Offset.w;OUT.vertex = UnityObjectToClipPos(targetPosition);//OUT.vertex.xy *= _OutlineWidth;return OUT;}fixed4 frag(v2f IN) : SV_Target{half4 targetColor = half4(0,0,0,1);half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * targetColor;#ifdef UNITY_UI_CLIP_RECTcolor.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);#endif#ifdef UNITY_UI_ALPHACLIPclip(color.a - 0.001);#endifreturn color;}ENDCG}Pass{Name "Default"CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma target 2.0#include "UnityCG.cginc"#include "UnityUI.cginc"#pragma multi_compile __ UNITY_UI_CLIP_RECT#pragma multi_compile __ UNITY_UI_ALPHACLIPstruct appdata_t{float4 vertex : POSITION;float4 color : COLOR;float2 texcoord : TEXCOORD0;UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float4 vertex : SV_POSITION;fixed4 color : COLOR;float2 texcoord : TEXCOORD0;float4 worldPosition : TEXCOORD1;UNITY_VERTEX_OUTPUT_STEREO};sampler2D _MainTex;fixed4 _Color;fixed4 _TextureSampleAdd;float4 _ClipRect;float4 _MainTex_ST;float _OutlineWidth;v2f vert(appdata_t v){v2f OUT;UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);OUT.worldPosition = v.vertex;OUT.color = v.color * _Color;OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);return OUT;}fixed4 frag(v2f IN) : SV_Target{half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;#ifdef UNITY_UI_CLIP_RECTcolor.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);#endif#ifdef UNITY_UI_ALPHACLIPclip(color.a - 0.001);#endifreturn color;}ENDCG}}}