UnityのuGUI用、ステンシルを使ったUnityシェーダーで逆マスク。
関連ページ
参考URL
Unityで逆マスクを実装するには、すでに有志の人が作ってくれた
UnmaskForUGUI
を使う選択肢がある。
自分も大分お世話になったが、ただこのライブラリは実装がやや複雑に感じていた。
ShaderのStencilを使うことでより簡単に実装ができるのではと思い、試してみて可能だったので共有。
逆マスクについて
逆マスクはマスクと逆に、指定のポイントを切り抜く機能のこと。
シェーダーを使わなくても、UnmaskForUGUIでも上のような表現はできる。
ただUnmaskForUGUIは、透過される先の背景画像もMaskコンポーネントの子要素にする必要があって、そこを残念に思っていた。
今回の実装では、逆マスクをかける側と、逆マスクをかけられる側2つのシェーダーを組み合わせて画面を作る。
上の画像で言うと?マークが逆マスクをかける側、Unity仮面が逆マスクをかけられる側となる。
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