概要
Unity上でSheet Animationを使ったシェーダーの例です。
Sheet Animationを使うことで板ポリ1枚とテクスチャ1枚でアニメーションを表現することができます。
連番アニメーションはAnimatorを用いることで実装することもできますが、Shaderを使った方が使用するコンポーネントも少なく軽量です。
また、アニメーションの際にMaterialを変化させないので、MaterialのInstance化を防ぎバッチを効かせることができます。
Unity Sheet Animation Shader Graph版
ソースコード
Shader "Unlit/SheetAnimation"
{
Properties
{
[NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
_MainColor("Main Color",Color) = (1,1,1,1)
_Row("Row",int) = 4
_Column("Column",int) = 4
_Speed("Speed",float) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _MainColor;
uint _Row;
uint _Column;
float _Speed;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//全てのコマ数を計算
uint cells = _Row * _Column;
//時間にSpeedを掛けて小数点以下だけを返すことで0~1を生成
fixed process = frac(_Time.y * _Speed);
//index=どのコマを指しているか
uint index = process * cells;
//1コマ当たりのUVサイズを計算
float invRow = 1.0 / (float)_Row;
float invColumn = 1.0 / (float)_Column;
float2 tiling = float2(invRow,invColumn);
//indexからどのコマに当たるかを計算する
half x = (index % _Row) * invRow;
//画像の左上からコマが始まるのでひっくり返している
half y = 1 - (((index / _Row) +1) * invColumn);
float2 offset = float2(x,y);
//テクスチャのオフセットを適用する
fixed4 col = tex2D(_MainTex, (i.uv * tiling) + offset);
//色を変えられるようにする
col *= _MainColor;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
解説
-
Unlit Shaderから作成を開始しています
- 今はOpaqueになってますが、
Blend Mode
を変えることで半透明シェーダーとして使うこともできます
- 今はOpaqueになってますが、
-
_Time.y
の時間で変化する変数を用いて、テクスチャの表示する位置を変化させています -
メインのテクスチャでTilingやOffsetを設定できないよう
[NoScaleOffset]
の属性を付与しています- Sheet Animationの場合はTexture全体を使うのが一般的なので、TilingやOffsetを設定する必要は無いはず
-
Sheet Animationのコマ割りの順番は、下の画像のように左上から右下に進むことを想定しています
- もし順番が違う場合はoffsetを計算する部分のコードを書き換える必要が出てきます
- 例えば左下からスタートする場合は下記のようになります
half y = ((index / _Row) +1) * invColumn;