序列帧动画
Shader "Chan/SqueueAction"{
Properties
{
_Color("Main Color",Color) = (1,1,1,1)
_MainTex("Main Tex",2D) = "white"{}
_HorizontalAmount("Horizontal Amount",Float) = 8
_VerticalAmount("Vertical Amount",Float) = 8
_Speed("Action Speed",Range(0,40)) = 20
}
SubShader
{
//动画帧一般包含透明通道,因此设置为渲染队列设置为 透明 = Transparent
//透明度操作必有的三个标签
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass
{
Tags{"LightMode" = "Forwardbase"}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
float _HorizontalAmount;
float _VerticalAmount;
float _Speed;
struct a2v
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}
fixed4 frag(v2f i):SV_Target
{
float2 cellUV = float2(i.uv.x /_HorizontalAmount,i.uv.y/_VerticalAmount);
//位移
float deltaX = 1 / _HorizontalAmount;
float deltaY = 1 / _VerticalAmount;
int index = _Time * _Speed;
int col = fmod(index, _HorizontalAmount);
int row = index / _HorizontalAmount;
// 顶点(0,0)到(1,1)区域内经过映射过的UV坐标 + 位移坐标
cellUV.x += col * deltaX;
cellUV.y += row * deltaY;
fixed4 c = tex2D(_MainTex,cellUV);
c.rgb *= _Color;
return c;
}
ENDCG
}
}
}
原理:随着时间增加,每隔一段时间间隔,改变UV的坐标,进而改变纹理的采样,达成帧动画效果。
具体操作是将获取到的顶点UV(0,0)到(1,1)的区间的UV坐标区域,根据时间变化映射到相应的纹理相应的UV区域,然后根据映射后的UV区域,采样得到纹素,进而显示屏幕像素。
half2 uv = float2(i.uv.x /_HorizontalAmount, i.uv.y / _VerticalAmount);
将原本(0,0)到(1,1)UV区域,根据帧动画纹理的行列数划分成 _HorizontalAmount * _VerticalAmount个(1/_HorizontalAmount,1/_VerticalAmount)大小的区域。第一个区域如下:
// 顶点(0,0)到(1,1)区域内经过映射过的UV坐标 + 位移坐标。这种写法,纹理Wrap Mode != Repeat也没问题。因为UV的xy分量不会超过1.0;
cellUV.x += col * deltaX;
cellUV.y += row * deltaY;
</