前言
学习UnityShader已经有几个月了,从刚开始开、看shder代码像看天书一样的小白,到现在略懂一二的入坑新人,一路走来体会到了shader神奇的力量。这次是我首次针对项目需求实现的shader,实现UI从上往下渐变,心里还是有点小小窃喜 哈哈哈哈。
效果
逻辑
做到从下往上或者从左往右的基本逻辑就是如何确定顶点在那个位置。uv坐标就能帮我们确定。uv的x轴分量0表示图片的最左端,1表示图片的最右端。uv的y轴分量0表示图片的最下端,1表示图片的最上端。
得到了顶点的位置,接下来就是如何改变该点的alpha值。我们通过垂直方向举例,已知uv的y分量从下往上增大,如果 alpha 直接等于 uv.y 那么图标将是一张从上往下逐渐渐变的图。
这样我们还不能控制它消失和不透明显示,我们可以声明一个属性 _FillAmount ,
让alpha = _FillAmount + uv.y,我们可以控制_FillAmount 来控制图片的alpha了。
当_FillAmount = -1 时 _FillAmount + uv.y <= 0,当_FillAmount = 1时 _FillAmount + uv.y >= 0。
我们在Properties 这样声明_FillAmount("Fill Amount",Range(0,1)) = 0 (因为这样看着更人性化) 然后在使用时进行处理_FillAmount = (_FillAmount - 0.5f) * 2,就可以得到[-1,1];
我们已经可以控制透明度了,那如何倒转方向实现从下到上啦?我们先声明一个属性[MaterialToggle]_VerReverse("Vertical Reverse",int) = 0,加上了[MaterialToggle]的前缀_VerReverse的值只能是0和1,而shader中使用if-else语句会影响性能所以我们只能通过计算的方式入手。倒转方向改uv的方向和倒转_FillAmount 的值都行,我这里是处理的uv的方向,我就直接给出公式:
half ver = -((_VerReverse - 0.5f) * 2) * i.uv.y + _VerReverse;
当_VerReverse 等于0时-(0-0.5f) * 2 = 1 所以方向不变,
当_VerReverse 等于1时-(1-0.5f) * 2 = -1 、-1 * i.uv.y + 1 、[0,1] =>[1,0]
代码
Shader "MyShader/UITransparentGradient"
{
Properties
{
_FillAmount("Fill Amount",Range(0,1)) = 0 // 图片填充百分比
_Multiple("Multiple",Range(1,10)) = 0 // 边缘渐变效果
[MaterialToggle]_Vertical("Vertical",int) = 0 // 垂直开关
[MaterialToggle]_VerReverse("Vertical Reverse",int) = 0 // 垂直渐变方向
[MaterialToggle]_Horizontal("Horizontal",int) = 0 // 水平开关
[MaterialToggle]_HorReverse("Horizontal Reverse",int) = 0 // 水平渐变方向
}
SubShader
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
Pass
{
//深度写入
ZWrite On
//掩码遮罩
ColorMask 0
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
half _FillAmount;
half _Multiple;
int _Vertical;
int _VerReverse;
int _Horizontal;
int _HorReverse;
v2f vert (appdata v)
{
v2f o;
// 计算裁剪空间顶点
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 图片颜色
fixed4 col = tex2D(_MainTex, i.uv);
// 处理渐变进度
_FillAmount = (_FillAmount - 0.5f) * 2;
// 计算uv垂直轴的方向
half ver = -((_VerReverse - 0.5f) * 2) * i.uv.y + _VerReverse;
// 垂直透明度
half alphaVer = min((ver + _FillAmount) * _Multiple,1);
alphaVer = max(alphaVer,0);
// 开关
_Vertical = 1 -_Vertical;
alphaVer = max(alphaVer,_Vertical);
// 计算uv水平轴的方向
half hor = -((_HorReverse - 0.5f) * 2) * i.uv.x + _HorReverse;
// 水平透明度
half alphaHor = min((hor + _FillAmount) * _Multiple,1);
alphaHor = max(alphaHor,0);
// 开关
_Horizontal = 1 -_Horizontal;
alphaHor = max(alphaHor,_Horizontal);
// 选择最小透明度
half alpha = min(alphaHor,alphaVer);
col.a = min(alpha , col.a) ;
return col;
}
ENDCG
}
}
}