前言
大家好,本期给大家展示shader实现的一些有趣的效果,寓教于乐
效果是由uv流动+遮罩实现,具体来说就是,
- 将第二张图片与第一张图片利用a通道进行混合
- a通道的区域由一个黑白图片决定,遮罩的r值决定利用哪个图片的像素
- mask.r=0,像素由第一个图片决定,mask.r=1,像素由第二个图片决定
资源
遮罩图片,可以利用ps制作
- 使用钢笔工具
- 选择形状
- 关闭填充,打开描边,调整描边大小
- 加模糊,顶部菜单栏->滤镜/模糊/高斯模糊或者表面模糊
Shader代码
- 创建Shader,创建->Shader->Unlit Shader,命名为MaskUVFlow
2.声明Properties
Properties
{
_MainTex ("Texture", 2D) = "white" {}//主贴图,在下面的贴图
_FlowTexture("FLowTexture",2D)="white" {}//副贴图,在上面流动的贴图
_MaskVTex("MaskSin Texture",2D)="white" {}//V形遮罩贴图
_FlowSpeed("FlowSpeed",Float)=1//uv流动的速度
_Drakness("Drakness",Range(0,1))=1//主贴图的暗度
_Brightness("Brightness",Range(1,5))=1//副贴图的亮度
}
- 定义
//顶点着色器,接收的结构体
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//片元着色器,接收的结构体,由顶点着色器传入
struct v2f
{
float2 uv : TEXCOORD0;//主贴图变换后的uv
float2 uv1:TEXCOORD1;//副贴图变换后的uv
float2 uv2:TEXCOORD2;//遮罩贴图变换后的uv
float4 vertex : SV_POSITION;
};
- 顶点着色器
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _FlowTexture;
sampler2D _MaskVTex;
float4 _FlowTexture_ST;
float4 _MaskVTex_ST;
float _FlowSpeed;
float _Drakness;
float _Brightness;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);//将模型空间->裁剪空间
o.uv = TRANSFORM_TEX(v.uv, _MainTex);//变换主贴图的uv
//o.uv=v.uv*_MainTex_ST.xy+_MainTex_ST.zw;
//使用一个float4对原来的uv进行缩放和偏移
o.uv1 = TRANSFORM_TEX(v.uv,_FlowTexture);//变换副贴图的uv
o.uv2 = TRANSFORM_TEX(v.uv, _MaskVTex);//变换遮罩贴图的uv
o.uv2=float2(o.uv2.x+_Time.y*_FlowSpeed,o.uv2.y);
//_Time.y单位s,游戏运行的秒数
//利用对遮罩贴图的uv的x进行偏移
return o;
}
- 片元着色器
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//利用uv对_MainTex进行采样
//如(0.1,0.2),图片大小1920*1080=>采样(192,216)
fixed4 col2=tex2D(_FlowTexture,i.uv1);
float mask=tex2D(_MaskVTex,i.uv2).r;//获取遮罩图片的r通道
_Drakness=0.5-_Time.y%10/20;//每十秒暗度从0.5变化到0
_Brightness=_Time.y%10/5+1;//每十秒亮度从1变化到3
col*=_Drakness; //使用暗度乘以主贴图的rgba
col2*=_Brightness;//使用亮度乘以副贴图的rgba
fixed4 final=lerp(col,col2,mask);
//线性插值,lerp(a,b,t),a + (b - a) * t
//利用mask.r混合图片1和2,mask黑色的区域显示为图片1,mask白色的区域显示为图片2
return final;
}
完整Shader代码
Shader "Unlit/FlowSin"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}//主贴图,在下面的贴图
_FlowTexture("FLowTexture",2D)="white" {}//副贴图,在上面流动的贴图
_MaskVTex("MaskSin Texture",2D)="white" {}//V形遮罩贴图
_FlowSpeed("FlowSpeed",Float)=1//uv流动的速度
_Drakness("Drakness",Range(0,1))=1//主贴图的暗度
_Brightness("Brightness",Range(1,5))=1//副贴图的亮度
}
SubShader
{
Tags
Tags { "RenderType" = "Opaque" "Queue" = "Transparent" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//顶点着色器,接收的结构体
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
//片元着色器,接收的结构体,由顶点着色器传入
struct v2f
{
float2 uv : TEXCOORD0; //主贴图变换后的uv
float2 uv1:TEXCOORD1; //副贴图变换后的uv
float2 uv2:TEXCOORD2; //遮罩贴图变换后的uv
float4 vertex : SV_POSITION;//变换到裁剪空间的位置
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _FlowTexture;
sampler2D _MaskVTex;
float4 _FlowTexture_ST;
float4 _MaskVTex_ST;
float _FlowSpeed;
float _Drakness;
float _Brightness;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex); //将模型空间->裁剪空间
o.uv = TRANSFORM_TEX(v.uv, _MainTex); //变换主贴图的uv
//o.uv=v.uv*_MainTex_ST.xy+_MainTex_ST.zw;
//使用一个float4对原来的uv进行缩放和偏移
o.uv1 = TRANSFORM_TEX(v.uv, _FlowTexture); //变换副贴图的uv
o.uv2 = TRANSFORM_TEX(v.uv, _MaskVTex); //变换遮罩贴图的uv
o.uv2 = float2(o.uv2.x + _Time.y * _FlowSpeed, o.uv2.y);
//_Time.y单位s,游戏运行的秒数
//利用对遮罩贴图的uv的x进行偏移
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//利用uv对_MainTex进行采样
//如(0.1,0.2),图片大小1920*1080=>采样(192,216)
fixed4 col2 = tex2D(_FlowTexture, i.uv1);
float mask = tex2D(_MaskVTex, i.uv2).r; //获取遮罩图片的r通道
_Drakness = 0.5 - _Time.y % 10 / 20; //每十秒暗度从0.5变化到0
_Brightness = _Time.y % 10 / 5 + 1; //每十秒亮度从1变化到3
col *= _Drakness; //使用暗度乘以主贴图的rgba
col2 *= _Brightness; //使用亮度乘以副贴图的rgba
fixed4 final = lerp(col, col2, mask);
//线性插值,lerp(a,b,t),a + (b - a) * t
//利用mask.r混合图片1和2,mask黑色的区域显示为图片1,mask白色的区域显示为图片2
return final;
}
ENDCG
}
}
}
ASE实现
- uv流动,遮罩
- 控制图片亮度
结束语
本文章只是用Shader实现有趣的效果,寓教于乐
如果有不懂的地方或者建议,欢迎在评论区交流
制作不易,希望大家支持一下,谢谢~~😊
遮罩图片可以换成正弦波
可以根据自己的喜好更换