そろそろShaderをやるパート6 画像をマスクする

3 min読了の目安(約2700字TECH技術記事

そろそろShaderをやります

そろそろShaderをやります。そろそろShaderをやりたいからです。
パート100までダラダラ頑張ります。10年かかってもいいのでやります。
100記事分くらい学べば私レベルの初心者でもまあまあ理解できるかなと思っています。

という感じでやってます。

※初心者がメモレベルで記録するので
 技術記事としてはお力になれないかもしれません。

下準備

下記参考
そろそろShaderをやるパート1 Unite 2017の動画を見る(基礎知識~フラグメントシェーダーで色を変える)

デモ

メイン画像をマスク画像の形状に切り抜くことができました。

Shaderサンプル

Shader "Custom/Mask"
{
    //Inspectorに出すプロパティー
    Properties
    {
        //テクスチャー(オフセットの設定なし)
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
        //Mask用テクスチャー(オフセットの設定なし)
        [NoScaleOffset] _MaskTex("Mask Texture (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            //頂点シェーダーに渡ってくる頂点データ
            struct appdata
            {
                //セミコロン以降の大文字はセマンティクスと呼ばれる 
                //"この変数は ○○を受け取ります" みたいなやつらしい
                float4 vertex : POSITION;
                float2 uv1 : TEXCOORD0; //1番目のUV座標 たぶんテクスチャが複数枚あって別々に何かしたいときに助かるやつ
            };

            //フラグメントシェーダーへ渡すデータ
            struct v2f
            {
                float2 uv1 : TEXCOORD0; //テクスチャUV
                float4 vertex : SV_POSITION; //座標変換された後の頂点座標
            };

            sampler2D _MainTex;
            sampler2D _MaskTex;

            //頂点シェーダー
            v2f vert(appdata  v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex); //3D空間座標→スクリーン座標変換
                o.uv1 = v.uv1;
                return o;
            }

            //フラグメントシェーダー
            fixed4 frag(v2f i) : SV_Target
            {
                //マスク用画像のピクセルの色を計算
                fixed4 mask = tex2D(_MaskTex, i.uv1);
                //引数の値が"0以下なら"描画しない すなわち"Alphaが0.5以下なら"描画しない
                clip(mask.a - 0.5);
                //メイン画像のピクセルの色を計算
                fixed4 col = tex2D(_MainTex, i.uv1);
                //メイン画像とマスク画像のピクセルの計算結果を掛け合わせる
                return col * mask;
            }
            ENDCG
        }
    }
}

clip

切り抜きの原理としてはclip(mask.a - 0.5);の箇所が肝です。
clipの引数に渡した値が0以下となった場合、描画しないみたいなことができるようです。

マスク画像のAlpha値から0.5を引いているので、
マスク画像のAlpha値が0.5以下の場合(すなわち引数の値が0以下)は描画しないということになります。

なのでマスク画像の描画したくない部分のAlpha値は
あらかじめ0.5以下になるように透過した画像を用意しておく必要があります。

参考リンク

Unityシェーダプログラム入門 UnlitShaderの要素を全て解説
Use of Clip () in alpha cutouts?