Unity Shaders and Effects Cookbook:修改UV坐标实现帧动画
在2D游戏中,如果要做动画效果,一般是让美术制作连续帧的动画,然后我们用代码控制图片连续播放,这样就实现了帧动画,在shader中也可以实现这个效果。
上篇文章大家已经学会了如何改变UV坐标来实现水流效果,这篇文章我们就通过改变UV坐标来实现帧动画效果。
美术给我们的帧动画的图可能是一张一张的小图,也可以是类似于下面的大图图集。
在 Shader 中实现帧动画的原理:
默认的,Shader 中的 UV 范围是 (0,1) ,也就是说默认的是整个图集 这张大图显示出来,如下图
这里有9张小图 如果要显示 第一张小图,该怎么办?
只要把 UV的范围修改成 ( 0 , 1/9 ) 就是了,那么从 (0,1) 到 ( 0 , 1/9 ) ,只要乘以 1/9 就可以了。
然后根据Unity提供的内置变量 _Time.y 进行取整,每次 _Time.y 增加 1 就移动 1/9,然后加上位移,那么
从 0 - 1s 这个时间段,取整为 1 显示的都是 第一张图 ( 0 , 1/9 ) 的x 范围,即第一张小图。
从 1 - 2s 这个时间段, 取整为 2 显示的都是 第一张图 ( 1/9 , 2/9 ) 的x范围,即第二张小图。
Shader完整代码
Shader "CookBookShaders/Sprite Sheet Anim" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed2 spriteUV = IN.uv_MainTex; float cellPercentage = 1.0 / 9; //每一个小图占百分比; float xValue=spriteUV.x; //UV默认是(0,1),就是说默认显示整个大图,我们要显示一个小图,UV要指定到(0,1/9)的范围; xValue=xValue*(1.0/9); //再对时间取整,如果 _Time.y 时间超过了1,就加一个小图这么宽的位移,也就是把x 指到下一个小图的范围。就显示出下一个小图 xValue+=cellPercentage * ceil(_Time.y); //_Time.y 等同于 Time.timeSinceLevelLoad,就是游戏运行时间 //再赋值; spriteUV = float2(xValue,spriteUV.y); half4 c = tex2D (_MainTex, spriteUV); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
这里再次提醒 _Time 是一个 float4变量,值为 值为 Time (t/20, t, t*2, t*3), t 等同于 Time.timeSinceLevelLoad,就是游戏开始运行时间。
所以我这里取的 _Time.y 就是游戏开始运行到现在的时间,ceil ( _Time.y ) 就是游戏运行到现在有多少秒,每秒变动一次图片。
书上也提到,在计算 当前应该将 UV 偏移到第几张小图 这里,可以把这个计算移动到 CPU中,用以节省 GPU 。
那新建一个脚本,内容如下:
using UnityEngine; using System.Collections; public class SpriteSheetAnim : MonoBehaviour { float cellIndex; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } void FixedUpdate() { cellIndex = Mathf.Ceil(Time.time); transform.renderer.material.SetFloat("_cellIndex", cellIndex); } }
在 FixedUpdate 中计算,仍然是对 当前时间进行了取整,来计算出当前应该偏移到第几张图。
把脚本挂在 Quad 上。运行后效果同上面的图。
另外书上的 Shader 代码写的太复杂……
其中用到了另一个内置函数 fmod:
fmod ( x, y) 返回 x / y 的余数,即 x % y ,符号同 x ,如果 y =0 那么结果不可预料。
ceil ( x ) 对 x 向上取整,如 ceil ( 0.6 ) == 1 。
示例工程打包下载:http://pan.baidu.com/s/1skqBKmx