問題
重なるUIを一緒にフェードしたい場合、CanvasGroupでAlphaを弄っても、それぞれのUIが互いにフェードして、下にあるUIが透けて見える問題があります。
解決
一番思いつきやすい解決案として、RenderTextureを用いることが考えられます。
しかしRenderTextureの描画はやや手順が複雑、かつ負荷が重いので今回はステンシルバッファを用いる手法を紹介します。
マスクに似たような考え方で、上にあるUIを常に描画するマスクとして、下にあるUIを上のマスク領域内で描画しないようにします。
そうすると下にあるUIが描画順上上にあるUIの後に描画されますが、上にあるUIと重なる部分だけステンシルテストが通らず、描画されなくなります。
それでCanvasGroupでAlphaを一緒に弄っても透けて見える問題がありません。
手順
デフォルトのUIシェーダーですでにステンシルを自由に設定できるので、それのマテリアルを2つ作ればOKです。
- 新規のマテリアルAを作成する。
- マテリアルAのシェーダーをUI/Defaultに変える。
- マテリアルAのインスペクターから、Stencil Comparisonを5(Greater)、Stencil IDを1、Stencil Operationを2(Replace)にする。
- つまり参照値(1)が既存のステンシルバッファの値より大きいピクセルのみを描画し、そのステンシルバッファの値を1に書き換えること。
- マテリアルAを上にあるUI画像のマテリアルに設定する。
- 新規のマテリアルBを作成する。
- マテリアルBのシェーダーをUI/Defaultに変える。
- マテリアルBのインスペクターから、Stencil Comparisonを5(Greater)、Stencil IDを1、Stencil Operationを0(Keep)にする。
- つまり参照値(1)が既存のステンシルバッファの値より大きいピクセルのみを描画し、そのステンシルバッファの値をそのままにしておくこと。
- マテリアルBを下にあるUI画像のマテリアルに設定する。
- CanvasGroupコンポーネントを付けて上にあるUIと下にあるUIを同時にフェードする。
ステンシル設定の詳細はUnityのドキュメントをご参考ください。
UnityのMaskコンポーネントと一緒に使う時の問題
上記の方法はステンシルバッファを使って実現しているため、同じくステンシルバッファを利用しているUnityのMaskコンポーネントと衝突する場合があります。
それを回避するためにはMaskの代わりにRectMask2Dを使うのをお勧めします 。RectMask2Dはステンシルバッファを用いなく、軽量なので基本こちらのほうを使いましょう。
もしマスクの形が矩形ではないなど、どうしてもMaskコンポーネントを使いたい時は別途対応する必要があります。
まずUI/Defaultみたいなステンシル設定をマテリアルから直接いじられるシェーダーでは、UnityのMaskコンポーネントによって強制的に書き換えられてしまうので、専用シェーダー(UI/Defaultの改造)でステンシルを制御します。
UnityのMaskコンポーネントではマスク領域のステンシルバッファの値を1にしているため、上にあるUIを1だったら描画し、かつそのステンシルバッファの値を1増やせば、下にあるUIでは上にあるUIの領域で描画されなくなります。
Stencil
{
Ref 1
Comp Equal
Pass IncrSat
}