【Unity】ドカベンOPのロゴアニメーションをシェーダーで実装してみた

# ﾃｰﾃｰﾃｰﾃﾃﾃﾃｯﾃﾃｰ

ｶｧｧｧﾝ!!!
ﾜｧｧｧｧ-----!!

![title.gif](https://qiita-image-store.s3.amazonaws.com/0/80207/c3901cb7-47df-cb5b-90df-a789dcfdce54.gif)


ﾃｰﾃｰﾃｰﾃﾃﾃﾃｯﾃﾃｰ

[こちらの記事](https://qiita.com/trkbt10/items/e451a9d90b90e7bb551f)に触発され、ドカベンOPのロゴアニメーションをUnityの**シェーダー**で実装してみたので内容をメモ。

※Unity2017.2.0f3で実装





# 実装について

先ずはシェーダーの肝となる処理を下記に記載します。

- ※なお、今回作成したシェーダーについてはUnity2017.2.0f3に含まれる"Sprites/Default"をベースにして実装した物となりますが、以下の処理を頂点シェーダーに組み込むことで他のシェーダーにも動きを適用できるかと思われます。
- ※シェーダーコード全体についてはGitHubにアップしております。
    - [mao-test-h/Dokaben-Sprite-Default.shader](https://gist.github.com/mao-test-h/e17b04b36832112b401f7ddd8deeb48e)

```text
    float4 _MainTex_TexelSize; 
    v2f vert (appdata_t IN)
    {
        //.......
        
        // コマ落ちアニメーション(※動き自体はほぼ目コピ)
        float Animation[16] = 
        {
            1,
            0.9333333333333333,
            0.8666666666666667,
            0.8,
            0.7333333333333333,
            0.6666666666666666,
            0.6,
            0.5333333333333333,
            0.4666666666666667,
            0.4,
            0.3333333333333333,
            0.26666666666666666,
            0.2,
            0.13333333333333333,
            0.06666666666666667,
            0
        };
        // _SinTime0~1に正規化→0~15(コマ数分)の範囲にスケールして要素数として扱う
        float normal = (_SinTime.w+1)/2;
        // X軸に0~90度回転
        float rot = Animation[round(normal*15)]*radians(90);

        // 回転行列
        float sinX = sin(rot);
        float cosX = cos(rot);
        float2x2 rotationMatrix = float2x2(cosX, -sinX, sinX, cosX);

        // 回転軸を下端にする為に先ずは原点の位置に下端が来るように移動→回転行列を掛けた後に元の位置に戻す。
        IN.vertex.y += ((_MainTex_TexelSize.w/100)/2);
        IN.vertex.yz = mul(rotationMatrix, IN.vertex.yz);
        IN.vertex.y -= ((_MainTex_TexelSize.w/100)/2);

        //.......
    }

```

ソース中にコメントを残しておりますが、やっている事を纏めると以下の様になります。

- コマ落ちアニメーションは0~1の範囲のテーブルを用意し、時間をindexとして値を取得して`radians(90)`と掛け合わせる事で再現。
    - ※`_SinTime`については「[ShaderLab built-in values](https://docs.unity3d.com/455/Documentation/Manual/SL-BuiltinValues.html)」を参照
- 回転について、回転軸を下端に設定するために先ずは原点の位置に下端が来るように移動→回転行列を掛ける→元の場所に戻すと言う手順で実装。





# オマケ

> // _SinTime0~1に正規化→0~15(コマ数分)の範囲にスケールして要素数として扱う
> float normal = (_SinTime.w+1)/2;
> // X軸に0~90度回転
> float rot = Animation[round(normal*15)]*radians(90);

上記の処理で扱っている値はいずれも0~1に正規化した値となっているので、こちらに時間以外の値を渡してやることで独自のアニメーションが実装可能です。

一つ例として挙げると、以下のアニメーションは`Animation[n]`の値では無く、PerlinNoiseの値を直接掛け合わせてランダムな動きを実現したものとなります。
※PerlinNoiseの値の取得周りを省いておりますが、実装としては予め用意したPerlinNoiseのTextureをVTFで参照してます。

> float rot = perlin_noise*radians(90);

![perlin.gif](https://qiita-image-store.s3.amazonaws.com/0/80207/f5c4cfb9-2585-8288-7b7f-550f6f616e65.gif)

※`normal`の値に入れることでコマ落ちを適用させつつランダムな動きを実現することも可能です。
→そんなに違いが無いようにも見えますが若干カクついてます。

> float normal = perlin_noise;
> float rot = Animation[round(normal*15)]*radians(90);

![perlin_2.gif](https://qiita-image-store.s3.amazonaws.com/0/80207/47c8fde7-39d7-43e1-5ca4-da83477c9866.gif)






# 参考/関連サイト

- [【Unity】Particle System (Shuriken)で回転シェーダーアニメーション](http://www.jonki.net/entry/20140205/1391612451)
    - ※回転の実装の際に参考にさせて頂きました。
- [ドカベンメーカー](http://arkw.net/data/dokaben/) 
    - ※ロゴの作成に利用させて頂きました。