URP+2DRendererで画面の一部にモザイクやブラーをかける

URP + 2DRenderer にすると _OpaqueueTexutre が利用できない(設定しても画像が設定されない)ため旧来の GrabPass を使用したレンダリング結果に対して効果をつけることが直接はできませんでした。旧来、対処法として RenderTexture を使用した実装などで少し工夫が必要でしたが、最近は _CameraSortingLayerTexture という変数によって _OpaqueueTexutre のようなことができるようなり、これを使用して画面にモザイクやブラーをかけることが可能になりました。

今回は、URP + 2DRenderer + ShaderGraph で画面にモザイクやブラーをかけてみたいと思います。

実装後のイメージは以下の通りです。ちなみにシャドーキャスターやスポットライトにも効果がかかっています。

f:id:Takachan:20211219205158g:plain

f:id:Takachan:20211219224514g:plain

確認環境

  • 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 に変更します。

f:id:Takachan:20211219204158p:plain

こうすることでシェーダーのパラメーターで _OpaqueTexture の代わりの _CameraSortingLayerTexture という変数が使用可能になります。

次に SortignLayer を追加します。今回は以下のように最前面を表す TopMost をレイヤーとして追加します。

f:id:Takachan:20211219204425p:plain

次にシーンに Canvas を配置してシェーダーを適用する Image を配置します。

f:id:Takachan:20211219205944p:plain

Canvas には先ほど追加した Sorting Layer の TopMost を設定しておきます。

f:id:Takachan:20211219210302p:plain

また、画面上には適当な位置に Image を配置しておきます。

f:id:Takachan:20211219210009p:plain

参考のため Light を以下のような形状で配置し任意のオブジェクトに ShadowCaster 2D を設定しスポットライトから影が落ちている状態にしておきます。

f:id:Takachan:20211219210215p:plain

この時、描画結果に正しくライトと影の情報を反映させるために、中央のスポットライトは Target Sorting Layer は TopMost を含む All に

f:id:Takachan:20211219210535p:plain

Shadow Caster 2D の影は TopMost を含まないように設定しておきます。

f:id:Takachan:20211219210630p:plain

画面にモザイクをかける

準備編

新規に Sheder Graph と Material を作成し、Material に Shader Graph を設定します。

まずシェーダーグラフを適当に作成し「ShaderGraph_Mosaic」という名前で保存します。

f:id:Takachan:20211219210926p:plain

f:id:Takachan:20211219211033p:plain

次に Material を作成し「Materia_Mosaic」という名前で保存します。

f:id:Takachan:20211219211124p:plain

f:id:Takachan:20211219211201p:plain

作成した Material に「ShaderGraph_Mosaic」を設定します。

f:id:Takachan:20211219211259p:plain

次に Image にこのマテリアルを設定します。

f:id:Takachan:20211219211414p:plain

そうすると画面上の Image が灰色になるのでこれで準備は完了です。

f:id:Takachan:20211219211350p:plain

ShaderGraph編

上記で準備した「ShaderGraph_Mosaic」をダブルクリックしてシェーダーグラフのエディタを開きます。

右側の Graph Inspector から Graph Setting を以下画像の通り設定します。

  • Material:Sprite Unlit

f:id:Takachan:20211219212233p:plain

次に、通常左側にあるペインから「+」>「Texture2D」を選択します。

f:id:Takachan:20211219211846p:plain

追加した Texture2D を選択して右側の Inspector から以下画像の通り入力します。

  • Name:CameraOpaque (← 何でもよい)
  • Reference:_CameraSortingLayerTexture
  • Exposed:チェックOFF

f:id:Takachan:20211219211917p:plain

エディタ上に以下の通りノードを配置します。

f:id:Takachan:20211219212142p:plain

そして Sample Texutre2D ノードの出力を Fragment の Base Clolor に設定します。

f:id:Takachan:20211219212433p:plain

これで「Save Asset」を選択してシーンビューに戻ると Material を設定した Image の領域だけモザイクがかかっていると思います。

f:id:Takachan:20211219212512p:plain

シーンビューで既にモザイク模様が確認できます。

f:id:Takachan:20211219212533p:plain

画面にブラーをかける

いわゆるすりガラスシェーダーですがあんまりうまくできなかったので参考程度としてください。

綺麗なブラーをかける方法は以下記事で紹介しているので以下は参考程度としてください。

takap-tech.com

準備編

ブラー用の ShaderGraph と Material を準備し Image に設定します。モザイクシェーダーの時と同じく「ShaderGraph_Blur」と「Materia_Blur」を作成します。

f:id:Takachan:20211219213013p:plain

マテリアルに先ほどと同じく ShaderGraph を設定し Image の Material に設定します。

名前は「ShaderGraph_Blur」と「Materia_Blur」で作成します。

f:id:Takachan:20211219213047p:plain

イメージにマテリアルを設定したらモザイクの時と同じように今度も灰色の状態になっていると思います。

f:id:Takachan:20211219211350p:plain

ShaderGraph編

上記で準備した「ShaderGraph_Mosaic」をダブルクリックしてシェーダーグラフのエディタを開きます。

右側の Graph Inspector から Graph Setting を以下画像の通り設定します。

  • Material:Sprite Unlit

f:id:Takachan:20211219212233p:plain

次に、通常左側にあるペインから「+」>「Texture2D」を選択します。

f:id:Takachan:20211219211846p:plain

追加した Texture2D を選択して右側の Inspector から以下画像の通り入力します。

  • Name:CameraSortingLayerTexture(← 何でもよい)
  • Reference:_CameraSortingLayerTexture
  • Exposed:チェックOFF

f:id:Takachan:20211219213511p:plain

次に外部からブラーの強度を設定できるように Float 変数を追加します。

f:id:Takachan:20211219213606p:plain

Graph Inspector の値は以下の通りです。

  • Name:Blur
  • Reference:_Blur
  • Default:0
  • Min:0
  • Max:30
  • Mode:Slider

f:id:Takachan:20211219213634p:plain

次にノードを以下の通り設定します。

f:id:Takachan:20211219213822p:plain

LoopX のカスタムファンクションノードは配置時に以下を設定します。

f:id:Takachan:20211219213905p:plain

LoopY のカスタムファンクションノードは配置時に以下を設定します。

f:id:Takachan:20211219214014p:plain

カスタムノードは 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に張り付けます。

f:id:Takachan:20211219214322p:plain

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 に張り付けます。

f:id:Takachan:20211219214250p:plain

そして各々のカスタムファンクションノードの出力を以下のように接続して Fragment の Base Color に入力します。

f:id:Takachan:20211219214427p:plain

次に Save Asset を選択してシーンビューに戻ります。

f:id:Takachan:20211219214515p:plain

まだシーンビュー上だと何も起きていません。

f:id:Takachan:20211219214700p:plain

Material_Blur を選択するとのスライダーが表示されているのでスライダーの値を変更します。

f:id:Takachan:20211219214733p:plain

スライダーを右に移動させると以下のようにブラー効果が Image の範囲に発生します。

f:id:Takachan:20211219214825p:plain

動かすとこんな感じです。

f:id:Takachan:20211219224514g:plain

最後に

あれ、、、マルチパスできないのかぁ…となってブラーの処理はマルチパス用をシングルパスの Add で加算したため品質が悪めですが GrabPass 代わりの処理の基本的はこのような形になると思います。

参考

以下フォーラムに 2DRenderer で _OpaqueueTexutre の代わりに _CameraSortingLayerTexture 使えよって話が議論されています。

forum.unity.com

以下参考にしています。

qiita.com