こんにちは、Unityエンジニアのオオバです。
「ソフトマスク」とは以下の画像の通り 少しずつ透明になっていくマスク表現 です。
↑の画像は女の子の顔を中心に円形のソフトマスクを適用したサンプルです。
※このイラストアセットは中世ファンタジーRPG風2Dキャラクターパックを使わせていただいてます。
ゲームUIをデザインをする際には表現の候補に入るのではないでしょうか。しかし、Unity UIのマスク表現には課題がありました。Unityが未対応で 「ソフトマスクが使えなかったこと」 です。UIデザイナーのみなさま朗報です。 Unity2020からソフトマスクが使えるようになりました!!
本記事ではUnity2020から使えるようになったソフトマスクを紹介します。ただしこのソフトマスクは条件付きです。
でも、安心してください。 条件を満たさない場合の代替方法も合わせて紹介 します。この記事を読むだけでソフトマスクは実現できると思いますので、ぜひ最後まで読んでみてください。
ソフトマスクはRectMask2Dで簡単実装
Unity2021からRectMask2Dが進化しました。RectMask2DとはUnityのコンポーネントの1種で、矩形型のマスクを作ることができます。
👉 【保存版】Unityのコンポーネント徹底解説【Unity基礎】
矩形マスク機能に加え、ソフトマスク機能が追加実装されたのです。
元画像(マスクなし) | ソフトマスク後 |
---|---|
RectMask2Dコンポーネントを使うとこのようなソフトマスクが簡単に作れます。
時間のない方は次の15秒ショート動画で確認してみてください。RectMask2Dの使い方を紹介しています。
ここからは、文字でじっくりとRectMask2Dの使い方を解説していきます。
👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!
- ソフトマスク可能な「RectMask2D」の特徴4選
- スクロールリストにソフトマスクを適用する4ステップ
- ステップ①ヒエラルキーに「Scroll View」を追加
- ステップ②Viewportの「Mask」を削除
- ステップ③「RectMask2D」をAddComponent
- ステップ④ソフトマスク具合の調整
- ソフトマスク付きScrollViewの完成
- RectMask2Dが使えない場合のソフトマスク2つの作り方
- 標準機能のMaskコンポーネントで、きれいなソフトマスクを作れない
- 解決方法①uGUI用のマスクシェーダーを自作する
- 解決方法②外部アセット「SoftMaskForUGUI」できれいなマスクを作る方法
- SoftMaskForUGUIのインストール方法
- SoftMaskForUGUIの使い方
- SoftMaskForUGUIは多階層に対応
- SoftMaskForUGUIはMaskの子階層だけどマスク対象から除外できる
- Unity UIでソフトマスクを作る方法まとめ
ソフトマスク可能な「RectMask2D」の特徴4選
最初にRectMask2Dコンポーネントの特徴を紹介します。
①パフォーマンスの良いマスク
②マスク画像は不要
③マスク対象はRectMask2Dの子階層
④X・Y軸それぞれ具合の設定可
特徴①パフォーマンスの良いマスク
RectMask2Dとはマスクコンポーネントの1種です。特徴は マスク領域を四角形にしぼり、従来のMaskコンポーネントよりパフォーマンスを良い点 。
そして、Unity2020からソフトマスクに対応しているということです。
特徴②マスク画像は不要
RectMask2Dにはマスク画像は不要です。なぜなら四角形に限定したマスク領域だからです。
マスクの範囲はRectTransformのWidth(幅)とHeight(高さ)です。
特徴③マスク対象はRectMask2Dの子階層
RectMask2DコンポーネントをアタッチしたGameObjectの子階層がマスク対象です。
子階層であれば複数のGameObjectもまとめてマスク可能です。
特徴④X・Y軸それぞれ具合の設定可
RectMask2Dコンポーネントの Softness の値を0以上にすると、x、y軸それぞれグラデーション具合を調整できます。
スクロールリストにソフトマスクを適用する4ステップ
ソフトマスクの使い所の1つは スクロールの境界表現 です。
今までUIデザイナーから 「スクロールの境界をグラデーションできれいに消したい」 という要望が多くありました。
RectMask2Dを使うことで実現可能です。
①ヒエラルキーに「Scroll View」を追加
②Viewportの「Mask」を削除
③「RectMask2D」をAddComponent
④ソフトマスク具合の調整
上記の手順でソースコードを書かずにソフトマスク付きのスクロールリストを作れます。
ステップ①ヒエラルキーに「Scroll View」を追加
まずはヒエラルキー上で右クリック。 UI > ScrollView
をクリックしましょう。
ステップ②Viewportの「Mask」を削除
作成されたScrollViewを調整していきます。
ViewportにはデフォルトでMaskコンポーネントがくっついています。この「Mask」を削除します
- ①
Maskコンポーネント
のメニューを開く - ② Remove Component で
Mask
の削除
ステップ③「RectMask2D」をAddComponent
Maskを削除したGameObjectにRectMask2Dをアタッチします。
- ① Add Componentボタンをクリック
- ② RectMask2Dを選択
以上で準備は完了です。
ステップ④ソフトマスク具合の調整
最後に「Softness」ソフトマスクの消え方具合を調整します。
Softnessを調整することでマスクのグラデーション具合を調整可能です。
ソフトマスク付きScrollViewの完成
このようにソースコードを1行も書くことなく、ソフトマスク付きScroll Viewを作ることができるのです。
Unityには難しいUI表現がいくつかあります。 「マスク表現」もその1つです。 Unity開発では重要なのは「簡単に実装することが難しいことを事前に知っておくこと」です。 次の記事ではUnityの難しい表現をまとめました。Unityエンジニアのほか、UIデザイナーもぜひ読んでUIデザインに生かしてみてください。
Unityでは難しいUI表現5選
ゲーム開発ではできないことを知るのは重要です。Unity UIも同じ。基本機能で表現できること、できないことを知っておくことで開発計画を立てやすくなります。
RectMask2Dが使えない場合のソフトマスク2つの作り方
RectMask2Dはあくまで四角形のマスクしか作れません。例えば 円形のマスクを作ることはできない のです。そこで2つの方法を紹介します。
①新たにUI用のマスクシェーダーの作成
②SoftMaskForUGUIの使用(おすすめ)
標準機能のMaskコンポーネントで、きれいなソフトマスクを作れない
結論から話すと標準機能の「Mask」ではきれいなソフトマスクは作れません。そもそもMaskコンポーネントがどういう仕様なのか確認しましょう。
元画像 | マスク画像 |
---|---|
image.png | mask.png |
↑このように2つの画像を用意します。
理想 | 現実 |
---|---|
理想と現実にはギャップあり。思ったのと違うものができあがります。
MaskはON/OFF2択のみ
Maskコンポーネントにはグラデーション表現はありません。白から黒にかけてグラデーション画像を用意したとしても、 グレーだからといって半透明表現になりません。
つまり Maskコンポーネントでソフトマスクは表現できない のです。
マスクの縁が汚い
もう少し、Maskコンポーネントの特徴を紹介します。Maskコンポーネントの マスクの縁は汚い です。
ご覧の通りガタガタです。アンチエイリアスが効かない ため曲線を持つ図形ではジャギが目立ちます。
マスクの輪郭を 上から別の画像で隠す といった工夫でしのぐことが多いです。別の対策として マスク画像の解像度を高くする ことでかなり軽減します。
しかし、ソフトマスクの根本解決ではありません。
解決方法①uGUI用のマスクシェーダーを自作する
Maskコンポーネントを使わず、uGUIシェーダーを作成してソフトマスクを対応します。
uGUIのシェーダーを作成する際はUnity公式からuGUIシェーダーをダウンロードしてカスタマイズします。Unity公式のシェーダーをコピーして最低限の変更を加えています。
Unityダウンロードアーカイブを開きます。
あなたが使っているUnityバージョンのシェーダー をダウンロードしましょう。
- お使いのUnityバージョンの Downloads(Mac) ボタンをクリック
- Built in shaders をクリック
↑の動画の通りこの手順でシェーダーをダウンロードします。
(執筆時はUnity2020.3.19f1を使用)
Mac環境をベースに解説していますが、
お使いのマシンがWindowsならWindowsのビルトインシェーダーをダウンロードしましょう。
使っているUnityのバージョンがわからない方は、こちらの記事を参考にしてみてください。
uGUIシェーダーのカスタマイズ
Unity公式からuGUIシェーダーをダウンロードできたら早速カスタマイズしていきます。カスタマイズするシェーダーは UI-Default.shader です。格納場所はこちら DefaultResourcesExtra/UI/UI-Default.shader 。
UI-Default.shaderをコピーして、プロジェクトに追加しておきましょう。「UI-SoftMask.shader」という名前にしました。
今回の実装で重要なのはの2点です。
- Mask画像をセットできるようにする
- マスク画像のアルファ値を参照してカラー合成
ステップ①Mask画像をセットできるようにシェーダーを修正
Mask画像をインスペクタからセットできるようにシェーダーを調整します。
Propertiesを調整 します。
Properties
{
// マスク画像を外からセットできるようにする
_MaskTex("MaskTexture", 2D) = "white"{}
Propertiesブロックに _MaskTex
変数を定義します。
Pass
{
// Mask画像を定義
sampler2D _MaskTex;
Passブロック中に Propertiesで定義した同名の _MaskTex
変数を定義します。
マスク画像の用意
今回のシェーダーで必要なソフトマスクを作る画像を用意します。
マスク画像自体ははグレースケール(白黒の濃淡画像)で作ります。白から黒に向かって透明になるのです。
TextureのインスペクタでAlpha from Grayscale
にチェックを入れましょう。すると、黒に近づくにつれて透明(アルファ:0)に変換されます。
ステップ②マスク画像のアルファ値を参照してカラー合成
シェーダーの中で最も重要なのは次の2行です。
// マスク画像のカラーを取得
half4 maskCol = tex2D(_MaskTex, IN.texcoord);
// マスク画像の透明度を出力のカラーにセット
color.a = maskCol.a;
フラグメントシェーダーで取得したマスク画像のピクセル色が大事なポイントです。
ピクセルごとのアルファ値にマスク画像のアルファ値をセット します。つまり 各ピクセルの透明度はマスク画像の透明度になる のです。
このように きれいなソフトマスク を表現できました。
uGUIシェーダーをカスタマイズすることは意外とあります。 基本機能では乗算しかできませんが、加算合成する場合はシェーダーをカスタマイズ します。次の記事ではUIの加算合成するシェーダーの作り方を紹介しています。本記事とあわせて読んでみてください。
解決方法②外部アセット「SoftMaskForUGUI」できれいなマスクを作る方法
標準機能ではありませんが「SoftMaskForUGUI」を使用することで、無料できれいなソフトマスクを作ることができます。
↑このとおり、とてもきれいなソフトマスクを表現できます。
SoftMaskForUGUIのインストール方法
SoftMaskForUGUIはパッケージで提供されているため、Package Managerでインストールするのがおすすめです。 メニューWindow > Package Manager
からPackage Managerウィンドウを開きます。
①の「+」ボタンをクリックします。②にURL
https://github.com/mob-sakai/SoftMaskForUGUI
を入力して、③のAddボタンをクリックしてください。 するとインストールは完了します。
SoftMaskForUGUIの使い方
では具体的なSoftMaskForUGUIの使い方を解説します。まずはマスクする側を親、マスクされる側を子という関係のGameObjectを作ります。
↑上図のようにMaskがマスクする側、Imageがマスクされる側です。
マスクする側に「SoftMask」「Image」という2つのコンポーネントをセットしましょう。
↑上図のように2つのコンポーネントを追加します。セットする順は自由です。Imageコンポーネントにセットする画像がマスク画像になります。
今回使用するマスク画像は↑上の円形グラデーションにしました。
TextureTypeを「Sprite(2D and UI)」に設定します。
Imageの「Source Image」に設定してみましょう。
すると↑上図のとおりきれいなソフトマスクが作れます。
SoftMaskForUGUIは多階層に対応
SoftMaskForUGUIは「マスクされる側」の階層に依存せずマスクをかけられます。つまり子階層が深かかろうときれいなソフトマスクを作れるのです。
上図のようにマスクされる側の階層を3階層するとどうなるでしょうか。
SoftMaskForUGUIは子階層の階層数に関係なく、きれいにソフトマスクを作ることができるのです。
SoftMaskForUGUIはMaskの子階層だけどマスク対象から除外できる
SoftMaskForUGUIの便利な機能を紹介します。通常Maskコンポーネントの子階層は強制的にマスクされてしまいます。しかし、SoftMaskForUGUIはMaskの子階層のオブジェクトをマスク対象から外すことができる のです(下図参照)。非常に便利です。
設定方法は簡単です。マスクされる側に自動的にセットされる「SoftMaskable」の設定を変更します。
「Mask Interaction」を「Custom」、「Mask 0」を「None」に設定しましょう。するとマスク対象から除外できます。
とても便利で使いやすいSoftMaskForUGUIですが、処理を見る限りMaskコンポーネントより負荷は上がります。使用する際は負荷計測しつつ使ってみてください。
→ SoftMaskForUGUIの公式サイトはこちらUnity UIでソフトマスクを作る方法まとめ
記事前半ではUnity2020から実装された RectMask2Dのソフトマスク を紹介しました。
・RectMask2Dの子階層がマスク対象
・SoftnessでX、Y軸に対して設定化
・要望の多かったソフトマスク付きスクロールがデフォルトで実装可能
・プログラミングはいっさいなし
また、記事後半ではRectMask2Dの使えない状況におけるソフトマスクの実装方法を紹介しました。
・uGUIシェーダーをカスタマイズして自作
・SoftMaskForUGUI(無料)を使う
Unityの進化によって基本機能でできることが増えています。ありがたいことです。
しかし、 まだまだできないことは多い です。ソフトマスクはまだ発展途上。RectMask2Dは矩形のみに対応しました。RectMask2Dを使わない場合は、カスタムシェーダーの自作、または外部ライブラリである「SoftMaskForUGUI」を使う方法を紹介しました。いずれ標準機能でソフトマスクが実現できる日が来るかもしれません。
今後のUnityの進化に期待し、 新機能には敏感にウォッチ しておきたいですね。
とりあえず、今Unityのソフトマスクで悩んでいる方がこの記事を読んで課題を解決できていると嬉しいです。もしこの記事を読んでいるのがデザイナーさんだった場合、ぜひUI実装担当のエンジニアに見せてあげてください。なにか実装のヒントになるかもしません。
この記事があなたのゲーム開発に少しでもお役に立てたら嬉しいです。
今回使ったソースコード公開
今回作成したシェーダーコード全文はこちらです。
ご自由にお使いください。
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
Shader "UI/SoftMask"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
_MaskTex("MaskTexture",2D) = "white"{}
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend One OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile_local _ UNITY_UI_CLIP_RECT
#pragma multi_compile_local _ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
half4 mask : TEXCOORD2;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
float _UIMaskSoftnessX;
float _UIMaskSoftnessY;
sampler2D _MaskTex;
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
float4 vPosition = UnityObjectToClipPos(v.vertex);
OUT.worldPosition = v.vertex;
OUT.vertex = vPosition;
float2 pixelSize = vPosition.w;
pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
OUT.mask = half4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
half4 maskCol = tex2D(_MaskTex, IN.texcoord);
color.a = maskCol.a;
#ifdef UNITY_UI_CLIP_RECT
half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
color.a *= m.x * m.y;
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
color.rgb *= color.a;
return color;
}
ENDCG
}
}
}
このシェーダーをUnityプロジェクトにコピー後、Materialにアタッチしてお使いください。
この記事が気に入ったらフォローしよう
「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!
最後まで読んでいただきありがとうございました!
すばらしいソフトマスクライフをお過ごしください。
- Unity2020.3.31f1