我们都知道顶点着色器可以用来改变模型各个顶点的位置,那么本篇我们就利用顶点着色器来做一个模拟简单水波的应用。
1. 简谐运动
在进行模拟水波之前,我们需要了解简谐运动(Simple Harmonic Motion)公式:
其中,是物体在时刻 t 的位移。是振幅,表示物体离开平衡位置的最大距离。是角频率,表示单位时间内物体转过的角度。是时间,表示从某个参考点开始经过的时间,可以理解为频率。是初相位,表示 时物体的初始位置与平衡位置的相位差。
在物理学中,简谐运动是一种理想化的运动模型,许多实际的振动系统(如弹簧振子、单摆等)在近似条件下都可以看作是简谐运动。我们可以利用简谐运动的公式来模拟简单水波的运动。
2. 实现横波与纵波
我们首先在Properties语义块中定义三个可调参数:
_Range("振幅", range(0, 1)) = 0.1
_Hz("频率", range(0.1, 2)) = 1
_Speed("速度", range(1, 5)) = 1
然后我们直接在代码里套用公式:
v2f vert(a2v appData)
{
// 简谐运动计算
appData.vertex.y += _Range * sin(appData.vertex.x * _Hz + _Time.y * _Speed);
v2f outData;
outData.pos = UnityObjectToClipPos(appData.vertex);
outData.color = fixed4(appData.vertex.y, appData.vertex.y, appData.vertex.y, 1);
return outData;
}
运行效果如下:
我们发现平面就会进行类似横波的运动,如果我们在公式里将appData.vertex的x改成z:
appData.vertex.y += _Range * sin(appData.vertex.z * _Hz + _Time.y * _Speed);
则平面就会进行纵波运动。
倘若我们将这两个公式计算全都加上,则会呈现如下效果:
3. 实现环形波
现在我们要实现一个以平面中心为起点向外扩散的环形波,只需把顶点与中心点之间的距离带入计算即可:
appData.vertex.y += _Range * sin(-length(appData.vertex.xz) * _Hz + _Time.y * _Speed);
实现效果如下:
4. 模拟简单水波
最后,我们运用两个简谐运动公式的叠加来模拟一个简单的水波效果:
appData.vertex.y += _Range * sin((appData.vertex.x + appData.vertex.z) * _Hz + _Time.y * _Speed);
appData.vertex.y += _Range * 1.5f * sin((appData.vertex.x - appData.vertex.z) * _Hz + _Time.w * _Speed);
简单地配置一下参数:
运行效果如下: