[Unity] Simple Shaderlab 1 // UI用的簡單shader 1 - 流光


最近經常要給2D游戲寫一些新的shader來做特效。比起粒子特效,着色器特效可能更適合UI和2D元素上的表現。

先看一下效果:

 

關於在shaderlab種實現流光的文章很多,但很少有給UI實現的,並且常常只是Add一層顏色,並沒有去表現“光”的效果。

以下是shader全文,后面會介紹一些細節:

  1 Shader "UI/Unlit/Flowlight"
  2 {
  3     Properties
  4     {
  5         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
  6         _Color ("Tint", Color) = (1, 1, 1, 1)
  7         [MaterialToggle] PixelSnap ("Pixel snap", float) = 0
  8         
  9         /* Flowlight */
 10         _FlowlightTex ("Add Move Texture", 2D) = "white" {}
 11         _FlowlightColor ("Flowlight Color", Color) = (0, 0, 0, 1)
 12         _Power ("Power", float) = 1
 13         _SpeedX ("SpeedX", float) = 1
 14         _SpeedY ("SpeedY", float) = 0
 15         /* --------- */
 16 
 17         /* UI */
 18         _StencilComp ("Stencil Comparison", Float) = 8
 19         _Stencil ("Stencil ID", Float) = 0
 20         _StencilOp ("Stencil Operation", Float) = 0
 21         _StencilWriteMask ("Stencil Write Mask", Float) = 255
 22         _StencilReadMask ("Stencil Read Mask", Float) = 255
 23         /* -- */
 24     }
 25 
 26     SubShader
 27     {
 28         Tags
 29         { 
 30             "Queue"="Transparent" 
 31             "IgnoreProjector"="True" 
 32             "RenderType"="Transparent" 
 33             "PreviewType"="Plane"
 34             "CanUseSpriteAtlas"="True"
 35         }
 36 
 37         Cull Off
 38         Lighting Off
 39         ZWrite Off
 40         Blend One OneMinusSrcAlpha
 41         
 42         /* UI */
 43         Stencil
 44         {
 45             Ref [_Stencil]
 46             Comp [_StencilComp]
 47             Pass [_StencilOp] 
 48             ReadMask [_StencilReadMask]
 49             WriteMask [_StencilWriteMask]
 50         }
 51         /* -- */
 52 
 53         Pass
 54         {
 55         CGPROGRAM        
 56             #pragma vertex vert
 57             #pragma fragment frag
 58             #pragma multi_compile _ PIXELSNAP_ON
 59             #include "UnityCG.cginc"
 60             
 61             struct appdata_t
 62             {
 63                 float4 vertex : POSITION;
 64                 float4 color : COLOR;
 65                 float2 texcoord : TEXCOORD0;
 66             };
 67 
 68             struct v2f
 69             {
 70                 float4 vertex : SV_POSITION;
 71                 fixed4 color : COLOR;
 72                 half2 texcoord : TEXCOORD0;
 73 
 74                 /* Flowlight */
 75                 half2 texflowlight : TEXCOORD1;
 76                 /* --------- */
 77             };
 78             
 79             fixed4 _Color;
 80 
 81             /* Flowlight */
 82             fixed4 _FlowlightColor;
 83             float _Power;
 84             sampler2D _FlowlightTex;
 85             fixed4 _FlowlightTex_ST;
 86             fixed _SpeedX;
 87             fixed _SpeedY;
 88             /* --------- */
 89 
 90             v2f vert(appdata_t IN)
 91             {
 92                 v2f OUT;
 93                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
 94                 OUT.texcoord = IN.texcoord;
 95 
 96                 /* Flowlight */
 97                 OUT.texflowlight = TRANSFORM_TEX(IN.texcoord, _FlowlightTex);
 98                 OUT.texflowlight.x += _Time * _SpeedX;
 99                 OUT.texflowlight.y += _Time * _SpeedY;
100                 /* --------- */
101 
102                 OUT.color = IN.color * _Color;
103                 #ifdef PIXELSNAP_ON
104                 OUT.vertex = UnityPixelSnap (OUT.vertex);
105                 #endif
106 
107                 return OUT;
108             }
109 
110             sampler2D _MainTex;
111 
112             fixed4 frag(v2f IN) : SV_Target
113             {
114                 fixed4 c = tex2D(_MainTex, IN.texcoord);
115 
116                 /* Flowlight */
117                 fixed4 cadd = tex2D(_FlowlightTex, IN.texflowlight) * _Power;
118                 cadd.rgb *= c.rgb;
119                 c.rgb += cadd.rgb;
120                 c.rgb *= c.a;
121                 /* --------- */
122 
123                 return c;
124             }
125         ENDCG
126         }
127     }
128 }

其實博文發出來之后這個改過一次,因為是用的Sprite-Default改的,能用在UI上但沒有實現遮罩等等功能,這次補上。

/* UI */里的就是添加上的屬於UI shader的部分,如果只是用在Sprite上的話這部分可以刪掉。

而/* Flowlight */里的是從Sprite-Default基礎上添加的部分,去掉之后就變成Sprite-Default原文了(

 

其實流程和正常的UV滾動疊加沒有什么區別,注意要用UI傳入的UV計算紋理坐標。

97  OUT.texflow = TRANSFORM_TEX(IN.texcoord, _FlowlightTex);

之后兩張紋理在frag中疊加輸出,需要注意的只有一行:

118  cadd.rgb *= c.rgb;

很多shader作者在寫流光的時候只是把疊加紋理的顏色+=在了主紋理上,但如果先將疊加紋理乘以主紋理的顏色,就會讓暗色變得更暗,更符合光吸收的感覺,再配合Power控制光強度可以更好地表現光。

當然這樣一來的副作用就是流光紋理本身的顏色就沒有用了,因為變成了只用灰度,畢竟本來目的只是在打光。需要顏色的話可以在這行的下一行乘以自定義顏色,這里就不寫了。

以上是需要留意的部分。

 

具體流程上,在vert中先獲得流光紋理的紋理坐標OUT.texflow,而后使用_Time時間參數讓紋理坐標隨時間偏移,注意偏移操作在頂點着色vert部分進行而不是在片段着色frag,這樣不會浪費計算量。

之后在frag中進行疊加將流光紋理與主紋理疊加,注意是c.rgb += cadd.rgb,否則c += cadd會導致透明通道也被疊加上去,對下一步c的預乘透明通道產生影響。

 

在紋理的制作上,因為是循環滾動,所以為了不會讓光出現過度頻繁,需要在流光紋理的旁邊加上合適寬度的黑色區域。

下面是本文開頭動圖使用的流光紋理:

 

它在光線紋理(正方形)的左側加上了等寬的黑色區域,讓紋理變為了2x1的寬高,這樣再將材質的Tiling改為X:0.5 Y:1就可以讓光出現的頻率減半了,當然還可以把光線區域在PS再縮小為66%,這樣就可以讓光線的出現頻率變為最初的1/3了(別忘了改Tilling),其他頻率以此類推。

 

下一次會分享一下uGui用的溶解。說是uGui用,其實使用了UI或Sprite Shader的東西都可以用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM