目标是让一个矩形网格面片,通过顶点动画,实现出河流的效果。(如下图)所谓的河流效果,就是呈现出波浪感,而想要呈现出波浪感,我们必须了解 波长、波动频率、波动幅度 这些关键因素
1、波浪感的关键因素
- 波长:指两个相邻波峰或波谷之间的距离。波长越大,波动越缓慢,波形周期越长。
- 波长的倒数:1/波长,倒数越大,表示波动越频繁,波形周期越短
- 波动频率:指波动在单位时间内发生的次数(相当于波浪变化的频率)
- 波动幅度:指波峰或波谷相对于中线(静止位置)的最大偏移位置
我们需要在我们的Shader代码中,声明这三个关键因素变量,用于控制顶点的偏移
从而实现流动的2D河流效果
2、基本原理
基本原理:让我们的顶点在对应的轴向产生偏移。
主要运用的就是Shader中的内置函数 sin,以及内置时间变量 _Time.y
sin 是正弦函数,正弦函数是一个周期性函数,常用与表示波动和震荡效果,它的返回值是 -1~1
_Time.y 是切换到当前场景后所经过的时间,参与到计算中,可以让我们的波浪周期性变化
再结合 波长的倒数、波动评率、波动幅度 等可变参数,参与到计算中,便可以实现效果
关键步骤一:让顶点上下动起来
我们可以利用sin函数让顶点在希望移动的轴向上产生偏移,并且为了能够周期性变化,可以让时间参与到计算中: sin( _Time.y )
该函数随着时间的变化,会不停地返回 -1~1 之间的数
为了控制波动评率,我们可以声明波动评率变量参与计算:sin( _Time.y * 波动频率)
用得到的返回值,作为顶点在某一轴向的偏移值,便可以让顶点动起来
但这样有一个问题:所有顶点偏移的会一样,会呈现出整体移动的效果
关键步骤二:让顶点有差异性的动起来
为了让顶点之间偏移位置有差异,我们可以在计算 sin 时利用每个顶点的不同点制造差异性
对于顶点来说,不同点主要来自坐标,我们可以利用他们变化某个轴的坐标制造差异性
sin( _Time.y * 波动频率 + 顶点某轴坐标)
用得到的返回值,作为顶点在某一轴向的偏移值,便可以让顶点有差异性的动起来
但是这样还是没办法体现波长和波动幅度
关键步骤三:体现波长和波动幅度
sin( _Time.y * 波动频率 + 顶点某轴坐标) 已经可以帮助我们实现波动变化了
想要体现出波长和波动幅度,我们只需要将这两个变量参与计算即可
波长的体现: sin( _Time.y * 波动频率 + 顶点某轴坐标 * 波长的倒数)
倒数越大,波形周期越短
波动幅度体现: sin( _Time.y * 波动频率 + 顶点某轴坐标 * 波长的倒数) * 波动幅度
相当于将 -1~1 范围扩大了
总结后就是:
流动的2D河流基本原理,就是利用下面这个公式,对顶点位置进行偏移计算
某轴位置偏移量 = sin( _Time.y * 波动频率 + 顶点某轴坐标 * 波长的倒数) * 波动幅度
其中具体轴向根据模型空间决定波动频率、波长倒数、波动幅度为自定义变量,可以外部调节
3、实现
在这里需要一个渲染标签:"DisableBatching" = "True"
主要作用:是否对SubShader关闭批处理
在制作顶点动画时,有时需要关闭该Shader的批处理,因为在制作顶点动画时,有时需要使用模型空间下的数据,而批处理会合并所有相关的模型,这些模型各自的模型空间会丢失,导致我们无法正确使用模型空间下相关数据。在实现流程的2D河流效果时,我们就需要让顶点在模型空间下进行偏移,因此我们需要使用该标签,为该Shader关闭批处理、
Shader "ShaderProj/8/2DWate"
{Properties{_MainTex ("Texture", 2D) = "white" {}_Color ("Color", Color) = (1,1,1,1)// 波动的幅度、频率、波长的倒数_WaveAmplitude("WaveAmplitude", Float) = 1_WaveFrequency("WaveFrequency", Float) = 1_InvWaveLength("InvWaveLength", Float) = 1// 纹理变化速度_Speed("Speed", Float) = 1}SubShader{//透明Shader相关渲染标签 + 关闭批处理标签Tags { "RenderType"="Tranparent" "Queue"="Transparent" "IgnoreProjector" = "True" "DisableBatching" ="True"}Pass{ZWrite OffBlend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;float4 _Color;float _WaveAmplitude;float _WaveFrequency;float _InvWaveLength;float _Speed;v2f vert (appdata_base v){v2f o;// 模型空间下的偏移位置float4 offset;// 在模型空间的 x 轴进行偏移offset.x = sin(_Time.y * _WaveFrequency + v.vertex.z * _InvWaveLength) * _WaveAmplitude;offset.yzw = float3(0, 0, 0);o.vertex = UnityObjectToClipPos(v.vertex + offset);o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);o.uv += float2(0, _Time.y * _Speed);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 color = tex2D(_MainTex, i.uv);color.rgb *= _Color.rgb;return color;}ENDCG}}
}