【Unity】特定のLayerだけPostProcessを適用する

こんにちはっ🌟八ツ橋まろんです

今回はUnityで『特定のレイヤーだけPostProcessを適用する』方法の解説です。
対象は
・PostProcessingStack
・Layer
がわかる人です。

#概説

そもそも特定のLayerだけPostProcessを適用したい時ってどんな時よ？って人向けの画像は以下です↓↓↓↓↓↓↓↓
![2020-10-12_21-40-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478685/4c9f84f8-1ce3-9faa-2d5e-712119aa9b61.png)


ここでは眼とペンダント以外の全てのオブジェクトにPostProcessをかけて見た目をグレースケールにしています。かっこいい✨！！

UnityのPostProcessingStackはとても便利で使いやすいですが、基本的には「描画した全てのオブジェクトに対して適用されるもの」なので、特定のオブジェクトだけに適用することはできないのですが、CameraとLayerを使うことで疑似的に実現していきます。

#やり方

🌟Cameraを3つ用意します。以下のように、どれか一つを親にして残りを子にしておくと後で楽です。
![ｇｒｇ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478685/c6552e51-95f2-0837-20cd-7593ad7c271c.png)

・1つめ：通常描画用のCamera
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478685/cdf1e4ea-ed47-06b7-ae8c-d6c449e579e8.png)
Clear Flags: Don't Clear
Culling Mask: PostProcessをかけたいオブジェクト以外を描画
Depth: 1

・2つめ：PostProcess適用する用のCamera
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478685/381f1140-d2fc-8c7b-1ed4-e6dfac75bd7d.png)
Clear Flags: Don't Clear
Culling Mask: PostProcessをかけたいオブジェクトのみを描画
Depth: 0
PostProcessgLayer Componentを付ける

・3つめ：Skybox描画用のCamera
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478685/7853a8c0-2e83-8e54-2189-0b7ae1b540c9.png)
Clear Flags: Skybox
Culling Mask: Nothing
Depth: 指定なし
Target Texture: 1920x1080など、Game画面に合わせた適当なRenderTextureを選択

🌟Canvas (Raw Image)を用意します。Skybox描画用です。
・Raw Image：上記のRenderTextureを指定し、サイズはGame画面と同じに。
・Canvas：Render Mode: Screen Space-Cameraで1つ目のカメラを指定

🌟PostProcessingVolumeを用意します。設定は自由です。

これで準備は完了です。2つ目のカメラに映るオブジェクトだけがPostProcessの影響を受けます。

#解説

・Game画面に映るのはHierarchyにあるCameraに映るものをDepthの小さい順に並べた映像になります。

・Cameraが2個以上ある場合、デフォルトではClear FlagsがSkyboxなので、Depthの値が最も大きいCameraの映像のSkyboxによってそれ以外のCamera映像は上書きされ、Game画面に映りません。

・Clear FlagsがDon't ClearのCameraの映像は背景が透過した映像になるので、Game画面にはDepthの小さいCameraの映像も一緒に映ります。

・今回は2つ目のカメラにPostProcessが付いているため、それ以下のDepth値のCameraに映るオブジェクトは全てPostProcessが適用されます。
(Depthが-3,-2,-1,0のCameraがあったとして、-1のCameraにPostProcessが適用される場合、Depthの小さい順に描画するため-1のCamera描画時には-3と-2の映像は既に描画されており、その映像と-1のCamera映像をまるっと含めてPostProcessが適用される)

・その性質上、SkyboxはDepthが最も小さいCameraで描画しないといけないですが、そうするとどうしてもPostProcessに影響されてしまうので、RenderTextureに描画して、Canvasを使ってDepthの高いCameraのScreenSpaceに描画することで、Depthが高く且つPostProcessよりも後に描画するという回避を行っています。

解説は以上となります。

#その他応用
・親子構造にしたため、CinemachineなどでCameraを動かしたい場合、親のCameraを動かすことで子も一緒に追従するので便利です。
・CameraのField of viewなどのパラメータを変更したいとき、3つのCameraを全て変更しないといけませんが、以下のようなスクリプトを書けば親の変更が子に適用されるので便利です。([ExecuteAlways]のためEditor上でも動きます)

```c#:CameraParamSync.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteAlways]
public class CameraParamSync : MonoBehaviour
{
    [SerializeField]
    Camera ParentCamera;
    [SerializeField]
    Camera[] ChildCamera;

    void Update()
    {
        if (ParentCamera != null && ChildCamera != null)
        {
            for (int i = 0; i < ChildCamera.Length; i++)
            {
                ChildCamera[i].fieldOfView = ParentCamera.fieldOfView;
                ChildCamera[i].nearClipPlane = ParentCamera.nearClipPlane;
                ChildCamera[i].farClipPlane = ParentCamera.farClipPlane;
            }
        }

    }
}

```

・HDRPの場合、Clear Flags: Don't Clearがないためこのままのやり方は適用できませんが、RenderTextureを複数枚使うことで上手く動かせると思います。

以上『特定のLayerだけPostProcessを適用する』でしたっ🌟

八ツ橋まろん
[Twitter](https://twitter.com/Maron_Vtuber)
[YouTube](https://www.youtube.com/channel/UCiIbLpncjzahHsp8cokG56g)