-->



Shader "UI/FTLDrive"
{
Properties
{
[HideInInspector]_MainTex("-",2D)="white"{}
[HideInInspector] _EasePow ("EasePow", Range(0, 10)) = 10
_Transition("Transition", Range(0, 1)) = 0
[Space(10)]
_Line1Color("Line1Color", Color) = (1,1,1,1)
_Line2Color("Line2Color", Color) = (0,0,0,1)
_FadeOutColor("FadeOutColor", Color) = (1,1,1,1)
_RippleColor("RippleColor", Color) = (0,0,0,1)
[Space(10)]
_CompDistortTiming("CompDistortTiming", Range(0, 1)) = 0.8
_StartScaleInTiming("StartScaleInTiming", Range(0, 1)) = 0.5
_CompLine1Timing("CompLine1Timing", Range(0, 1)) = 0.7
_StartFadeOutTiming("StartFadeOutTiming", Range(0, 1)) = 0.8
_CompFadeOutTiming("CompFadeOutTiming", Range(0, 1)) = 0.9
_RippleTiming("RippleTiming", Range(0, 1)) = 0.7
_StartLine2Timing("StartLine2Timing", Range(0, 1)) = 0.7
[Space(10)]
_Line1NoiseScale("Line1NoiseScale", Range(1, 500)) = 100
_Line2NoiseScale("Line2NoiseScale", Range(1, 500)) = 100
_RippleLength("RippleLength", Range(0, 5)) = 2
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderType"="Transparent"
}
Cull Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGINCLUDE
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _GrabTexture;
fixed _EasePow;
fixed _Transition;
fixed4 _Line1Color;
fixed4 _Line2Color;
fixed4 _FadeOutColor;
fixed4 _RippleColor;
fixed _CompDistortTiming;
fixed _StartScaleInTiming;
fixed _CompLine1Timing;
fixed _StartFadeOutTiming;
fixed _CompFadeOutTiming;
fixed _RippleTiming;
fixed _StartLine2Timing;
fixed _Line1NoiseScale;
fixed _Line2NoiseScale;
fixed _RippleLength;
//radianの最大値、degreeで言うと360度のこと
static const float PI2 = 3.14159 * 2;
struct appdata
{
fixed4 vertex : POSITION;
fixed4 uv : TEXCOORD0;
};
struct v2f
{
fixed4 vertex : SV_POSITION;
fixed2 uv : TEXCOORD0;
};
v2f vert(appdata i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.uv = ComputeGrabScreenPos(o.vertex);
return o;
}
//引数に渡された対象座標の角度を0~1の範囲に圧縮して返す。
//反時計周りに徐々に値が大きくなる。第二Passと第五Passで使用する。
fixed2 getUvAngle(fixed2 uv)
{
//uv座標を、画面中央を原点として(0,0)>(1,1)から(-1,-1)>(1,1)の範囲に修正する
fixed2 fixUv = uv * 2 - 1;
//修正したuv座標の角度をradian値で取得
fixed angle = atan2(fixUv.y, fixUv.x);
//0~PI*2の値を0~1の範囲に圧縮
return angle / PI2;
}
//Unity公式が用意してる4つのノイズ関数。
//https://docs.unity3d.com/ja/Packages/com.unity.shadergraph@10.0/manual/Simple-Noise-Node.html
inline float unity_noise_randomValue (float2 uv)
{
return frac(sin(dot(uv, float2(12.9898, 78.233)))*43758.5453);
}
inline float unity_noise_interpolate (float a, float b, float t)
{
return (1.0-t)*a + (t*b);
}
inline float unity_valueNoise (float2 uv)
{
float2 i = floor(uv);
float2 f = frac(uv);
f = f * f * (3.0 - 2.0 * f);
uv = abs(frac(uv) - 0.5);
float2 c0 = i + float2(0.0, 0.0);
float2 c1 = i + float2(1.0, 0.0);
float2 c2 = i + float2(0.0, 1.0);
float2 c3 = i + float2(1.0, 1.0);
float r0 = unity_noise_randomValue(c0);
float r1 = unity_noise_randomValue(c1);
float r2 = unity_noise_randomValue(c2);
float r3 = unity_noise_randomValue(c3);
float bottomOfGrid = unity_noise_interpolate(r0, r1, f.x);
float topOfGrid = unity_noise_interpolate(r2, r3, f.x);
float t = unity_noise_interpolate(bottomOfGrid, topOfGrid, f.y);
return t;
}
void Unity_SimpleNoise_float(float2 UV, float Scale, out float Out)
{
float t = 0.0;
float freq = pow(2.0, float(0));
float amp = pow(0.5, float(3-0));
t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
freq = pow(2.0, float(1));
amp = pow(0.5, float(3-1));
t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
freq = pow(2.0, float(2));
amp = pow(0.5, float(3-2));
t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
Out = t;
}
ENDCG
//第一Passの前に画面全体をキャプチャーする。
GrabPass{}
//第一Pass、画面全体を糸巻歪曲収差で歪ませて、Trasnsitionの後半ではズームアップする
Pass
{
CGPROGRAM
fixed2 getIsUnderHalf(v2f i)
{
//x軸が0.5より小さければ1を代入
fixed isUnderHalfX = step(i.uv.x, 0.5);
//y軸が0.5より小さければ1を代入
fixed isUnderHalfY = step(i.uv.y, 0.5);
return fixed2(isUnderHalfX, isUnderHalfY);
}
fixed2 getFarFromSafe(v2f i)
{
fixed fixRange = lerp(0, 1, saturate(_Transition / _CompDistortTiming + 0.0001));
fixed safeRange = 1 - fixRange;
fixed farFromSafeX = abs(0.5 - i.uv.x) - (safeRange / 2);
fixed farFromSafeY = abs(0.5 - i.uv.y) - (safeRange / 2);
return fixed2(farFromSafeX, farFromSafeY);
}
fixed2 getFarFromCenter(v2f i)
{
fixed farFromCenterX = abs(0.5 - i.uv.x);
fixed farFromCenterY = abs(0.5 - i.uv.y);
return fixed2(farFromCenterX, farFromCenterY);
}
fixed2 getMainDist(fixed2 farFromSafe)
{
//InQuadのEaseでfarFromSafeが大きい程指数関数的に座標がずれるようにする
fixed quadX = farFromSafe.x * (farFromSafe.x - 2);
fixed quadY = farFromSafe.y * (farFromSafe.y - 2);
//指数関数の伸びが強すぎるのでfixEaseで抑える
//このシェーダーではHideInspectorで隠され_EasePowの値は10で固定なので、実質fixEaseは1.9になる。
fixed fixEase = 11.9 - _EasePow;
fixed mainDistX = quadX * quadX / fixEase;
fixed mainDistY = quadY * quadY / fixEase;
return fixed2(mainDistX, mainDistY);
}
fixed2 getSubDist(fixed2 farFromCenter, fixed2 mainDist)
{
fixed subDistX = farFromCenter.x * mainDist.y;
fixed subDistY = farFromCenter.y * mainDist.x;
return fixed2(subDistX, subDistY);
}
fixed2 getMainReduce(fixed2 isUnderHalf, fixed2 mainDist)
{
fixed mainReduceX = (isUnderHalf.x * mainDist.x) + ((1 - isUnderHalf.x) * -1 * (mainDist.x));
fixed mainReduceY = (isUnderHalf.y * mainDist.y) + ((1 - isUnderHalf.y) * -1 * (mainDist.y));
return fixed2(mainReduceX, mainReduceY);
}
fixed2 getSubReduce(fixed2 isUnderHalf, fixed2 subDist)
{
fixed subReduceX = (isUnderHalf.x * subDist.x) + ((1 - isUnderHalf.x) * -1 * (subDist.x));
fixed subReduceY = (isUnderHalf.y * subDist.y) + ((1 - isUnderHalf.y) * -1 * (subDist.y));
return fixed2(subReduceX, subReduceY);
}
fixed2 getUseDist(fixed2 farFromSafe)
{
//x軸が歪み対象エリア内かどうか
fixed useDistX = step(0, farFromSafe.x);
//y軸が歪み対象エリア内かどうか
fixed useDistY = step(0, farFromSafe.y);
return fixed2(useDistX, useDistY);
}
fixed4 frag(v2f i) : SV_Target
{
//対象のy軸とx軸座標が中心点を超えてるかどうかを習得
fixed2 isUnderHalf = getIsUnderHalf(i);
//非歪みエリアから外側にx軸、y軸がどれだけ離れてるかを取得
fixed2 farFromSafe = getFarFromSafe(i);
//中心からx軸、y軸がどれだけ離れてるかを取得
fixed2 farFromCenter = getFarFromCenter(i);
//メインの歪みの基本値を取得
fixed2 mainDist = getMainDist(farFromSafe);
//サブの歪みの基本値を取得
fixed2 subDist = getSubDist(farFromCenter, mainDist);
//メインの座標の減退値を取得
fixed2 mainReduce = getMainReduce(isUnderHalf, mainDist);
//サブの座標の減退値を取得
fixed2 subReduce = getSubReduce(isUnderHalf, subDist);
//対象のx軸、y軸が歪み対象エリア内かどうか
fixed2 useDist = getUseDist(farFromSafe);
//元のuv座標を歪ませて糸巻歪曲収差っぽくする
i.uv.x = i.uv.x + useDist.x * mainReduce.x + useDist.y * subReduce.x;
i.uv.y = i.uv.y + useDist.y * mainReduce.y + useDist.x * subReduce.y;
fixed scalingBase = 4.7;
fixed scaleFix = 5;
//拡大演出が開始されるタイミングを算出
fixed multi = 1 / _StartScaleInTiming;
fixed scaleTransition = saturate(_Transition - _StartScaleInTiming) * multi;
//画面の拡大値を算出。
scaleTransition *= scaleTransition;
fixed scaleInNum = 1 - (scaleTransition * scalingBase / scaleFix);
//画面拡大に伴って中央の座標がずれるので、座標の中央値を算出
fixed scalingSub = scalingBase / 2;
fixed2 scaleShiftPos = fixed2(scaleTransition * scalingSub / scaleFix, scaleTransition * scalingSub / scaleFix);
fixed4 col = tex2D(_GrabTexture, i.uv * scaleInNum + scaleShiftPos);
return col;
}
ENDCG
}
//第二Pass、1つ目の集中線を作る
Pass
{
CGPROGRAM
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = _Line1Color;
//半時計周りに値を大きくなるグラデーションを取得
fixed deg = getUvAngle(i.uv);
float resultLine = 0;
//エッジ部分にグラデーションがかかった綺麗な集中線を取得
Unity_SimpleNoise_float(float2(deg, deg), _Line1NoiseScale, resultLine);
//sin関数で集中線を細かくする。_Transitionの値が大きいほど、どんどん細かくなる
fixed lineTransition = lerp(0, 1, saturate(_Transition / _CompLine1Timing + 0.0001));
resultLine= sin(resultLine * lineTransition * 100);
col.a *= resultLine;
return col;
}
ENDCG
}
//第三Pass、画面全体を_FadeOutColorで塗りつぶす
Pass
{
CGPROGRAM
fixed4 frag (v2f i) : SV_Target
{
//後半の画面全体を埋め尽くす色をalpha0で取得
fixed4 col = fixed4(_FadeOutColor.r, _FadeOutColor.g, _FadeOutColor.b, 0);
fixed fadeOutDiff = _CompFadeOutTiming - _StartFadeOutTiming;
fixed multi = 1 / fadeOutDiff;
//_Transitionが_StartFadeOutTimingまで進んだ瞬間から_CompFadeOutTimingの間までにFadeOutを完了させる
fixed alpha = saturate(saturate(_Transition - _StartFadeOutTiming) * multi);
col.a = alpha * _FadeOutColor.a;
return col;
}
ENDCG
}
//第四Pass、リップル演出を走らせる
Pass
{
CGPROGRAM
//リップルが発生するTransitionの値を渡して、リップルのカラー値を取得
fixed4 getRippleColor(fixed length, fixed startTransition)
{
fixed multi = 1 / (1 - startTransition);
fixed rippleTransiton = saturate(_Transition - startTransition) * multi;
fixed rippleStartPos = rippleTransiton;
fixed rippleEndPos = (rippleStartPos + (_RippleLength * rippleTransiton));
fixed isRipple = step(length, rippleEndPos) * step(rippleStartPos, length);
//ドーナツ状の波紋を作る
fixed4 col = isRipple * _RippleColor;
//中心に近づくほどアルファが薄くなるグラデーションをかける
col.a *= isRipple * (length - rippleStartPos) / (rippleEndPos - rippleStartPos);
return col;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = _RippleColor;
//uv座標を、画面中央を原点として(0,0)>(1,1)から(-1,-1)>(1,1)の範囲に修正する
fixed2 fixUv = i.uv * 2 - 1;
fixed len = length(fixUv) / 1.5;
//ドーナッツ状のリップルを取得
col = getRippleColor(len, _RippleTiming);
return col;
}
ENDCG
}
//第五Pass、2つ目の集中線を作る
Pass
{
CGPROGRAM
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = _Line2Color;
//半時計周りに値を大きくなるグラデーションを取得
fixed deg = getUvAngle(i.uv);
float resultLine = 0;
//エッジ部分にグラデーションがかかった綺麗な集中線を取得
Unity_SimpleNoise_float(float2(deg, deg), _Line2NoiseScale, resultLine);
//集中線が発生するタイミングを指定
fixed fixTransition = saturate(_Transition - _StartLine2Timing);
//sin関数で集中線を細かくする。_Transitionの値が大きいほど、どんどん細かくなる
resultLine= sin(resultLine * fixTransition * 100);
col.a = resultLine;
fixed multi = 1 / (1 - _StartLine2Timing + 0.0001);
fixed rate = fixTransition * multi;
//Easeをかけて後半にかけて急速に1に近づくようにする
rate = rate * rate;
//Transition後半にかけて段々と集中線を消す
col.a -= lerp(0, 1, rate);
return col;
}
ENDCG
}
}
}
