UnityのuGUI用、ステンシルを使ったUnityシェーダーで逆マスク。
関連ページ
参考URL
Unityで逆マスクを実装するには、すでに有志の人が作ってくれた
UnmaskForUGUI
を使う選択肢があります。
自分も大分お世話になりましたが、ただこのライブラリは実装がやや複雑に感じていました。
自作ShaderのStencilでもっとシンプルに実装ができるのではと思い、試してみて可能だったので共有します。

逆マスクについて
逆マスクはマスクと逆に、指定のポイントを切り抜く機能のことです。
シェーダーを使わなくても、UnmaskForUGUIでも上のような表現はできます。
ただUnmaskForUGUIは、透過される先の背景画像もMaskコンポーネントの子要素にする必要があって、そこを残念に思っていました。
今回の実装では、逆マスクをかける側と、逆マスクをかけられる側2つのシェーダーを組み合わせて画面を作ります。
上の画像で言うと?マークが逆マスクをかける側、Unity仮面が逆マスクをかけられる側となります。
UI Maskのコンポーネントは必要としません。

StencilUnmaskシェーダー
逆マスクをかける側のシェーダー全文は次の通り。適当な.shader拡張子ファイルに丸コピします。

Shader
"UI/StencilUnmask"
{
Properties
{
_StencilRef("StencilRef",
Range(0,
255))
=
2
[HideInInspector]_MainTex("-",2D)="white"{}
[HideInInspector]_StencilComp
("Stencil
Comparison",
Float)
=
8.000000
[HideInInspector]_Stencil
("Stencil
ID",
Float)
=
0.000000
[HideInInspector]_StencilOp
("Stencil
Operation",
Float)
=
0.000000
[HideInInspector]_StencilWriteMask
("Stencil
Write
Mask",
Float)
=
255.000000
[HideInInspector]_StencilReadMask
("Stencil
Read
Mask",
Float)
=
255.000000
[HideInInspector]_ColorMask
("Color
Mask",
Float)
=
15.000000
}
SubShader
{
Tags
{
"Queue"
=
"Transparent"
}
Cull
Off
ZWrite
Off
Blend
SrcAlpha
OneMinusSrcAlpha
Pass
{
//このシェーダーの描画範囲のステンシルバッファをStencilRefに上書き
Stencil
{
Ref
[_StencilRef]
Comp
always
Pass
replace
}
CGPROGRAM
#pragma
vertex
vert
#pragma
fragment
frag
#include
"UnityCG.cginc"
struct
appdata
{
fixed2
uv
:
TEXCOORD0;
fixed4
vertex
:
POSITION;
};
struct
v2f
{
fixed2
uv
:
TEXCOORD0;
fixed4
vertex
:
SV_POSITION;
};
sampler2D
_MainTex;
float4
_MainTex_ST;
v2f
vert
(appdata
v)
{
v2f
o;
o.vertex
=
UnityObjectToClipPos(v.vertex);
o.uv
=
TRANSFORM_TEX(v.uv,
_MainTex);
return
o;
}
fixed4
frag
(v2f
i)
:
SV_Target
{
fixed4
col
=
tex2D(_MainTex,
i.uv);
//alphaがほぼ0ならStencilのreplaceを実行しない
if(col.a<0.1)discard;
//逆マスクのためだけの機能なので、画像のアウトライン以外は無視してほぼ透明で描画
return
fixed4(0,
0,
0,
0.01);
}
ENDCG
}
}
}

新たにマテリアルを作り、パスに
UI/StencilUnmask
に指定。
これをImageのマテリアルにアタッチ。詳しくは
こちらのページ
を参照。

StencilUnmaskedシェーダー
逆マスクをかけられる側のシェーダー全文は次の通りです。適当な.shader拡張子ファイルに丸コピします。

Shader
"UI/StencilUnmasked"
{
Properties
{
_StencilRef("StencilRef",
Range(0,
255))
=
2
[HideInInspector]_MainTex("-",2D)="white"{}
[HideInInspector]_StencilComp
("Stencil
Comparison",
Float)
=
8.000000
[HideInInspector]_Stencil
("Stencil
ID",
Float)
=
0.000000
[HideInInspector]_StencilOp
("Stencil
Operation",
Float)
=
0.000000
[HideInInspector]_StencilWriteMask
("Stencil
Write
Mask",
Float)
=
255.000000
[HideInInspector]_StencilReadMask
("Stencil
Read
Mask",
Float)
=
255.000000
[HideInInspector]_ColorMask
("Color
Mask",
Float)
=
15.000000
}
SubShader
{
Tags
{
"Queue"
=
"Transparent"
}
Blend
SrcAlpha
OneMinusSrcAlpha
LOD
100
ZWrite
Off
Pass
{
//ステンシルバッファが指定値以外の時のみ描画
Stencil
{
Ref
[_StencilRef]
Comp
NotEqual
}
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
:
SV_POSITION;
fixed4
color
:
COLOR;
};
sampler2D
_MainTex;
v2f
vert
(appdata
v)
{
v2f
o;
o.vertex
=
UnityObjectToClipPos(v.vertex);
o.uv
=
v.uv;
o.color
=
v.color;
return
o;
}
fixed4
frag
(v2f
i)
:
SV_Target
{
fixed4
col
=
tex2D(_MainTex,
i.uv);
col
*=
i.color;
return
col;
}
ENDCG
}
}
}

新たにマテリアルを作り、パスを
UI/StencilUnmasked
に指定。
これをImageのマテリアルにアタッチします。

実装の仕方
逆マスクをかける側の方をHierarchy上は上に配置する必要があります。
またシェーダーを指定した2つのマテリアルは、Inspector上で
StencilRef
のint値を一緒にする必要がある。
初期値は2になってますが、場合によっては値を変える必要があるかもしれないです。
値を変えたのちは、Controll+Sでプロジェクトを保存しないと画面に反映されないことがあります。
0
0