【Unity】簡単にレンダリングの品質を上げる方法

Post Processing に標準搭載されているエフェクトの品質を簡単に上げる方法です。

標準エフェクトの品質には満足してるけど、あとほんのちょっとだけ、似たようなエフェクトを再開発すせずにプロジェクト特有の問題に対処したい、という時に。

<img src="https://dl.dropbox.com/s/2flr8rgm96vujrz/PPSv2_Orb_Comparison.png" />


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">望遠だと出てくる PP Stack v2 Ambient Occlusion の同心円状のモアレ<br>消したい <a href="https://t.co/jhSRXYrxQz">pic.twitter.com/jhSRXYrxQz</a></p>&mdash; サトー (@sator_imaging) <a href="https://twitter.com/sator_imaging/status/1425805441708093441?ref_src=twsrc%5Etfw">August 12, 2021</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<!--
https://qiita.com/sator_imaging/items/1859aeaf525c864af89b
-->


### もくじ

- [はじめに](#はじめに)
- [簡単に直せるのに直せない問題](#簡単に直せるのに直せない問題)
- [正攻法で直すには](#正攻法で直すには)
- [もっと簡単に直す方法](#もっと簡単に直す方法)
- [おわりに](#おわりに)



## はじめに

Post-Processing で Ambient Occlusion の Multi-Scale Volumetric Obscurance を適用した際、カメラのレンズが 100mm を超えた辺りから ↑ に示した画像のように同心円状のモアレ、ノイズが出てしまうという問題にぶつかりました。@ Post-Processing v2.3.0

これはオクルージョンのアルゴリズムを見直せば解決できる、とか深刻なモノではなく、デプスの値をほんのちょっと弄るだけで簡単に直せる問題です。が、それが簡単なのに簡単ではないというのが問題です。


## 簡単に直せるのに直せない問題

修正は非常に簡単で、`MultiScaleVO.shader` というシェーダーにちょっとデプスをごにょる１行を加えるだけです。


そして、これは望遠レンズで撮った時に限った問題なので、このプロジェクト以外では不要なモノ、ワンオフでサクッと修正したい。ところが、、、


```hlsl
// 0 - Depth copy with procedural draw
Pass
{
    HLSLPROGRAM

    #pragma vertex VertDefault
    #pragma fragment Frag

    float4 Frag(VaryingsDefault i) : SV_Target
    {
        float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.texcoordStereo);
        
        // ↓ ↓ ↓ 追加 ↓ ↓ ↓
        d += sin(i.texcoordStereo.x * _ScreenParams.x * 2.1414) * cos(i.texcoordStereo.y * _ScreenParams.y * 2.524) * 0.00000075 * min(1, d * 100000);
        // ↑ ↑ ↑ 追加 ↑ ↑ ↑

        return d;
    }
    ENDHLSL
}
```

※ パフォーマンスは多少落ちるけど問題ない。他では使わないし。



## 正攻法で直すには

これを Post-Processing のお作法に則ってプロジェクトに適用するのは非常に面倒です。

下記の通り Post-Processing には独自のエフェクトを追加する方法が用意されていますが、

- [Writing Custom Effects | Post Processing | 2.3.0](https://docs.unity3d.com/Packages/com.unity.postprocessing@2.3/manual/Writing-Custom-Effects.html)


マニュアルにあるのはあくまで新規にエフェクトを書き起こす為の方法であり、既存のエフェクトを微調整する方法は示されていません。

--

それなら、と `Packages/` 以下のファイルを直接修正すると、Unity を再起動するたびに元の状態に戻ってしまいます。

なので、Ambient Occlusion 関係のスクリプト／シェーダーを複製して調整版エフェクトの追加を試みると、、、

- `internal` アクセスレベルなモノがあったりするので Ambient Occlusion 以外のファイルもコピー・リネームが必要。
- どんどんコピー・リネームが必要なファイルが増えていく。
- 結局全部コピー・リネームが必要っぽい。
- `Packages/` から `Assets/` に移せば `internal` も見える、けど今風じゃない。

という、非常に面倒な感じです。新たなエフェクトを作りたいのではなく、ほんのちょっとだけ手を加えたいだけなのにかなりの大事。途中でイヤになってやめました。




## もっと簡単に直す方法

幸いなことに Post-Processing Stack v2 に標準搭載のエフェクトで使用されるシェーダーは `PostProcessResources.asset` に参照の形でまとめられていたので、コチラを書き換えることで面倒なことをせずとも調整版エフェクトへの差し替えが行えます。


<!--
※ PPSv2 のシェーダーがビルドに含まれない事態が起きないように参照を持たせてるようで。結果ハードコードが防がれているのでイイですね。

--

-->

このアセットファイルもスクリプト／シェーダーと同様、Unity を再起動するたびに元の状態に戻るので `InitializeOnLoadMethod` で起動のたびに書き換えるスクリプトを用意してやります。


`MonoBehaviour` からランタイム中に書き換えても動作するようなので、シーンごと、負荷ごとにシェーダーの切り替えも出来そうです。

--

これで公式パッケージの恩恵を受けつつ、プロジェクトに合わせた微調整が簡単に行えるようになりました。

ありきたりのポストエフェクトを再開発するような無駄を省きつつ、プロジェクト特有の問題に対処できる。イイ感じですね。


```csharp
using UnityEngine;
using UnityEditor;
using UnityEngine.Rendering.PostProcessing;

public static class ReplacePostProcessingShader
{
    const string SHADER_NAME = "Hidden/Path/to/Customized/Version/of/MultiScaleVO";

    [InitializeOnLoadMethod]
    static void Init()
    {
        var GUIDs = AssetDatabase.FindAssets(nameof(PostProcessResources));
        foreach(var id in GUIDs)
        {
            var path = AssetDatabase.GUIDToAssetPath(id);
            if (AssetDatabase.GetMainAssetTypeAtPath(path) != typeof(PostProcessResources)) continue;

            Debug.Log($"GUID: {id} ({path})");

            var asset = AssetDatabase.LoadMainAssetAtPath(path) as PostProcessResources;
            var shader = Shader.Find(SHADER_NAME);
            if (null == asset || null == shader) continue;

            asset.shaders.multiScaleAO = shader;
        }
    }

}
```


## おわりに

対象が球体だから特にエラーが目立つだけ、人型キャラにちゃんとテクスチャが載ってれば目立たない（目立ちにくい）、望遠レンズを使わなければ問題なし、という特殊な事例です。



↓ 人型だったり周波数の高いテクスチャが貼られていれば目立ちにくい

![](https://dl.dropbox.com/s/0nm591y3e4nn3p3/PPSv2_Ethan_Comparison.png)
![](https://dl.dropbox.com/s/2flr8rgm96vujrz/PPSv2_Orb_Comparison.png)


Post-Processing の出力にもパフォーマンスにも不満はないけど、処理を追加したり省いたり、ほんの少しだけプロジェクト向けに調整を加えたい！ という時に使える手法じゃないでしょうか。



<!--
公式パッケージは汎用性が高くていいんですが、あとちょっと、の調整が簡単にできるようになってるとありがたいですね。全部 `public` にしちゃえばいいんじゃ無いですかね。
-->


以上です。お疲れ様でした。