Unity Shader序列帧动画学习笔记
关于无限播放序列帧动画的一点问题
在学shader的序列帧动画时,书上写了这样一段代码:
fixed4 frag(v2f i){
// 获得整数时间
float time = floor(_Time.y * _Speed) % 64;
// 根据时间计算当前行数和列数
float row = floor(time/_HorizontalAmount);
// 对uv坐标进行偏移
half2 uv = float2(i.uv.x/_HorizontalAmount,i.uv.y/_VerticallAmount);
uv.x += column / _HorizontalAmount;
uv.y -= row / _VerticallAmount;
fixed4 c = tex2D(_MainTex,uv);
c.rgb *= _Color; float column = time - row * _HorizontalAmount;
return c;
}
就是依据时间变量_Time来获得当前要播放的序列帧动画在整个Texture里是第几行第几列,然后在后面根据列数行数绘制当前序列帧动画,在上面的代码中,用time/_HorizontalAmount来获得当前行数,用time % _HorizontalAmount来获得当前列数,其中_HorizontalAmount表示在Texture中一行中有多少个序列帧动画。
一开始我看到上面的代码的时候是蒙蔽的!_Time.y表示从游戏开始到现在经过的时间,而行数和列数跟time变量是成正比例的,我就想。
难道row和column变量不会迅速膨胀吗??!
但是,使用上述代码表现出来的shader是不断的重复播放该动画,这是为什么呢?
Answer
首先给出肯定,row和column是肯定会随着time的变大而不停的变大的,那么为什么表现出来的效果不是动画播放一次之后就结束呢?(因为当row和column变大后,后面根据行数和列数绘制序列帧的代码就会失效,因为row和column已经超过了整个Texture最大的行数和列数了)
答案是
Texture(贴图)的Wrap Mode属性被设置为了Repeat!
当行数和列数急剧增加的时候,在后面的代码中计算他们的偏移也会急速的增长,见下面的代码:
// 对uv坐标进行偏移
half2 uv = float2(i.uv.x/_HorizontalAmount,i.uv.y/_VerticallAmount);
uv.x += column / _HorizontalAmount;
uv.y -= row / _VerticallAmount;
其中column/_HorizontalAmount和row/_VerticalAmount会不停的变大,当前uv的偏移坐标大于(1,1)的时候,Repeat属性就起到了作用!Repeat属性规定当uv坐标超过(1,1)时,就会不停的重复本身的图形。
所以上述代码才会不停的进行播放动画。
但是,个人认为直接这样写还是不妥,实际测试中,当speed超过10^6,图像就会变得失真,变成一团马赛克,如下图所示。
所以,最好的方法是,将题目中的row和column限制在一定范围,下面是我改动的代码。
// 获得整数时间
float time = floor(_Time.y * _Speed) % (_HorizontalAmount*_VerticallAmount);
// 根据时间计算当前行数和列数
float row = floor(time/_HorizontalAmount);
float column = time - row * _HorizontalAmount;