このブログで使用しているUnityのVer
・Unity 6000.0.33f1

やほー!マスク表現の扱いにはもう慣れた?
Unityでマスクする方法に関して、前に幾つか記事を書きましたが、
外部のライブラリをインストールしたり、複雑なレイヤー構成にしたり、コードを書いたり、コンポーネントが微妙に自分の希望に合うコンポーネントじゃなかったり…
そんな事、ありませんか?(あるー!)
そんな時に今回はサクッとマテリアルの設定のみで出来るマスク処理を紹介します。
UIオブジェクトでのクリックするためのレイキャストターゲットに関しては下記で少し触れています。
今回のマスクの方法は「ステンシルバッファ」という機能を使ってマスクを表現していきます。

ステンシルバッファは概念は少し難しいけど、使う分にはシンプルで簡単ふるよ!
ステンシルバッファとは?
ステンシルバッファは 画面の各ピクセル毎に8ビット(0~255の値) 分のデータ持つ領域(バッファ)の事でここに整数値を格納できます。(RGBみたいなもんですね)
この格納された数値と描画するものとで比較したり・書き換えたりすることで、画面への描画をコントロールすることが出来ます。
例えば
「ステンシル値 1 を書き込む」設定のオブジェクトを画面に描画したらそのピクセルは「1」になります。
この「1のピクセル」と、重なったオブジェクトのステンシルの比較条件を参照します。
「ステンシル値が 1 の場所にだけ描画する」といったルールであれば重なった所だけ描画されますね。

ステンシル1の領域にオブジェクトを重ねると…↓

こんなイメージです。
Unityではステンシルバッファをコントロールする方法はいくつかありますが、
ここでは簡単にノーコードで出来るマテリアルでの設定方法を記載します。
ステンシルバッファを使ったマスク方法(マテリアル)
まずは最初に具体的な作り方を記載します。
その後に各項目の意味などを説明したいと思いますので気になる方は見ていって下さいね。
※今回説明用に使っているアセットはこちらになります。
https://assetstore.unity.com/packages/2d/gui/violet-themed-ui-235559
マテリアルのみでのマスクの作り方
今、こんなUIオブジェクトの画面があるとします。

ボタンやコインなどのImageオブジェクトがあり、最前面に半透明のPanelで蓋がしてある状態です。

※Unityはレイヤーの上から描画されていくので、一番下が最前面に描画される。
この時、Maskとして使いたいImageを用意します。(右クリック→UI→Image)
Maskという名前にして、Hierarchyの上に配置します。

このレイヤーの順番は非常に重要です。
Unityでは
1.マスク用のImageを最初に描画してステンシルバッファに「マスク領域」を設定
2.以降に描画されるオブジェクトが描画したステンシルの設定と比較してどう描画されるかを決める
という順番で処理されているからです。
次にステンシルバッファを設定するためにマテリアルを作っていきましょう。
まずは、マスク用のマテリアルを作成します。Projectウインドウで
右クリック→Create→Material
でマテリアル作成。
名前を「MaskMt」に私はしました。
マテリアルを作れたらShaderをUI/Defaultにして下さい。

そしてマテリアルの各数値の設定を下記のように設定して下さい。

・カラーのアルファを0
・Stencil Comparison 8
・Stencil ID 1
・Stencil Operation 2
となります。
これらコンポーネントの詳細は後述しますが、簡単に説明すると
・Comparison 比較で数字によって比較・描画のルールを決めています。
・ID このオブジェクトが描画された時にピクセルに設定されているステンシルバッファと比較するためのID値。
・Operation ステンシルバッファを書き換える(新たに格納する)ルールを数字で決めています。
このマテリアルが用意できたら先ほど作成した「Mask」にアタッチしましょう。

アルファを0にしたので透明になってしまいますが、大丈夫です!

次に「マスクされる側」のマテリアルを作りましょう。
先ほどと同じで
Projectウインドウで右クリック→Create→Materialでマテリアル作成。
今回は名前を「MaskedMt」にしました。
マテリアルを作れたら同じくShaderをUI/Defaultにして下さい。
そしてこちらのマテリアルの設定は下記のようにして下さい。

・Stencil Comparison 3
・Stencil ID 1
・Stencil Operation 0
色はそのままで大丈夫です。
それでは、このマテリアルをUIのImageを覆っているPanelにアタッチしましょう。
Panelが非表示になったかと思います。
これは今、マスク設定をしているので「Mask」オブジェクトが重なっている部分だけ描画されるようになっているためです。
試しに動かしてみましょう。

Maskオブジェクトが重なった所だけPanelが表示されています!
マテリアルを使ったマスク表現は以上になります。

