[Unity uGUI] ドット欠けシェーダー。ピクセルが虫食いで欠けていく演出。
(Dead Pixel Shader)
関連ページ
参考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座標を、下の
randam
関数を使って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な場合次のような計算式になります。
fixed doVanish = step(0, rdm - _VanishPow);
fixed doVanish = step(0, 0.1 - 0);
fixed doVanish = step(0, 0.1);
0は0.1以下なので、
step
関数の結果doVanishには1が保存されます。
そして
col.a = col.a * doVanish;
でピクセルのalpha値に1が掛け算されます。つまり値に全く変化がありません。
もしこれで、
_VanishPow
が0.2であった場合次のような計算式になります。
fixed doVanish = step(0, rdm - _VanishPow);
fixed doVanish = step(0, 0.1 - 0.2);
fixed doVanish = step(0, -0.1);
0は-0.1より大きいので、
step
関数の結果doVanishには0が保存されます。
そして
col.a = col.a * doVanish;
でピクセルのalpha値に0が掛け算されます。つまり対象座標のピクセルは消滅します。
1
1