Shinpy’s blog

Unityで映像とか作ってます。

URPでImageコンポーネント同士でブラー処理を入れる話

Imageコンポーネント同士でブラー処理をかけたくなったので作ってみました。
BRPには便利な関数があったんですけどパフォーマンス的に廃止され、URP環境で使えなくなりました。
とはいえ背景の色の取得はできるみたいなのでどうにかして実装してみましょう。

そもそもの使い方編

まずどうやってやればいいんでしょう。
純粋にブラーを使う方法はネットに結構落ちてるので今更ですけどまとめてみましょう。

こちらを参考に組んでみます。
https://matcha-choco010.net/2018/11/06/unity-lwrp-cameraopaquegexture-grabpass/

1 プロジェクト作成

まずプロジェクトを作りますが、 3D(URP)テンプレート を選んでください。
後述しますが、おそらくパイプラインアセットの関係で上手くブラーがかけれません。

2 パイプラインアセット設定

続いて使用するパイプラインアセットの設定をします。
どれか分からなくなったら プロジェクト設定/グラフィック にある スクリプタブルレンダーパイプライン設定 にアタッチされてるので確認できます。

見つかったらインスペクター上の不透明テクスチャをオンにしましょう。
これをすることで後にシェーダーからカメラ画像を取得することができます。

3 シェーダー作成

続いてシェーダーを作ります。
Unlit で作ると綺麗な透明になりますが、最初は上手くできたか分からないのであえてLitにしておきましょう。

作ったらグラフインスペクターから サーフェスタイプ を透明にしましょう。

続いてカメラ映像をテクスチャで取得できるようにします。
先に不透明テクスチャを設定しておくことで _CameraOpaqueTexture にカメラ映像を焼いてくれます。
Texture2D パラメータを準備したら Reference の文字を _CameraOpaqueTexture に置き換えます。
これで内部で生成されたテクスチャと紐づけて取得できるようになります。

あとは座標データがあれば設定できるので、一番簡単な構成で実装します。

4 動作確認

マテリアルにシェーダーを適用させてみます。

いいですね。ちゃんとカメラから見て後ろの映像に処理がかけれてます。

本番編

使い方が分かったところで目的達成を目指します。
目指すところはImageコンポーネントを重ねてグラスモーフィズムっぽいことをすることです。

こういう感じで上に重ねたオブジェクトで下のオブジェクトをぼかすことをします。

やり方

とりあえずCanvasはそのままワールド空間で、雑にImageコンポーネントにスプライトを入れてみます。

後ろのワールドは処理が入ってますね。
しかし肝心のスプライトに処理がかかってません。
っていうか描画が上書きされてますね。

それもそのはず。
そもそもこの処理はシェーダーを適用させたオブジェクトの座標からカメラ映像をテクスチャにしてます。この時不透明テクスチャが対象になっているので、そもそもテクスチャじゃないスプライトの情報が焼かれなくても納得です。
(詳しい原理は分からないのでまた調べますorz)

じゃあテクスチャにすればいいんか?ってことでマテリアルにしてみましょう。

はい。できました。

え?これでできるの??
ってびっくりしました。

しかしこのままだとスケールが違いすぎて調整しにくいですね。
というか調整できないので使い物になりません。

そこでCanvasの設定を見直します。

今まではワールドスペースでしたが、スクリーンスペース-カメラにしてみます。

おお!いい感じですね。


パラメータもしっかり解像度の値になって扱えるようになりました。


スクリーンスペースでやっているので通常のメッシュオブジェクトとは別で扱えます。
つまり目的だったImageコンポーネント同士のブラー処理ができたわけです。

感想

意外とさくっと実装できました。
てっきりメッシュにしか対応できないと思ってたので特別な処理が必要かな、なんて考えてましたけど、描画方法を見直すだけでしたね。
レイヤー分けとかでもできそうでしたがGUIを実装したくて作ってるので使用感が変わるのはちょっとって感じです。
メッシュオブジェクトと併用せずGUI単体ならワールドスペースでもよさそうですね。

ともあれこれでGUI上でブラーができました!今回はPosterizeを使いましたが、ガウシアンブラーを組み込んだりもできるはずなので、今度やってみようと思います。

以上です!