URP + 2DRenderer にすると _OpaqueueTexutre が利用できない(設定しても画像が設定されない)ため旧来の GrabPass を使用したレンダリング結果に対して効果をつけることが直接はできませんでした。旧来、対処法として RenderTexture を使用した実装などで少し工夫が必要でしたが、最近は _CameraSortingLayerTexture という変数によって _OpaqueueTexutre のようなことができるようなり、これを使用して画面にモザイクやブラーをかけることが可能になりました。
今回は、URP + 2DRenderer + ShaderGraph で画面にモザイクやブラーをかけてみたいと思います。
実装後のイメージは以下の通りです。ちなみにシャドーキャスターやスポットライトにも効果がかかっています。
確認環境
- Unity 2021.2.5f1
- Universal RP 12.1.2
- Visual Studio 2019
- Windows10
補足: 古い URP(たぶん11.0より前)だとこの方法使用できない?(というか12.0より前だと不具合多数)っぽい?のでURPは念のため 12.0 以上を使用して実装しています。
シーンセットアップ
まず、Renderer 2D Data > Camera Sorting Layer Texture > Foremost Sorting Layer を Disable から Default に変更します。
こうすることでシェーダーのパラメーターで _OpaqueTexture の代わりの _CameraSortingLayerTexture という変数が使用可能になります。
次に SortignLayer を追加します。今回は以下のように最前面を表す TopMost をレイヤーとして追加します。
次にシーンに Canvas を配置してシェーダーを適用する Image を配置します。
Canvas には先ほど追加した Sorting Layer の TopMost を設定しておきます。
また、画面上には適当な位置に Image を配置しておきます。
参考のため Light を以下のような形状で配置し任意のオブジェクトに ShadowCaster 2D を設定しスポットライトから影が落ちている状態にしておきます。
この時、描画結果に正しくライトと影の情報を反映させるために、中央のスポットライトは Target Sorting Layer は TopMost を含む All に
Shadow Caster 2D の影は TopMost を含まないように設定しておきます。
画面にモザイクをかける
準備編
新規に Sheder Graph と Material を作成し、Material に Shader Graph を設定します。
まずシェーダーグラフを適当に作成し「ShaderGraph_Mosaic」という名前で保存します。
次に Material を作成し「Materia_Mosaic」という名前で保存します。
作成した Material に「ShaderGraph_Mosaic」を設定します。
次に Image にこのマテリアルを設定します。
そうすると画面上の Image が灰色になるのでこれで準備は完了です。
ShaderGraph編
上記で準備した「ShaderGraph_Mosaic」をダブルクリックしてシェーダーグラフのエディタを開きます。
右側の Graph Inspector から Graph Setting を以下画像の通り設定します。
- Material:Sprite Unlit
次に、通常左側にあるペインから「+」>「Texture2D」を選択します。
追加した Texture2D を選択して右側の Inspector から以下画像の通り入力します。
- Name:CameraOpaque (← 何でもよい)
- Reference:_CameraSortingLayerTexture
- Exposed:チェックOFF
エディタ上に以下の通りノードを配置します。
そして Sample Texutre2D ノードの出力を Fragment の Base Clolor に設定します。
これで「Save Asset」を選択してシーンビューに戻ると Material を設定した Image の領域だけモザイクがかかっていると思います。
シーンビューで既にモザイク模様が確認できます。
画面にブラーをかける
いわゆるすりガラスシェーダーですがあんまりうまくできなかったので参考程度としてください。
綺麗なブラーをかける方法は以下記事で紹介しているので以下は参考程度としてください。
準備編
ブラー用の ShaderGraph と Material を準備し Image に設定します。モザイクシェーダーの時と同じく「ShaderGraph_Blur」と「Materia_Blur」を作成します。
マテリアルに先ほどと同じく ShaderGraph を設定し Image の Material に設定します。
名前は「ShaderGraph_Blur」と「Materia_Blur」で作成します。
イメージにマテリアルを設定したらモザイクの時と同じように今度も灰色の状態になっていると思います。
ShaderGraph編
上記で準備した「ShaderGraph_Mosaic」をダブルクリックしてシェーダーグラフのエディタを開きます。
右側の Graph Inspector から Graph Setting を以下画像の通り設定します。
- Material:Sprite Unlit
次に、通常左側にあるペインから「+」>「Texture2D」を選択します。
追加した Texture2D を選択して右側の Inspector から以下画像の通り入力します。
- Name:CameraSortingLayerTexture(← 何でもよい)
- Reference:_CameraSortingLayerTexture
- Exposed:チェックOFF
次に外部からブラーの強度を設定できるように Float 変数を追加します。
Graph Inspector の値は以下の通りです。
- Name:Blur
- Reference:_Blur
- Default:0
- Min:0
- Max:30
- Mode:Slider
次にノードを以下の通り設定します。
LoopX のカスタムファンクションノードは配置時に以下を設定します。
LoopY のカスタムファンクションノードは配置時に以下を設定します。
カスタムノードは Type を String にすると Body という欄が出てきてそこにシェーダーのコードを直接記入できるので以下を設定します。
LoopX 用のコード
// LoopX のコード col = (0, 0, 0, 0); float weight_total = 0; float uvPitchX = 1 / _CameraSortingLayerTexture_TexelSize.w; for (float x = -blur; x <= blur; x += 1) { float distance_normalized = abs(x / blur); float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0); weight_total += weight; float4 pos = grabPos; pos.x = grabPos.x + (x * uvPitchX); col += SAMPLE_TEXTURE2D(grabTexture.tex, grabTexture.samplerstate, grabTexture.GetTransformedUV(pos.xy)) * weight; } col /= weight_total;
上記をBodyに張り付けます。
LoopY 用のコード
col = (0, 0, 0, 0); float weight_total = 0; float uvPitchY = 1 / _CameraSortingLayerTexture_TexelSize.w; for (float y = -blur; y <= blur; y += 1) { float distance_normalized = abs(y / blur); float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0); weight_total += weight; float4 pos = grabPos; pos.y = grabPos.y + (y * uvPitchY); col += SAMPLE_TEXTURE2D(grabTexture.tex, grabTexture.samplerstate, grabTexture.GetTransformedUV(pos.xy)) * weight; } col /= weight_total;
これも同じく Body に張り付けます。
そして各々のカスタムファンクションノードの出力を以下のように接続して Fragment の Base Color に入力します。
次に Save Asset を選択してシーンビューに戻ります。
まだシーンビュー上だと何も起きていません。
Material_Blur を選択するとのスライダーが表示されているのでスライダーの値を変更します。
スライダーを右に移動させると以下のようにブラー効果が Image の範囲に発生します。
動かすとこんな感じです。
最後に
あれ、、、マルチパスできないのかぁ…となってブラーの処理はマルチパス用をシングルパスの Add で加算したため品質が悪めですが GrabPass 代わりの処理の基本的はこのような形になると思います。
参考
以下フォーラムに 2DRenderer で _OpaqueueTexutre の代わりに _CameraSortingLayerTexture 使えよって話が議論されています。
以下参考にしています。