ソースコード大公開!SYNC2022リッチなUI演出の解説をします 〜 その1

こんにちは。クライアントエンジニアの畑山です。

この記事は「Applibot Advent Calendar 2022」22日目の記事になります。

2022年 10月26日に行われたUnity SYNC2022にて「UIもshaderで盛る! 〜 shaderとanimationで作るリッチなUI演出」というタイトルで公演させて頂きました。

沢山の方に見て頂き、現在(2022年12月22日時点)Unity SYNCの講演動画の中では再生数がTOPになっております。(スライドはコチラです) 講演にご参加いただいた皆様には、改めて御礼申し上げます。

解説記事を公開するにあたり、実際に動作するサンプルUnity Projectを用意しました。弊社githubリポジトリにて公開しています。 (処理に間違いがあれば、ご指摘いただけると幸いです)

これから何回かに分け、サンプルの公開とその解説を書いていこうと思います。

サンプルUnity Projectをご覧になりながら読んで頂けると、より理解が深まるかと思います。

今回は下記の項目に関してサンプルを公開、解説します。

  1. 描画モードの再現
  2. フィルタを使ったアウトライン
  3. ディゾルブ

描画モードの再現

photoshopにある全ての描画モードを再現できているわけではないですが、メジャーな描画モードには対応できたかと思います。

講演のおさらいになりますが、shaderにて

Blend [_SrcFactor] [_DstFactor]
BlendOp [_BlendOp]

このように記述し、[_SrcFactor]などの変数を指定する事で合成方法をコントロールする事ができます。

unityのマニュアルはコチラです。

ShaderLab コマンド: Blend – Unity マニュアル

これを実装する上で、下記URLの記事が参考になりました。

Blend Modes in Unity | Elringus

Framebuffer Fetchを使うと、更に自由に描画モードの処理が実装できそうです。しかし端末により挙動の差異があるため、使用するハードルは高そうです。

動作確認方法

サンプルシーンのCanvas内をご覧下さい。UICustomBlendコンポーネントのBlendModeパラメータを変化させる事で確認できます。

ソーベルフィルタを使ったアウトラインについて

ソーベルフィルタは画像のエッジ抽出を行うフィルタです。画像の輝度を調べ、大きく変化している箇所をエッジとみなします。shaderの行数は多いものの、やっている事は割と単純です。

他にも色々なフィルタがあるので、色々比較してみると面白そうです。

実装にあたってのポイントを書きます。

  • 各pixelを判定する際、輝度に変換
  • アルファ値が考慮されるよう、輝度を判定する際にアルファ値をかけている
  • アルファの境目も判定したいため、色とalpha値、2つの差分で判定。大きい方を採用
    • これを利用して、色だけ、alphaだけ、など選択する事も可能
    • alphaだけで判定すると、画像の外側の輪郭線だけ抽出するようになります

適用結果の画像化について

サンプルではStart()のタイミングでrender textureに描画結果をコピーし、shaderが毎フレーム実行されないようにしました。

これを実行する際の注意点として、Blit()する際に余計なアルファブレンドが実行されないよう

Blend One Zero

としています。

こうしないと、画像化する際にアルファブレンドが行われ、画像化したテクスチャが画面に表示されるときにもう一度アルファブレンドされてしまい、2回アルファブレンドされることになってしまいます。

(通常はBlend SrcAlpha OneMinusSrcAlphaで描画)

また、今回サンプルを作成して気付いたのですが、画像化するタイミングで微妙に線の濃度が変化していました。こちら別途調査しており、分かり次第こちらの記事を更新予定です。

動作確認方法

サンプルシーンのCanvas内、Animationという名前のgameObjectをご確認下さい。

講演でお話したMaskコンポーネントを使ったサンプルになります。unityを再生するとアウトラインを画像化し、Maskコンポーネントのアニメーションが再生されます。

(旧Animationコンポーネントを使用していますが、新規プロジェクトでの使用は推奨されません。ここではサンプル作成の際の利便性を優先して使っています。ご了承下さい。)

ディゾルブについて

講演でご紹介したサンプルを更に改良し、エッジ部分を歪ませて画像がドロッと溶ける感じに調整してみました。

ディゾルブの仕組みについて簡単に解説します。まず、このようなテクスチャを用意します。

黒の部分が0で、白に近づくにつれ1の値が入ったテクスチャです。

簡単なものであれば、photoshopの雲模様フィルタで作成できます。

しきい値を設け、0〜1の間で変化させます。このテクスチャを参照し、しきい値と比較して大きい (または小さい) 部分のみを描画する事で、このテクスチャの模様が反映された形で、表示・非表示のコントロールが出来ます。

前述のアウトラインもそうですが、0 〜 1に正規化された値を作り、その情報を元に処理を行うというのがshader処理での常套手段になります。

今回はサンプルを2つご用意しました。


通常のDissolveサンプル

NormalDissolveコンポーネントのDissolveAmountパラメータを変化させる事で挙動が確認できます。

Dissolve用テクスチャを元に表示領域をコントロールする、一般的なDIssolveのサンプルです。

DissolveRangeというパラメーターを調整する事で端の色を変化する事ができます。

動作確認方法

サンプルシーン内にあるNormalDissolve というgameObjectをご確認下さい。


Y方向のマスクと混ぜたDissolve

発表でもお見せした、DissolveにY方向のマスクを混ぜたものです。

今回、さらにuv情報をずらし、下方向に伸ばす処理をする事で溶ける感じを出しています。こうすることで見出しにある動画のような表現になります。

shaderのalphaYなどのパラメーターを画面に出力すると、マスクの状態が良くお分かりになるかと思います。

また、Dissolve用テクスチャも2種類用意しました。変更すると雰囲気が変わるのがお分かり頂けると思います。このテクスチャが重要で、テクスチャ次第で様々なパターンが作れます。

動作確認方法

サンプルシーン内にあるWithScrollY というgameObjectをご確認下さい。

Animationを再生させるか、DissolveImageコンポーネントのYAmountパラメータを変化させる事で挙動が確認できます。

パラメーター次第でmeshの範囲を超えてしまい下部でパキッと表示が切れていますが、これは次回以降にご紹介する、meshを動的に大きくする事で対応できます。

まとめ

近日中に残りのサンプルを公開していこうと思っています。このサンプルが表現の参考になれば幸いです。

以上、「Applibot Advent Calendar 2022」22日目の記事でした。ここまで読んでくださり、ありがとうございました。


関連記事一覧