在阅读《Unity Shader入门精要》时,跟着此书实现了案例shader,今天把第十一章介绍的纹理动画复现了一遍。纹理动画一个很有趣的效果,用一些简单的技巧实现动画。记录一下。感谢乐乐女神~
书中介绍两种实现简单动画的技巧,一种是利用纹理坐标的偏移,一种是利用模型顶点坐标的偏移。还介绍了一种广告牌效果,作者也归于动画的范畴:)
纹理动画
实际上就是对Texture的采样坐标进行偏移,随着时间的流动,采样不断变化,以达到动画的效果。
书中介绍了两个例子,一个是火焰动画,一个是无限移动的背景板。
火焰动画关键的代码块是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| fixed4 frag(v2f i) :SV_Target{
float time = floor(_Time.y*_Speed); float row=floor(time/_HorizonAmount); float column = time - _HorizonAmount * row;
float2 uv; uv.x =i.uv.x + column; uv.y =i.uv.y - row; uv.x /= _HorizonAmount; uv.y /= _VerticleAmount; fixed4 c=tex2D(_MainTex,uv); c.rgb *= _Color.rgb; return c;
}
|
主要就是给一个含有N*N个局部小片段纹理的动画纹理,在fragment中对采样坐标进行从左向右,从上倒下的偏移,因为时间变化是连续的,即采样坐标是连续的,所以只要动画纹理中的局部片段是连续的,则可以得到连续的动画。随着时间_Time.y的变化。其中在uv.x/=_HorizonAmount把坐标映射到局部的小片段纹理中,需要仔细体会。
移动的背景墙就简单一点,关键的代码块为:
1 2 3 4 5 6 7 8 9 10
| v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv.xy = TRANSFORM_TEX(v.uv, _FarTex)+frac(float2(_Time.y * _FarMoveSpeed,0.0)); o.uv.zw = TRANSFORM_TEX(v.uv, _NearTex)+frac(float2(_Time.y*_NearMoveSpeed,0.0));
return o; }
|
因为是横向移动的背景墙,所以只在uv.x上叠加时间的流动
其中frac函数是取值的小数位。
顶点动画
顶点动画,就是对顶点的位置进行变化。
利用Asin(Bx+C)对顶点进行偏转。其中只对X方向进行位移,对应的mesh也是在xoz平面上分布如下图所示(如果在yoz平面上,对x偏移就使得mesh像飘动的丝带)。

关键代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| v2f vert (appdata v) { v2f o; float4 offset; offset.yzw = float3(0.0,0.0,0.0); offset.x = sin(_Frequency * _Time.y + v.vertex.x * _InvWaveLength + v.vertex.y * _InvWaveLength + v.vertex.z * _InvWaveLength) * _Magnet; o.vertex = UnityObjectToClipPos(v.vertex+offset); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.uv += float2(0.0, _Time.y * _Speed); return o; }
|
对正弦函数调参就能得到各种波浪效果了

另外,在纹理采样时,也需要对纹理进行偏移达到水流的效果。y偏转为0时,水流不动。对y值进行偏转的话,结合纹理(如下图所示)的特点,会使得采样点迅速更新向偏转位置采样,则造成水流的效果。

广告牌效果
(挖个坑,下面这个是什么意思?)
1 2 3
| float3 centerOffs = v.vertex.xyz - center; float3 localPos = center + rightDir * centerOffs.x + upDir * centerOffs.y + normalDir * centerOffs.z;
|
参考文献
Unity Shader 入门精要