动画效果往往都是把时间添加到一些变量的计算中,以便在时间变化时画面也可以随之变化。Unity Shader 提供了一系列关于时间的内置变量来允许我们方便地在Shader中访问允许时间,实现各种动画效果。下表给出了这些内置的时间变量。
序列帧动画的原理非常简单,它像放电影一样,依次播放一系列关键帧图像,当播放速度达到一定数值时,看起来就是一个连续的动画。它的有点在于灵活性很强,我们不需要进行任何物理计算就可以得到非常细腻的动画效果。而它的缺点也很明显,由于序列帧中每张关键帧图像都不一样,因此,要制作一张出色的序列帧纹理所需要的美术工程量比较大。
Shader "MyShader/ImageSequenceAnimation"
{
Properties
{
_Color("Color Tint",Color) = (1,1,1,1)
_MainTex("Image Sequence", 2D) = "white" {}
_HorizontalAmount("Horizontal Amount",Float) = 8
_VerticalAmount("Vertical Amount",Float) = 8
_Speed("Speed",Range(1,150)) = 30
}
SubShader
{
Tags{"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _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
{
float time = floor(_Time.y * _Speed);
float row = floor(time / _HorizontalAmount);
float column = time - row * _HorizontalAmount;
--
//half2 uv = float2(i.uv.x / _HorizontalAmount, i.uv.y / _VerticalAmount);
//uv.x += column / _HorizontalAmount;
//uv.y -= row / _VerticalAmount;
--
//--
half2 uv = i.uv + half2(column, -row);
uv.x /= _HorizontalAmount;
uv.y /= _VerticalAmount;
//--
fixed4 c = tex2D(_MainTex, uv);
c.rgb *= _Color;
return c;
}
ENDCG
}
}
Fallback "Transparent/VertexLit"
}
_MainTex 就是包含了所有关键帧图像的纹理。_HorizontalAmount 和 _VerticalAmount 分别代表了该图像在水平和竖直方向包含的关键帧图像的个数。而 _Speed 属性用于控制序列帧动画的播放速度。
1、我们首先用_Time.y和速度属性_Speed相乘得到模拟的时间。
2、然后我们用time除以_HorizontalAmount的结果值作为当前的行索引,除法结果的余数则是列索引。
3、接下来,我们根据行索引和列索引来构建真正的采样坐标。由于序列帧图像包含了很多张关键帧图像,这意味着采样坐标需要映射到关键帧图像的坐标范围。
4、我们可以把原纹理坐标i.uv按行数和列数进行等分,得到每个子图像的纹理坐标范围。
5、映射到对应的行列数后,再对纹理坐标进行偏移。
注意:Unity的纹理坐标竖直方向的顺序和序列帧纹理中竖直方向上的顺序是相反的。
bomp
效果
参考 我买的 unity shader 入门精要
策划只要从头到尾播放一遍,代码改改就行,行列我们在外面赋值(注释掉shader里面的)
using UnityEngine;
using UnityEngine.UI;
public class GoldEffectContrl : MonoBehaviour
{
private Material material;
private int row = 1;
private int column = 0;
private int m_Row = 5;
private float timer = 0;
private float timer1;
private bool isShowing = false;
public float speed = 8.5f;
private float speed1;
private int columnIndex = 0;
private int lastrow = 1;
private int lastcolumn = 0;
public void Init()
{
material = GetComponent().material;
material.SetFloat("row", row);
material.SetFloat("column", column);
}
public void ShowEffect()
{
timer = 1;
timer1 = 0;
row = 1;
lastrow = 1;
column = 0;
lastcolumn = 0;
isShowing = true;
columnIndex = 0;
speed1 = speed * m_Row;
}
private void Update()
{
if (isShowing)
{
timer += Time.deltaTime * speed;
timer1 += Time.deltaTime * speed1;
row = Mathf.FloorToInt(timer);
if (row >= m_Row + 1)
{
isShowing = false;
row = m_Row;
material.SetFloat("row", m_Row);
material.SetFloat("column", m_Row - 1);
return;
}
if (lastrow != row)
{
lastrow = row;
material.SetFloat("row", row);
}
column = Mathf.FloorToInt(timer1);
if (timer1 >= m_Row)
{
columnIndex++;
if (columnIndex == m_Row)
{
column = m_Row - 1;
}
else
{
column = 0;
timer1 = 0;
}
}
if (lastcolumn != column)
{
lastcolumn = column;
material.SetFloat("column", column);
}
}
}
}