ちょろっと数字をいじるだけで簡単ふるね!
マテリアルのみでの逆マスクの作り方
次に、逆マスクの作り方を説明します。
といっても、先ほどマスクの方で作成した「MaskedMt」の数値を変えるだけです。
※「Mask」オブジェクトの方は引き続き「MaskMt」マテリアルを使って下さい。
Projectフォルダで「MaskedMt」をコピペ、複製しましょう。(CtrlC→CtrlV)
複製したら名前を「InMaskedMt」に私はしました。
そうしたらコンポーネントの設定を下記のようにして下さい。

・Stencil Comparison 6
・Stencil ID 1
・Stencil Operation 0
設定できたら今度はこのマテリアルをPanelにアタッチしてみましょう。
見た目は元の半透明のPanelのままだと思います。
この状態でMaskを動かしてみましょう。

重なった部分だけマスクされる「逆マスク」表現ができました!
これで、マテリアルを使ったマスクの具体的な方法は終わりです。

この方法は簡単だけど、下に描画されているボタンのクリックはできないから注意してね!!
マテリアルのステンシルバッファの項目説明
使い方の説明では、Stencil Comparisonを6に!みたいな数字だけの記載でしたが、
それぞれの項目や数字が何を意味しているのか、ここで記載していこうと思います。
なお、Unityの公式マニュアルでも(現在は英語のみですが)記載があります。
https://docs.unity3d.com/Manual/SL-Stencil.html
Stencil Comparison(比較関数)
現在のピクセルのステンシル値と、指定した Stencil ID を比較する方法を決定。
数値 | 関数名 | 比較条件 |
---|---|---|
1 | Never | 常に描画しない |
2 | Less | 参照値がステンシルバッファ値より小さい場合に描画 |
3 | Equal | ステンシル値と比較値が一致する場合のみ描画 |
4 | LEqual | 参照値がステンシルバッファ値以下の場合に描画 |
5 | Greater | 参照値がステンシルバッファ値より大きい場合に描画 |
6 | NotEqual | 参照値がステンシルバッファ値と異なる場合に描画 |
7 | GEqual | 参照値がステンシルバッファ値以上の場合に描画 |
8 | Always | 常に描画する |
2. Stencil ID(比較・参照値)
比較の基準となる数値を設定する。ステンシルバッファに書き込むID値。
例えば
- 1つのオブジェクトで Stencil ID = 1 を設定
- 別のオブジェクトの Stencil Comparison = 3(等しい場合のみ描画)
- → Stencil ID が 1 の場所にだけ描画される
といったイメージ。
3. Stencil Operation(ステンシルバッファの書き換え処理関数)
ステンシルバッファに書き込む処理の仕方を設定。
数値 | 関数名 | 処理内容 |
---|---|---|
0 | Keep | 変更しない |
1 | Zero | 0 にリセット |
2 | Replace | 指定した Stencil ID に置き換える |
3 | IncrSat | 1 を加算(255 以上にならない) |
4 | DecrSat | 1 を減算(0 以下にならない) |
5 | Invert | ビット反転 |
6 | IncrWrap | 1 を加算(255の場合0になる) |
7 | DecrWrap | 1 を減算(0の場合は255になる) |
Stencil Write Mask(書き込みマスク)
→ 書き込みできるビットを制限する(デフォルト: 255 → 全ビット許可)
2進数の話が絡んでくるのでここでは詳しく記載しませんが基本的に255で大丈夫ではと思います。
Stencil Read Mask(読み取りマスク)
→ 比較の際に特定のビットだけ使用する(デフォルト: 255)
2進数の話が絡んでくるのでここでは詳しく記載しませんが基本的に255で大丈夫ではと思います。

以上でオプション項目に関しては終わりですふる!
終わりに
今回はノーコード、マテリアルのみで完結するマスク、逆マスク表現を紹介しました。
何度か触れましたがボタンなどをクリックするために逆マスク部分だけクリック判定を貫通させることはできないので、チュートリアル表現などをしたい場合は他の手法を検討してみて下さいね。
当ブログ「えきふるゲームラボ」では出来るだけ分かり易く読みやすい記事の作成を目指しています!
もし読んでくださった方の中で
「ここが良く分からなかった」「ここをもう少し掘り下げて欲しい」等ありましたら
ぜひコメントで教えて下さい!

コメント貰えると元気も出ますので、どうぞお気軽にお願いしますふる!
※このブログは、UnityTechnologiesまたはその関連会社が後援または提携しているものではありません。
「Unity」は、UnityTechnologiesまたはその関連会社の米国およびその他の国における商標または登録商標です。