﻿Shader "UI/BitTeleport"
{
    Properties
    {
        //以下4つの変数は適切にImageの座標を調整するために必要
        [HideInInspector]_CanvasScreenHeight("CanvasScreenHeight", float) = 1000
        [HideInInspector]_PosY("PosY", float) = 0
        [HideInInspector]_ScaleY("ScaleY", float) = 1
        [HideInInspector]_ImageHeight("ImageHeight", float) = 100

        [Space(10)]
        [HideInInspector]_Roughness ("Roughness", Range(1, 200)) = 100 //欠けていく粒子の粗さ
        [HideInInspector]_Scattering ("Scattering", Range(1, 10)) = 2 //移動する粒子のバラつき具合
        [HideInInspector]_Distance ("Distance", Range(1, 20)) = 1 //テレポートの移動距離
        [HideInInspector]_TeleportPow ("TeleportPow", Range(0, 1)) = 0 //テレポートの進捗、1で完全にテレポート完了

        [Space(10)]
        [Toggle] 
        [HideInInspector]_UseMonoCol("UseMonoCol", float) = 1 //テレポートの途中で単一色に変化するかどうか
        [HideInInspector]_MonoCol("MonoCol", Color) =  (1.0, 1.0, 1.0, 1.0) //単一色の色
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" }
        Cull Off
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        CGINCLUDE
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        struct appdata
        {
            fixed2 uv : TEXCOORD0;
            fixed4 vertex : POSITION;
            fixed4 color : COLOR;
        };

        struct v2f
        {
            fixed2 uv : TEXCOORD0;
            fixed4 vertex : POSITION;
            fixed4 color : COLOR;
        };

        sampler2D _MainTex;
        //アタッチされたSpriteのサイズを取得(x=1.0/width, y=1.0/height, z=width, w=height)
        float4 _MainTex_TexelSize;

        fixed _CanvasScreenHeight;
        fixed _PosY;
        fixed _ScaleY;
        fixed _ImageHeight;

        float _Roughness;
        float _Scattering;
        fixed _Distance;
        fixed _TeleportPow;

        int _UseMonoCol;
        fixed4 _MonoCol;
        ENDCG

        Pass
        {
            CGPROGRAM

            v2f vert (appdata v)
            {
                v2f o;
                v.vertex.y = v.vertex.y  * _Distance;
                o.vertex = UnityObjectToClipPos(v.vertex);
    
                //画像のHeightを変更しつつ、画像の見た目上の移動は極力抑える処理
                fixed screenHeightRatio = _ScreenParams.y / _CanvasScreenHeight;
                fixed imageRatio =  _ImageHeight / _MainTex_TexelSize.w;
                fixed texelRatio = (_MainTex_TexelSize.w * imageRatio * _ScaleY) / _ScreenParams.y;
                o.vertex.y = o.vertex.y + texelRatio * (_Distance - 1) * screenHeightRatio;
    
                //対象画像がスクリーン座標の中央から離れるほど画像の移動距離がずれるので、その修正
                o.vertex.y = o.vertex.y - _PosY * (_Distance - 1);
    
                o.uv = v.uv;
                o.color = v.color;
                return o;
            }

            //1次元 疑似ランダム
            float random(fixed2 st)
            {
                return frac(sin(dot(st.xy, fixed2(12.9898, 78.233))) * 43758.5453);
            }

            //指定ピクセルをmoveDotYの値だけ上に移動させる
            fixed2 moveUv(fixed2 uv, fixed moveDotY)
            {
                //頂点シェーダーの時点で画像をy軸に引き伸ばしているが、見た目自体は変えない(中央に圧縮)するための処理
                fixed y = uv.y * _Distance;
                //_TeleportPowの値に応じて少しだけ見た目のy軸を引き伸ばす
                fixed baseTelepoSt = 1 + _TeleportPow * (_Distance * 1) * 0.25;
                y = y / baseTelepoSt;
                //ピクセルを上にずらす
                y = y + moveDotY;

                fixed2 fixUv = fixed2(uv.x, y);
                return fixUv;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //アタッチされたSpriteの縦横比をratioに保存
                fixed ratio = _MainTex_TexelSize.z / _MainTex_TexelSize.w;
                //_Roughnessの入力値を実際に使う値まで細かくする
                fixed fixRough = _Roughness * 0.001f;

                //対象ピクセルのx座標とy座標を保存、ただしfixRoughの値に応じて座標の取得が大雑把になる
                //またy座標にはratioを追加で掛けることで、座標を大雑把にした時の値に補正を乗せて欠けるドットを正方形に修正する
                fixed roughX = floor(i.uv.x / fixRough) * fixRough;
                fixed roughY = floor(i.uv.y * _Distance  / (fixRough * ratio)) * (fixRough * ratio);
                fixed2 roughUv = fixed2(roughX, roughY);

                //ランダムノイズにより、指定座標に対し0~1のランダムな値が返ってくる
                fixed rdm = random(roughUv);
                //ドットの移動値を取得、マイナスになるほど上に移動する
                fixed moveDotY = min(0, rdm - _TeleportPow * 1.5) * _Distance * _Scattering;

                //ピクセルを_TeleportPowに準じて上に移動
                fixed2 fixUv = moveUv(i.uv, moveDotY);
                fixed4 col = tex2D(_MainTex, fixUv);

                //_TeleportPowが上昇するにつれて画像を単一色に変更
                fixed fixPow = saturate(_TeleportPow * 4);
                fixed3 monoCol = fixPow * _MonoCol + (1 - fixPow) * col;
                col.rgb = _UseMonoCol * monoCol + (1 - _UseMonoCol) * col.rgb;

                col *= i.color;
                return col;
            }
            ENDCG
        }
    }
}