本篇我们一起来实现一下水波纹在2D图片上的显示效果。
实现步骤:
首先我们打开UnityHub,设置好我们的项目名称和位置,选择新建一个2D场景:
项目设置
进入项目首先我们将从网上下载好的池塘水面素材放入我们的资源文件夹中:
随后建立一个材质球,和一个Shader(ImageEffectShader类型)文件
创建一个空的游戏物体,取名background,添加Sprite Renderer组件:
将创建好的材质球赋给我们的Sprite Renderer文件,并将shader指定给该材质球
点击进入Shader文件进行代码编写工作
Shader "Hidden/waterwave"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Amount("Amount",Range(0,1))=0.5
_W("_W",Range(0,200))=100
_Speed("Speed",Range(0,500))=200
}
SubShader
{
Cull Off ZWrite Off ZTest Always
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 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float _Amount;
float _W;
float _Speed;
fixed4 frag (v2f i) : SV_Target
{
float2 center_uv=(0.5,0.5);
float2 uv =i.uv;
float2 dt=center_uv -uv;
float len =sqrt(dot(dt,dt));
float amount = _Amount/(0.01+ len*_Speed);
if(amount<0.1){
amount=0;
}
uv.x+=amount*cos( len* _W );
fixed4 col = tex2D(_MainTex, uv);
return col;
}
ENDCG
}
}
}
在代码分析开始之前我们先回顾一下高中物理课上我们学到的两个关于水波的重要知识点:
水波扩散现象:当我们向水中投掷一块石头,我们会发现一圈圈形成的水波会围绕石头入水点展开,给人一种水波是沿中心点扩散的感觉,实际上水面上每一个点都是以自身圆心为基准进行扩散的,之所以会看到环装的水波,是因为水波内部的扩散对称特性经过相互抵消的结果。
能量衰减现象:我们知道水波不会永不停止的扩散,因为水自身是有阻尼的,在扩散的过程中会存在能量衰减的情况。
这次代码的主要理论依据来源于下面这个公式
波动距离=相对振幅*cos(水波频率*位置)
定义相关参数:
贴图:_MainTex ("Texture", 2D) = "white" {}
振幅:_Amount("Amount",Range(0,1))=0.5
水波扩散频率_W("_W",Range(0,200))=100
水波衰减速度 _Speed("Speed",Range(0,500))=200
首先我们设置一个水波纹中心点
float2 center_uv=(0.5,0.5);
定义水面每个点位置
float2 uv =i.uv;
计算出各个顶点距离水波纹中心的距离
float2 dt=center_uv -uv;
距离进行点积运算处理
float len =sqrt(dot(dt,dt));
计算出每一个点的振幅范围
float amount = _Amount/(0.01+ len*_Speed);
设置展现波纹的范围控制代码
if(amount<0.1){
amount=0;
}
X方向进行位置偏移控制
uv.x+=amount*cos( len* _W );
最终返回的颜色及坐标
fixed4 col = tex2D(_MainTex, uv);
设置在屏幕中心的水波纹效果
当然我们可以在代码中加入时间参数比如_Time.y,让水波纹随着时间的变化慢慢的衰减,感兴趣的小伙伴一起来试试,看看效果吧!