
UIだってShaderつかいたい! Unity SYNC2022 UI演出解説 その2
こんにちは。クライアントエンジニアの畑山です。
2022年 10月26日に行われたUnity SYNC2022にて「UIもshaderで盛る! 〜 shaderとanimationで作るリッチなUI演出」というタイトルで公演させて頂きました。
引き続きご好評頂き、現在(2023/02/20時点)でもSYNC2022の動画の中では視聴数TOPを維持しております。ご視聴頂いた皆様には改めて御礼申し上げます。
下記に関連URLをまとめておきます。
- 動画 (https://www.youtube.com/watch?v=T_dYC4LvFJk)
- スライド (https://www.docswell.com/s/UnityJapan/ZQDW75-sync2022_day2_track2_1920)
- 解説記事 その1(https://blog.applibot.co.jp/2022/12/22/sync2022-ui-part1/)
- サンプルgithubリポジトリ (https://github.com/applibot-inc/sync2022-ui-sample-techbot)
今回は解説記事の2回目になります。下記の項目に関してサンプルを公開、解説します。サンプルgithubリポジトリはコチラです。
- グリッチ
- 放射状のブラー
- 各種問題への対処
- 描画するためのMeshに面積が足らない問題
- Atlasを使っている場合、隣接パーツが見えてしまう問題
- Atlasを使っている場合、UV値がずれる問題
- 前回からの改善点
グリッチ
高橋啓治郎さんのKinoGlitch をベースにしています。
KinoGlitchはPost Effectとして実装されています。
それをUI用にアレンジしました。
また、走査線を追加しています。走査線を足した分だけ暗くみえてしまうため、色を全体的に持ち上げるパラメーターも追加しています。
サンプルリポジトリの Assets/Samples/Glitch/Glitch.unity にて確認頂けます。
放射状ブラー
これもPost Effectで良く使われる処理をUI向けにアレンジしたものです。
通常のブラー処理は、周囲の色を参照し、それらを混ぜ合わる事でボケた表現になります。
放射状のブラーは、ある点(サンプルでは画像の中心)に向かって色を参照し、混ぜ合わせます。
サンプルリポジトリの Assets/Samples/RadialBlur/RadialBlur.unity にて確認頂けます。
各種問題への対処
Post Effectの処理はUI向けに使えるものが多く、他にも参考になるものが沢山あります。
今回の2つのエフェクトもそうですし、前回ご紹介したエッジ検出フィルタを使ったアウトラインもその一つです。
ここからは、そうしたPost Effectの処理をUI向けにアレンジする際に発生する問題と対処を解説していきます。
これまでご紹介したUIエフェクトは
- テクスチャに透明部分の余白が十分にある
- UV Atlasを使わない
という条件下では上手くいきます。
ここからは、それに当てはまらない場合に発生する各種問題へ対処していきます。
1. 描画するためのMeshに面積が足らない
グリッチでノイズを大きくすると、横方向の面積が足りなくなります。
射状ブラーでは、外側にエフェクトが広がった場合、元々のUIパーツよりも大きくなります。すると、元々のMeshでは描画範囲が足らず、途中で表示が切れてしまいます。

そこで、実行時にmeshの頂点を取得・拡大する事で解決します。

具体的なコードは下記のようになります。
Meshの面積問題は解決しましたが、UI Atlasと組み合わせると新たな問題が発生します。
2. UI Atlasを使っている場合、Meshを大きくするとAtlas内の隣接したパーツまで描画される
Meshを大きくする事で、見切れてしまった部分を描画できるようになりました。しかしUI Atlasを使っている場合、Atlas内の隣接したパーツまで表示されてしまいます。

これに対しては、描画中のパーツがUI Atlasの中でどこにあるかを取得し「描画パーツの座標、大きさ」をshaderに伝えます。
shaderでは下記情報を元に描画すべき部分を判断します。
- Atlasの大きさ
- 描画パーツの座標、大きさ
- uv値
該当の処理は下記のようになります。IsInner()関数は Assets/Commoon/UvUtil.cginc に定義されています。
3. UI Atlasを使っている場合、UV座標がずれる
UI Atlasを使う場合、shaderに渡ってくるUV値はUnityエンジン側で調整されており、Atlas内の描画対象部分だけを表示するためのUV値が渡ってきています。例えば、通常ならuv値は0〜1の値を取りますが、atlasを使った場合は0.24 〜 0.78のように中途半端な値を取ります。
このため、shader内でUV値を元にした計算をしていた場合、期待した結果とは異なる場合があります。
すべてのエフェクトがこの問題の影響を受けるわけではないですが、この補正をしない場合、放射状ブラーでは中心点がずれてしまいます。
これも2. と同じく描画中のパーツがどこにあるかをshaderに伝え、補正します。

前回記事からの改善点
前記事でご紹介したディゾルブに関しても、今回ご紹介した処理を施すことで、画像の下の方が切れずに、溶けた部分が描画されるようになりました。

また、前回ご紹介したアウトラインを含め、エフェクトの強弱がテクスチャの大きさに依存していました。テクスチャの解像度設定を変更したりすると見た目が変化してしまうという問題に気づき、テクスチャの大きさ依存ではなく、描画しているcanvasの大きさを参照するように変更しました。
ただ、これには一長一短があります。動的にcanvasの大きさを取得するのではなく、設定ファイルを用意し、想定キャンバスサイズを指定する、などの手法も良いのではないかと考えています。
おわりに
Post Effectだと画面全体にエフェクトが一律にかかってしまいますが、UIに対してのみ効果を掛けることで、演出の幅がかなり広がるようになります。このサンプルが表現の参考になれば幸いです。
次回はTextMeshProと、UIパーツをキャプチャする処理について解説しようと思います。
ここまで読んでくださり、ありがとうございました。

この記事へのコメントはありません。