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
}
}
}