丸2日間ずっとやってて、結局解決できないので、どこかに書いて終わりにしようと思いました。
南無。
背景
uGUIを表示したら、後ろをブラーで隠したいじゃないですか。隠したい!
そのまた上にuGUIを置いたら、その裏も隠したい!
VRで!
MetaQuest2, 2022.2, 2023.3, URP, SinglePassInstanced, XRInteractionToolkit
実践
ブラー処理自体はどうやるかというと、
画面をキャプって、そのキャプったテクスチャをぼかして、UI矩形に合わせて表示します。
それ以外知りません。言葉にすると簡単なのですがしぇーだは複雑になります。
ビルトインコンロRPのころはすごい簡単にできました。
GrabPass { }
っていうすごいやつがいて、どこでも画面キャプチャが取れたんです。
それが、URPもといSRPではどうもこいついなくなっちゃったみたいなんですよね・・・?(不安)
ではどうするのか。画面を取る方法は調べたところ、2つある。
1.URPコンフィグにあるOpaqueTextureをチェックつけると使える_CameraOpaqueTextureを使う。
しかし_CameraOpaqueTextureにはUIは映らない。つまりこういうことです。
不透明オブジェクト描画 > 【ここでキャプチャ】 > 透明オブジェクト描画(UIとか)> ...
UIが映る前のキャプチャなんです。南無。
2.画面をGrabするカスタムRendererFeatureを実装する。
れんだらふゅーちゃー・・・?ビルトインコンロRPのときに炒めてたCommandBufferという柔軟に描画処理をコントロールできる機能がありました。それのSRP版といったところでしょうか。(違ってたらすみません。)
それを使えば画面をキャプれるそうですが、なんと公式にすごく丁度いいサンプルがありました。嬉しい。
https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/containers/create-custom-renderer-feature-1.html
長い!後半のVolumeの拡張のところは要りません。
RendererFeatureのことはほとんど知らない状態でしたが、コピーコピーで改造してできた・・・!
あれ?
VRじゃ映んないんですよね。なぜなんでしょう。諦めてます・・・とほほ。
補足
ところで、スタック可能と言っていますが、ブラーは1つしか使わないなんちゃって仕様になっています。
まず、UI2というレイヤーは標準では描画しないように設定します。
次に、RenderObjectsというRendererFeaturerでUI2を描画します。ブラーUIがでてくるまでおねんねしてます。
ランタイムでの流れは、
・画面のキャプチャを取る。
・ブラーUIを表示。
・RenderObjectsをSetActive(true)
・(更に上にスタックする場合)表示されてるUI2オブジェクトをUIレイヤに変更してブラーUIのみ非表示。(キャプチャループするから)
・新しいUI2を表示させる。
こんな感じでがちゃがちゃやっていい感じにできました。ですがVRでできなければ意味がない。もう少し考えたいけどノータイムによりフィニッシュです。薄暗くすっか!
https://github.com/emptybraces/Unity-URP-Stackable-UI-Blur
https://forum.unity.com/threads/blitter-blitcameratexture-seems-to-fail-for-vr-devices-only.1526263/
追記
下記のコードが上手く機能していないようです。
Blitter.BlitCameraTexture(cmd, camera_target_handle, _grabRTHandle, _material, 0);
そこで色々試してみたら、RendererFeatureの実行タイミングがBeforeRenderingSkybox以下であればこのBlit処理が成功しました。はて・・・
追記2
解決しました。RenderTextureの生成オプションにSPI用に追加で設定しないといけなかったみたいです。ランタイム時にSPIかどうか調べる方法が分からなかったのでシンボルで分岐しました。また、MultiPassでは動作していたことを今知った。(MultiPassは現在制作中のプロジェクトでは度外視してて調べても見てなかった。)
#if VR_SPI
_blurTextureDescriptor.volumeDepth = 2;
_blurTextureDescriptor.dimension = TextureDimension.Tex2DArray;
#endif
参考