[每天一个Unity Shader] 01.卡通风格水波 / 冲击波效果
1 最终效果图
2 制作过程
2.1 准备圆盘模型
准备一个圆盘模型,拖拽放入场景中
其具有放射状的mesh网格
2.2 编写使用单张材质图的Shader
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color",Color) = (1,1,1,1)
}
SubShader
{
Tags{"RenderType" = "Opaque" "DisableBatiching" = "True"}
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct a2v{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
half4 _MainTex_ST;
fixed4 _Color;
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
//o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
half color = tex2D(_MainTex, i.uv);
return color;
}
ENDCG
}
}
编写一个使用一张纹理、不考虑光照计算的shader,新建一个材质,把这个shader赋给该材质
准备如下的一张渐变纹理,拖拽赋予给材质
得到效果如下:
2.3 使用透明度测试剔除片元
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color",Color) = (1,1,1,1)
_Thres("Threshold gradient", Range(0.0,1.1)) = 0.0
_Speed("Speed", Vector) = (1,-1,0,0)
}
首先修改属性块如下,我们需要一个用于控制剔除的阈值_Thres和控制动画速度的_Speed
fixed4 frag(v2f i) : SV_Target
{
half gradient = tex2D(_MainTex, i.uv + _Time.y * _Speed.xy).x;
clip(gradient - _Thres);
return _Color;
}
修改片元着色器如下,我们只取纹理采样颜色的r分量,使用灰度值gradient 减去阈值_Thres作为透明度测试的基准,调用Clip()函数进行透明度测试,其原理如果输入的值<0,该片元将被剔除
同时调用时间函数,通过修改uv来动态采样纹理实现动画,_Speed的x分量控制旋转速度,y分量控制扩散速度
得到的效果如下:
2.4 使用噪声
准备如下噪声纹理
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color("Color",Color) = (1,1,1,1)
_NoiseMap("NoiseMap", 2D) = "" {}
_Thres("Threshold gradient", Range(0.0,1.1)) = 0.0
_Speed("Speed", Vector) = (0,-1,0,0)
}
修改属性块,加入一张新纹理用来传入噪声
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.uv * _NoiseMap_ST.xy + _NoiseMap_ST.zw;
//o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
在结构体v2f中修改uv的类型为float4,用zw分量来存储噪声的uv
fixed4 frag(v2f i) : SV_Target
{
half gradient = tex2D(_MainTex, i.uv.xy + _Time.y * _Speed.xy).x;
half noise = 1.0- tex2D(_NoiseMap, i.uv.zw + _Time.y * _Speed.xy).x;
clip(gradient - noise - _Thres);
return _Color;
}
修改片元着色器,对噪声进行采样后同样取r分量,并使用算式: 灰度值 - 噪声值 - 阈值 来裁剪片元
效果如下:
2.5 边缘优化
在上面的效果中,水波扩散在边缘整齐地消失,显得很生硬,考虑引入一个因子来弱化边缘的强度,使得其边缘消失效果自然一些
考虑用uv实现这个效果,注意到由于圆盘mesh的特性,uv的v分量刚好有放射状的特征,它在圆盘上中心位置最小,边缘位置最大,倒置之后则是中心位置最大,边缘位置最小,正好可以作为边缘的弱化因子
将倒置后的uv的v分量打印下来观察,确实具有这个特征
half gradient = tex2D(_MainTex, i.uv.xy + _Time.y * _Speed.xy).x * (1.0 - i.uv.y);
修改灰度值的计算公式,将倒置后的v分量作为因子乘以纹理采样结果
调节阈值参数,得到最终效果

标签:
每天一个Unity Shader
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了