UnityでuGUI用ドット欠けシェーダー。ピクセルが虫食いで欠けていく演出。
(Dead Pixel Shader for Unity uGUI to progressively missing pixels)
関連ページ
参考URL
よくSFCのFFとかでは、敵を倒した際に敵の画像のピクセルが徐々に欠けていき最終的に消滅する演出があった。
あれを作りたいと思って結構楽に作れたので共有。
なお今回
こちらの記事
を大いに参考にしている。
このシェーダーの応用で、
Dissolve Shader
も作れたのでそちらも併せてどうぞ。
ドット欠けシェーダー、コード全文
下がドット欠けシェーダーのサンプル動画。
以下コード全文。uGUI Imageへの反映方法は
こちらの記事
参照。
Shader
"UI/DeadPixel"
{
Properties
{
_VanishPow
("VanishPow",
Range(0.0,
1.0))
=
0
//消滅する力、1で全てのドットが消える
_Roughness
("Roughness",
Range(1,
100.0))
=
15
//欠けていくドットの粗さ
}
SubShader
{
Tags
{
"Queue"
=
"Transparent"
}
Cull
Off
ZWrite
Off
Blend
SrcAlpha
OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma
vertex
vert
#pragma
fragment
frag
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;
float
_VanishPow;
float
_Roughness;
v2f
vert
(appdata
v)
{
v2f
o;
o.vertex
=
UnityObjectToClipPos(v.vertex);
o.uv
=
v.uv;
o.color
=
v.color;
return
o;
}
//1次元 疑似ランダム(入力は2次元です)
float
random(fixed2
st)
{
return
frac(sin(dot(st.xy,
fixed2(12.9898,
78.233)))
*
43758.5453);
}
fixed4
frag
(v2f
i)
:
SV_Target
{
fixed4
col
=
tex2D(_MainTex,
i.uv);
//アタッチされた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
/
(fixRough
*
ratio))
*
(fixRough
*
ratio);
fixed2
roughUv
=
fixed2(roughX,
roughY);
//ランダムノイズにより、指定座標に対し0~1のランダムな値が返ってくる
fixed
rdm
=
random(roughUv);
//ランダムノイズから_VanishPowを引き、その値が0未満になった時対象ドットを消滅させる
fixed
doVanish
=
step(0,
rdm
-
_VanishPow);
col
*=
i.color;
col.a
=
col.a
*
doVanish;
return
col;
}
ENDCG
}
}
}
プロパティを解説
用意してあるプロパティは2つのみ。
VanishPowの値を上げていくと次第に対象の画像が消滅していく。
Roughnessの設定を1以上にする場合に、注意する点がある。
Imageのscale.xとscale.yの値が違ったり、元のSpriteのサイズからwidthやheightを変えると、欠けていくドットが正方形ではなくなる。
下の画像は1600x1200のドラゴンの画像に対し、ImageのHeightを2倍の2400の設定にした場合の画像。
見ての通り欠けていくドットが長方形になっている。
コードを少し解説
一番重要な点は、フラグメントシェーダーに渡されたuv座標を、下の関数を使って0~1のfloat値に変換して返している所。
//1次元 疑似ランダム(入力は2次元です)
float
random(fixed2
st)
{
return
frac(sin(dot(st.xy,
fixed2(12.9898,
78.233)))
*
43758.5453);
}
このランダムな値を使って、対象uv座標のピクセルを消滅させるかどうか判断している。
//ランダムノイズにより、指定座標に対し0~1のランダムな値が返ってくる
fixed
rdm
=
random(roughUv);
//ランダムノイズから_VanishPowを引き、その値が0未満になった時対象ドットを消滅させる
fixed
doVanish
=
step(0,
rdm
-
_VanishPow);
col
*=
i.color;
col.a
=
col.a
*
doVanish;
たとえばuv座標(0.5, 0.5)をrandom関数に渡し、その結果返ってきた値が0.1だったとする。
その上で、もし_VanishPowが0な場合次のような計算式になる。
0は0.1以下なので、step関数の結果doVanishには1が保存される。
そして
col.a = col.a * doVanish;
でピクセルのalpha値に1が掛け算される。つまり値に全く変化がない。
もしこれで、_VanishPowが0.2であった場合次のような計算式になる。
0は-0.1より大きいので、step関数の結果doVanishには0が保存される。
そして
col.a = col.a * doVanish;
でピクセルのalpha値に0が掛け算される。つまり対象座標のピクセルは消滅する。
1
1