US3S9L2——序列帧动画
US3S9L2——序列帧动画
分析利用纹理坐标制作序列帧动画的原理
Shader实现序列帧动画的关键点是:UV 坐标原点为左下角,而序列帧图集 “原点” 为左上角
我们需要注意采样开始位置的转换
以下图为例,制作一个序列帧爆炸动画(不需要使用 Unity 的 Sprite Editor 去分割图集):
-
关键点
- UV 坐标范围 0~1,原点为图片左下角
- 图集序列帧动画播放顺序为从左到右,从上到下
-
分析问题
- 如何得到当前应该播放哪一帧动画?
- 如何将采样规则从 0~1 修改为在指定范围内采样?
-
问题解决思路
-
用内置时间参数 _Time.y 参与计算得到具体哪一帧
时间是不停增长的数值,用它对总帧数取余,便可以循环获取到当前帧数
-
利用时间得到当前应该绘制哪一帧后
我们只需要确认从当前小图片中,采样开始位置,采样范围即可,
采样开始位置,可以利用当前帧和行列一起计算,采样范围可以将 0~1 范围 缩放转换到 小图范围内
-
我们按照顺序,从左到右,从上到下的选定不同小图的范围,改变 UV 坐标和采样范围,依次给小图采样
每过一帧就切换到下一个小图采样,通过在大图内依次采样不同的小图的方式,实现序列帧动画效果
用 Shader 实现序列帧动画
-
新建 Shader,删除无用代码
-
声明属性,进行属性映射
包括主纹理、图集行列、序列帧切换速度
c1
2
3
4
5
6
7Properties
{
_MainTex ("Texture", 2D) = "white" {} // 序列帧图集纹理
_Rows("Rows", int) = 8 // 图集的行数
_Columns("Columns", int) = 8 // 图集的列数
_Speed("Speed", float) = 1 // 切换动画速度变量
} -
设置透明 Shader 相关内容
往往这种序列帧图集图片都会有透明区域,因此需要使用透明混合相关的设置,具体详见:US3S3L5——透明度混合
设置渲染标签的渲染类型为透明,队列为透明,并忽略投影机
关闭深度写入,开启混合,需要使用SrcAlpha OneMinusSrcAlpha
混合c1
2
3
4
5
6
7
8
9
10
11
12
13SubShader
{
Tags { "RenderType"="Transparent" "IgnoreProjector"="True" "Queue"="Transparent"}
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
//...
ENDCG
} -
结构体
只需要顶点坐标和纹理坐标
c1
2
3
4
5
6
7
8
9
10
11struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Rows;
float _Columns;
float _Speed; -
顶点着色器
只需要进行坐标转换和纹理坐标赋值
c1
2
3
4
5
6
7v2f vert (appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
} -
片元着色器
- 利用时间计算帧数
- 利用帧数计算当前 uv 采样起始位置(得到小图片 uv 起始位置,注意起始位置要在小图的左下角)
- 计算 uv 缩放比例(将 转换到 )
- 进行 uv 偏移计算(在小图片格子中采样,需要先缩放后偏移)
- 采样
c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17fixed4 frag (v2f i) : SV_Target
{
// 利用时间计算当前播放帧数索引
float frameIndex = floor(_Time.y * _Speed) % (_Rows * _Columns);
// 计算UV起始坐标
float2 frameUV = float2(
// 计算U轴起始位置,其中 / _Columns 是为了让U轴起始位置处于 0~1
frameIndex % _Columns / _Columns,
// 计算V轴起始位置,其中+1是为了让起始位置位于格子左下角,/ _Rows是为了让V轴起始位置处于 0~1,
// (floor(frameIndex / _Columns) + 1) / _Rows 得的是左边上段,因为采样是从左下角开始的,因此需要1-..
1 - (floor(frameIndex / _Columns) + 1) / _Rows);
// 计算uv缩放比例
float2 size = float2(1 / _Columns, 1 / _Rows);
float2 uv = i.uv * size + frameUV; // 先缩放,是采样范围缩小到0 ~ 1/8,然后加上起始位置
return tex2D(_MainTex, uv);
}
显示效果(播放速度 20):
完整 Shader 代码如下:
c
1 | Shader "TeachShader/Lesson92_SequentialFrameAnimation" |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 文KRIFE齐的博客!