3D textureを使ったブレンドアニメーション

## 3D texture ##
サイバーエージェントさんの[Unity用エフェクトシェーダ](https://developers.cyberagent.co.jp/blog/archives/35148/)についての記事を読んで、Unity上で３Dテクスチャが簡単に作成できるようになっているのを知りました。
これはスプライトアニメーションに使えそうです。さっそく実装してみました。
<iframe width="560" height="315" src="https://www.youtube.com/embed/2KR65yXOShE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

左が９パターンにアニメーション（ブレンドあり）、中央がモデルアニメーション、右が通常のスプライトアニメーションです。
アニメーションパターンが多い場合はそれほど変わり映えしませんし、少ない場合でも変にブレると気持ち悪いということもあると思いますが、使い方によっては良い効果が得られるのではないかと思います。

## 作成方法-Flipbook Animation ##
まずはアニメーションパターンのテクスチャを作成します。
Unityではテクスチャシートアニメーションや Flipbook Animation などと呼ばれています。
左上から右下にアニメーションする一連のパターンを並べておきます。
![test3x3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/c8edf72d-6bb6-fea1-144a-999c1ca5cf89.png)
これをUnityに読み込むとInspectorにImport Settingsが現れるので、
Texture Shapeを3Dにし、行および列の数を３にします。
またGenerate Mipmapsのチェックを外しておきます。
これを外しておかないと、スプライトを遠くに表示した際に複数のコマがブレンドされて表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/22fd5bc1-2401-816c-731e-bd77901297aa.png)
Apply するとテクスチャシートが３Dテクスチャ化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/1d25854c-0668-a59f-8cec-8141357f3c96.png)
ここでSliceのタブを選択し、Zの値を変更するとアニメーションを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/1c4dcff6-5cdc-f563-7009-020f2bbe33c8.png)

## 表示方法-Shader ##
続いて、３Dテクスチャに対応したシェーダーを用意します。
基本的には普通のテクスチャを表示するのと同じですが、UVに.z値があります。
また、通常はOffset.Z=0がパターンの中央値なのですが、指定しやすいように0がパターンの先頭になるようにしておきます。

```
Shader "Unlit/VolumeTransparentForAnim"
{
  Properties
  {
    _Volume("Volume", 3D) = "" {}
    _Scale ("Scale (x, y, z, and w=mul)", vector) = (1,1,1,1)
	_Offset ("Offset (x, y, z, and w=div)", vector) = (0,0,0,1)
  }

  CGINCLUDE
  #include "UnityCG.cginc"

  struct appdata
  {
    half4 vertex : POSITION;
  };

  struct v2f
  {
    half4 vertex : SV_POSITION;
    half3 uv : TEXCOORD0;
  };

  sampler3D _Volume;
  half4 _Scale;
  half4 _Offset;

  v2f vert(appdata v)
  {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    half4 sclVec = v.vertex;
    sclVec.xyz /= _Scale.xyz*_Scale.w;
    half4 ofs = _Offset+half4(0,0,(_Offset.w-1)/2+1,0);
    o.uv = sclVec.xyz + (ofs.xyz / ofs.w) + 0.5;
    return o;
  }

  fixed4 frag(v2f i) : SV_Target
  {
    return tex3D(_Volume, i.uv);
  }
  ENDCG

  SubShader
  {
    Tags 
    { 
      "RenderType" = "Transparent" //"Opaque" // 
	  "Queue" = "Transparent" // "Geometry" // 
    }

    Pass
    {
	  Blend SrcAlpha OneMinusSrcAlpha
      ColorMask RGB
	  ZWrite Off
      Cull Back
      Offset 0,0
      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      ENDCG
    }
  }
}
```

上記shaderを使用したMaterialを作成し、Vokumeに3Dテクスチャを、Offset.wに分割数の9を入力します。
プレビューモデルをQuadにしておいて、Offset.Zにパターン番号を入れるとそのパターンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/8422ffd1-5205-ab11-a0e9-3024c09363da.png)
Z=1.5を入力するとパターン1と2がブレンドされて表示されるのがわかると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/7b22cc7b-3918-1c4d-bb37-1d1f45db226f.png)

## 使用方法-Script ##
スクリプト上から利用する場合は、マテリアルに対して```SetVector("_Offset", vec);```のようにOffsetを渡せばOKです。
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshRenderer))]
public class Tex3DAnim : MonoBehaviour
{
    [SerializeField] float m_DivNum = 9f;
    [SerializeField, Range(0.1f, 32f)] float m_speedGain = 16f;
    [SerializeField] bool m_isStep = false;
    Material m_mat;
    Vector4 m_vec;
    float m_ptn;

    void Start()
    {
        MeshRenderer mr = GetComponent<MeshRenderer>();
        m_mat = mr.material;
        m_vec = new Vector4(0, 0, 0, m_DivNum);
    }

    void Update()
    {
        m_ptn += Time.deltaTime * m_speedGain;
        m_vec.z = (m_isStep? Mathf.Floor(m_ptn) : m_ptn);
        m_mat.SetVector("_Offset", m_vec);
    }
}

```
## おまけ-Appendix ##
比較用に4x4のテクスチャシートも置いておきます。![test4x4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/4aa5c946-a31e-ffbc-bcf4-f7a6779b5a71.png)