序列帧动画在游戏开发中非常常见,比如:2D动画,序列帧特效等等。
老规矩,先上效果
贴图如下:
原理:
ID的增长方式:U方向是从左到右,V方向是 从下到上;
那么每个字的坐标怎么的出来呢 ?
例如:“师”的编号ID是多少?
师的编号/横向的总数= 15/6=2.5;
注意:程序计数是0开始计数,别算错了。
竖向ID为 即为 横向ID得出来的结果取整数部分 floor(2.5)=2;
横向ID: 整数ID减去 横向个数乘以纵向ID
横向ID: 15-6*2=3;
那么师的ID为(3,2);(YY:当前 状态是 还只是他在UV里面的横竖 方向上的ID,别搞混了 )
/*存储一下当前帧的ID; 注意这个ID的类型绝对不可能是fixed类型,
但是感觉在PC段又没有问题,想想为什么?
是因为PC端不管怎么申明类型都是以float执行的,而移动端就会改变成fixed类型,
此类型的数据范围是-2到+2之间*/
half _FpsID=0;
//对ID取模约束数值在0~最大图像之间。
_FpsID = _FpsID % (_UCount*_VCount);
//ID向下取整
_FpsID = floor(_FpsID);
// 纵横向ID = ID除以横向个数
half indexY = floor(_FpsID / _UCount);
把原始UV 切割;
//缩小UV,放大图像
fixed2 AnimUV = float2(i.uv.x / _UCount, i.uv.y / _VCount);
我们重新回来获取“从”的位置 坐标空间
坐标原理: (原始UV的U方向/U方向的个数,原始UV的V方向/V方向的个数)
结果即为: (1/6,1/3) = (0.1666,0.3333);
注意:坐标是从(0,0)开始的,也就是实际上整个“从”的实际坐标是:
U :(0~0.1666);
V:(0~0.333.);
往左继续增加坐标:
//横向ID与横向个数获取偏移值累加给基础位置
AnimUV.x += indexX / _UCount ;
“新”坐标空间即为:
AnimUV.x +=1/6
U方向结果:(0~0.1666)+0.1666 =(0.1666~0.3332)
同理 V方向坐标即为:
AnimUV.y +=1/3
但是咱们美术同学做图习惯是<写文章的方式写法,从做到右写,从上到下>
所以V方向坐标运算需要修改下:
//(由上向下播放 ) 如果纵向ID为0 总数-1 - 当前ID,ID越大,Y越小 。
AnimUV.y +=(_VCount-1 - indexY )/ _VCount;
这样新的V坐标结果即为:
AnimUV.y+=(3-1-1)/3
AnimUV.y+=0
V 方向结果为: (0~0.3333)+0= (0~0.3333)
完整代码如下:
Shader "Unlit/UV_FpsAnimation"
{
Properties
{
[NoScaleOffset]
_MainTex ("Texture", 2D) = "white" {}
_PlaySpeed("PlaySpeed",float) = 1//播放速度
_UCount("_UCount",float) = 1 //序列帧水平总数
_VCount("_VCount",float) = 1 //序列帧垂直总数
/* 这里是UnityUI面板得一个开关,通过变体_AUTOPLAY
去控制是否开启播放*/
[Toggle] _AUTOPLAY("AutoPlay",Float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
//变体得启用
#pragma shader_feature _AUTOPLAY_ON
struct appdata
{
half4 vertex : POSITION;
fixed2 uv : TEXCOORD0;
};
struct v2f
{
fixed2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
half4 vertex : SV_POSITION;
};
sampler2D _MainTex;
fixed _PlaySpeed;
fixed _UCount;
fixed _VCount;
/*存储一下当前帧的ID; 注意这个ID的类型绝对不可能是fixed类型,
但是感觉在PC段又没有问题,想想为什么?
是因为PC端不管怎么申明类型都是以float执行的,而移动端就会改变成fixed类型,
此类型的数据范围是-2到+2之间*/
half _FpsID=0;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//判断动画播放是否开启
#ifdef _AUTOPLAY_ON
//当前ID累加 ,流逝时间每秒乘以播放速度
_FpsID += _Time.y* _PlaySpeed;
#endif
//对ID取模约束数值在0~最大图像之间。
_FpsID = _FpsID % (_UCount*_VCount);
//ID向下取整
_FpsID = floor(_FpsID);
// 纵横向ID = ID除以横向个数
half indexY = floor(_FpsID / _UCount);
//横向ID = ID减去 横向个数乘以纵向ID
half indexX = _FpsID - _UCount * indexY;
//缩小UV,放大图像
fixed2 AnimUV = float2(i.uv.x / _UCount, i.uv.y / _VCount);
//横向ID与横向个数获取偏移值累加给基础位置
AnimUV.x += indexX / _UCount ;
/*同理竖向播放如下
AnimUV.y +=indexY / _YSum;*/
//(由上向下播放 ) 如果纵向ID为0 总数-1 - 当前ID,ID越大,Y越小 。
AnimUV.y +=(_VCount-1 - indexY )/ _VCount;
//用新UV显示贴图
fixed4 col = tex2D(_MainTex, AnimUV);
//透明剔除,硬裁剪,节约性能,当然特效类的火焰等可能需要半透明处理。
clip(col.a - 0.5);
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}