如何实现关卡切换黑屏遮罩

如何实现关卡切换黑色遮罩效果

1. shader需求分析

昨日看到一个效果,就是关卡结束可以有一个logo遮住关卡的效果,如下:

GIF来源:Fululu627的视频
为了仿制了一个,我尝试了使用UI中的Mask组件,然后动画调控scale,最后发现锯齿太多。由于最近在学shader,于是想shader能不能做这件事情?

所以让我们来分析,这里提出了三个需求:

  1. 我们需要让纹理一部分透过遮罩看到场景
  2. 我们需要一个纹理在中心点放大缩小的效果
  3. 我们需要让放大缩小受到脚本控制,可以录制动画

2. 实现需求

2.1 素材准备

  • 利用ps制作了一个黑色遮罩效果,透明部分为纯白色

2.2 白色部分片元裁切

由于是平面的图片,且放到Canvas下,所以不可能在顶点着色器中修改什么,只需要修改片元着色器即可。

  1. 创建一个unlit的shader
  2. 将Queue和RenderType改到Transparent
  3. 然后在片元着色器中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 100
        
        Pass
        {
            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 texture
                float2 uv = uvValue(i.uv,float2(0.5,0.5),_Num);//调用函数
                fixed4 col = tex2D(_MainTex, uv);
                clip(0.1 - col.r);//裁剪
                return col;
            }
            ENDCG
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值