UnityでRGBとDepthの連番画像を出力してAfterEffectsに読み込む

Unityで動画用素材を作成するときに、AfterEffectsなどの動画編集ソフトで編集しやすいように、RGBとDepthの連番画像を出力する方法について書きます。
今回はRenderTextureに描画された1フレームごとのRGBと深度画像をEXR形式で保存するようにします。
基本的にPNGなどでも同じようにできます。
また、AfterEffectでの読み込み方も記載します。

Depthを出力できると、AfterEffectsのマスクなどで活用できるので楽しいです。

 # 実行環境
- OS Windows10
- Unity 2020.3.17f1
- AfterEffects 2021

# Unity側の準備
## Unity Recorder
UnityPackageManagerからUnity Recorderをインポートします。
インポートできたら、Unityの上部タブのWindow>General>Recorder>Recorder Window からウインドウを開いておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216020/3e4b06bd-640a-8243-289c-2062344a946d.png)

## CameraとRenderTextureの設定
RGBとDepth用のカメラを別々に作り、それぞれの出力先のRenderTextureも分けて作るようにします。
まず、RenderTextureですが、解像度は以下の画像のような設定で作ります（必要に応じて適宜変えてください）。RGB用とDepth用で2つ作っておきましょう。
そして、CameraのtargetTextureにそれぞれのRenderTextureを設定しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216020/6a3ea5f5-58a1-53cf-bc59-bd5fab40b564.png)

RGBカメラの方はこれで完了ですが、Depth出力用に以下のScriptとShaderを作成してください。
作成したScriptをDepth用のCameraにアタッチして、shaderにDepth.shaderをセットします。

- DepthRenderer.cs
```C#
using UnityEngine;

public class DepthRenderer : MonoBehaviour
{
    [SerializeField]
    private Shader _shader;
    private Material _material;

    void Start()
    {
        GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
        _material = new Material(_shader);
    }

    private void OnRenderImage(RenderTexture source, RenderTexture dest)
    {
        Graphics.Blit(source, dest, _material);
    }
}
```

- Depth.shader
```GLSL
Shader "Custom/ShowDepthTexture"
{
    SubShader
    {
        Cull Off
        ZTest Always
        ZWrite Off

        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
           #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            
            sampler2D _CameraDepthTexture;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv));
                depth = LinearEyeDepth(depth);
                return depth;
            }
            ENDCG
        }
    }
}
```
## Recorderの設定
RecorderのAdd New Recordersをクリックして、Image Sequenceを追加しましょう。
細かい設定については適宜変更していただいて構いませんが、File Nameには必ず`<Frame>
`を入れましょう。この`<Frame>
`にフレーム数が入ってファイルが出力されます。
RGBとDepthのシーケンスをそれぞれ作って別々のファイル名にしておきましょう。フォルダも分けておいた方がいいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216020/601157a8-e32a-01f5-817a-f292e36b1c70.png)
以上で設定は完了です。
# 録画
StartRecordingを押すことで、録画を開始します。
うまく録画できるとこのようなファイルが出力されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216020/60a372fa-3dc8-4680-6383-31d9b935b6b0.png)

# AfterEffectsで読み込む
出力したファイルをAfterEffectsで読み込みます。
プロジェクトを作成し、まずはRGBのファイルの読み込みを行います。
このとき、連番画像を全選択し、OpenEXRシーケンスにチェックを入れて読み込みましょう。
Depthも同様です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216020/65f3522a-0cd9-62bf-224f-c14061a82924.png)

これで読み込みは完了です。

AfterEffectsで深度情報をマスクなどで使えるようになります。

## AfterEffectsで読み込んだ画像が白飛びしている
AfterEffectsのプロジェクト設定>カラーを選択してください。
「作業用スペースをリニア可」にチェックが入っていない場合はチェックを入れましょう。