如何实现关卡切换黑色遮罩效果
1. shader需求分析
昨日看到一个效果,就是关卡结束可以有一个logo遮住关卡的效果,如下:
GIF来源:Fululu627的视频
为了仿制了一个,我尝试了使用UI中的Mask组件,然后动画调控scale,最后发现锯齿太多。由于最近在学shader,于是想shader能不能做这件事情?
所以让我们来分析,这里提出了三个需求:
- 我们需要让纹理一部分透过遮罩看到场景
- 我们需要一个纹理在中心点放大缩小的效果
- 我们需要让放大缩小受到脚本控制,可以录制动画
2. 实现需求
2.1 素材准备
- 利用ps制作了一个黑色遮罩效果,透明部分为纯白色
2.2 白色部分片元裁切
由于是平面的图片,且放到Canvas下,所以不可能在顶点着色器中修改什么,只需要修改片元着色器即可。
- 创建一个unlit的shader
- 将Queue和RenderType改到Transparent
- 然后在片元着色器中
clip(0.1 - col.r);
这个函数代表如果此时传入的值为负就将其裁切。
2.3 在中心点放缩
在实现放缩之前,首先思考,由于uv的范围是(0,0)->(1,1),所以贸然放缩,肯定是围绕(0,0)去放缩,可现在明显中点在(0.5,0.5)。
我们想到一句话:如果要进行放缩旋转操作,先要将该片元平移到原点,然后旋转放缩,结束后再平移回去。(如果不知道,详情可以看Learn Unity Shader from Scratch系列的3-15.2)
按照这个原理,我们构造了一个放缩函数。
//pos是传入的uv,center是绕哪个点放缩,num是放缩系数
float2 uvValue(float2 pos,float2 center,float num)
{float2 destPos = pos - center;destPos = destPos * num;return destPos + center;
}
于是,只要在片元着色器中调用这个函数就好啦。
2.4 利用脚本实现放缩效果
在脚本中获得Image组件,从Image中点出Material设置_Num。然后利用Animator制作一个控制 _Num的动画。
效果如下:
虽然仍然有锯齿,但这多半是准备素材质量不高的导致的,并且锯齿不像放缩scale那么难看,只要提高导入MainTexture质量就行。
3. 大功告成
这里贴出实现的shader。完成撒花!
Shader "TWShaders/MaskBlack"
{Properties{_MainTex ("Texture", 2D) = "white" {}_Num("Num",Float) = 1}SubShader{Tags { "RenderType"="Transparent" "Queue" = "Transparent"}LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 position : SV_POSITION;float4 worldPos : TEXCOORD1;};sampler2D _MainTex;float4 _MainTex_ST;float _Num;//放大倍数v2f vert (appdata v){v2f o;o.position = UnityObjectToClipPos(v.vertex);o.worldPos = mul(unity_ObjectToWorld,v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}//自制放缩函数float2 uvValue(float2 pos,float2 center,float num){float2 destPos = pos - center;destPos = destPos * num;return destPos + center;}fixed4 frag (v2f i) : SV_Target{// sample the texturefloat2 uv = uvValue(i.uv,float2(0.5,0.5),_Num);//调用函数fixed4 col = tex2D(_MainTex, uv);clip(0.1 - col.r);//裁剪return col;}ENDCG}}
}