-->

【Unity Shader】UIドット欠けシェーダー

【Unity Shader】UIドット欠けシェーダー
 ※コードが古くなっていたのでURP用にコードを改修しました。(2026/08/18) 


よくSFCのFFとかでは、敵を倒した際に敵の画像のピクセルが徐々に欠けていき最終的に消滅する演出があったと思います。
あれを作りたいと思って結構楽に作れたので共有。

今回 こちらの記事を大いに参考にしています。
このシェーダーの応用で、 Dissolve Shaderも作れたのでそちらも併せてどうぞ。

ドット欠けシェーダーの概要

下がドット欠けシェーダーのサンプル動画です。
VanishPowの値を上げていくと徐々にドット欠けの範囲が広がっていき、最終的に消滅します。

ドット欠けシェーダーのコード全文

以下シェーダーのコード全文です。
.shader拡張子であればファイル名は何でもいいですが、とりあえず
 DeadPixel.shader 
というファイルを作り、中身を全てコピペしてください。
Copy Code

Shader "UI/DeadPixel"
{
    Properties
    {
        [HideInInspector]_MainTex("-",2D)="white"{}
        _VanishPow ("VanishPow", Range(0.0, 1.0)) = 0 //消滅する力、1で全てのドットが消える
        _Roughness ("Roughness", Range(1, 100.0)) = 15 //欠けていくドットの粗さ
    }

    SubShader
    {
        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "Queue" = "Transparent"
        }
        Cull Off
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            HLSLPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

                struct Attributes
                {
                    half2 uv : TEXCOORD0;
                    float4 positionOS : POSITION;
                    half4 color : COLOR;
                };

                struct Varyings
                {
                    half2 uv : TEXCOORD0;
                    float4 positionCS : SV_POSITION;
                    half4 color : COLOR;

                    //画像の縦横比、nointerpolationで線形補完を禁止
                    nointerpolation half2 ratio : TEXCOORD3;
                };

                //uGUI Image > Source Imageにアタッチされた画像を参照する
                TEXTURE2D(_MainTex);
                SAMPLER(sampler_MainTex);
                //アタッチされたSpriteのサイズを取得(x=1.0/width, y=1.0/height, z=width, w=height)
                float4 _MainTex_TexelSize;

                //SRP Batcherを適用
                CBUFFER_START(UnityPerMaterial)
                    //Propertiesに対応する変数
                    float _VanishPow;
                    float _Roughness;
                CBUFFER_END

                //1次元 疑似ランダム(入力は2次元です)
                float random(half2 st)
                {
                    return frac(sin(dot(st.xy, float2(12.9898, 78.233))) * 43758.5453);
                }

                //頂点シェーダー
                Varyings vert (Attributes input)
                {
                    Varyings output;

                    output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                    output.uv = input.uv;
                    output.color = input.color;

                    //RectTransformのWidthのHeightの設定値を参照し、Imageの縦横比をratioに保存
                    float2 sizeDelta = abs(input.positionOS.xy) * 2.0;
                    output.ratio = sizeDelta.x / sizeDelta.y;

                    return output;
                }

                //ピクセルシェーダー
                half4 frag (Varyings input) : SV_Target
                {
                    half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
                    col *= input.color;

                    //_Roughnessの入力値を実際に使う値まで細かくする
                    half fixRough = _Roughness * 0.001f;

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

                    //ランダムノイズにより、指定座標に対し0~1のランダムな値が返ってくる
                    half rdm = random(roughUv);
                    //ランダムノイズから_VanishPowを引き、その値が0未満になった時対象ドットを消滅させる
                    half doVanish = step(0, rdm - _VanishPow);
                    col.a = col.a * doVanish;

                    return col;
                }
            ENDHLSL
        }
    }
}
シェーダーファイルを作成したら、次にMaterialを新規作成し、Shaderの欄に
 UI/DeadPixel 
を指定します。

この辺りの紐づけの仕様についてはこちらでも解説してあります。 p.63 : 【Unity Shader 基礎】Imageにシェーダーを反映させる方法

プロパティを解説

用意してあるプロパティは2つのみです。
 VanishPow 
の値を上げていくと次第に対象の画像が消滅していきます。
ドット欠けシェーダーのプロパティ
 VanishPow 
: 消滅する力。0から1まで設定可能で、0で全て表示、1で全てのピクセルが消える。
 Roughness 
: VanishPowを上げていく際の、欠けていくドットの粗さ。1から100まで設定可能。

コードを少し解説

一番重要な点は、ピクセルシェーダーに渡されたuv座標を、下の
 randam 
関数を使って0~1のfloat値に変換して返している所です。
Copy Code

                //1次元 疑似ランダム(入力は2次元です)
                float random(half2 st)
                {
                    return frac(sin(dot(st.xy, float2(12.9898, 78.233))) * 43758.5453);
                }

このランダムな値を使って、対象uv座標のピクセルを消滅させるかどうか判断しています。
Copy Code

                    //ランダムノイズにより、指定座標に対し0~1のランダムな値が返ってくる
                    half rdm = random(roughUv);
                    //ランダムノイズから_VanishPowを引き、その値が0未満になった時対象ドットを消滅させる
                    half doVanish = step(0, rdm - _VanishPow);
                    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