Unity Recorder の使い方

## はじめに

この記事は [Unity アセット真夏のアドベントカレンダー 2018 Summer!](http://assetstore.info/eventandcontest/adventcalendar/asset-adventcalendar2018summer/) の 24 日目の記事です。

2018 年に入って Unity に VR 動画を作成する機能が搭載された、という話をきっかけに半年くらいそんなことばっかりやってて Qiita に何本か記事を書きました。

* [Unity 2018.1 でステレオ VR 動画を作成する](https://qiita.com/tan-y/items/ea824684077b0a544421)
* [Unity 2018.1 で VR180 動画を作成する](https://qiita.com/tan-y/items/c4b09d2f92a60fda6113)
* [Unity でステレオ VR 動画を作成する (ほぼ完全 (?) 版)](https://qiita.com/tan-y/items/941de5c8bc3309f835d5)

これらの記事は VR 動画の作成に焦点をあてて作成していますので、 VR 動画に興味のある方は是非一度お読みください。

今回はここまでさんざんお世話になった Unity Recorder について、まとめていきたいと思います。  VR 動画は横に置いておいて、アセット全般的にふれていきます。

## Unity Recorder とは

* [Unity Recorder](https://assetstore.unity.com/packages/essentials/unity-recorder-94079)

![img01.png](https://qiita-image-store.s3.amazonaws.com/0/211064/f2a58cab-5a1c-7387-37a7-785dcdacffda.png)

Unity Recorder は Unity Editor 上で実行したシーンのレンダリング結果等をキャプチャーし、静的なファイル等に保存するためのアセットです。 主な用途は 2 つあります。

* 実行したシーンのレンダリング結果をキャプチャーし、動画ファイルなどに出力する。
* 特定の GameObject の動きをキャプチャーし、 Animation Clip に出力する。

基本的には Unity Editor をコンテンツ制作のツールとして利用するためのものです。

先日、正式版として 1.0 が公開されましたがそれまで公開されていた実験版とは UI からして別物のようなものになりました。また、 1.0 より GitHub でのコードの公開はなくなったようです。従来の実験版は下記にてソースコードが公開されています。

* [Unity-Technologies/GenericFrameRecorder](https://github.com/Unity-Technologies/GenericFrameRecorder)
* [unity3d-jp/FrameCapturer](https://github.com/unity3d-jp/FrameCapturer) (GenericFrameRecorder 以前のキャプチャーアセット)

## 基本的な使い方

[アセットストア](https://assetstore.unity.com/packages/essentials/unity-recorder-94079) からダウンロードし、キャプチャしたいコンテンツのあるプロジェクトにインポートしてください。

(※2019/5/6 追記) Unity 2019.1 以降は Package Manager からインストールします。アセットストアのものは入れても動作しないので注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/043cde48-8ad7-ed8c-5b3a-27c14bbc11ad.png)

インポートするといくつかの機能が使えるようになります。

なお、 Unity 本体は可能な限り新しいバージョンを使った方がよさそうです。 (今回の記事では基本的には 2018.2.3f1 を利用しています)

### カメラから映像をキャプチャーする

一番基本的な機能で最も使用するものではないかと思います。

![img02.png](https://qiita-image-store.s3.amazonaws.com/0/211064/a05c8a0a-a148-285d-8ac2-eaed94faaeb4.png)

メニュー "Window - General - Recorder - Recorder Window" (2018.1 以前は General はありません) で設定パネルが表示されるので、適切に設定をし "START RECORDING" ボタンを押すとシーンの実行とそれに合わせてキャプチャーが開始されます。 "STOP" を押すかアプリケーションが終了するとキャプチャーも停止します。

![img03.png](https://qiita-image-store.s3.amazonaws.com/0/211064/145400fa-569b-907e-013f-52ff49bd3fdf.png)

1. "Add New Recorders" を押すと追加する Recorder を選択するメニューが出るので任意のものを選択する。
    * 動画ファイルを出力する場合は "Movie"
    * 連番静止画ファイルを出力する場合は "Image Sequence"
2. "Format" で出力するファイル形式を選択する。
3. "File Name", "Path" で出力先を設定します。最終的に確定する出力先がフルパスで表示されているので、そちらも合わせて確認。
4. "Capture" でキャプチャー元となるソースを選択します。
    * Game View - Game View に表示されている映像をキャプチャーします。
    * Targeted Camera - 指定のカメラの映像をキャプチャーします。特定のカメラを固定的にキャプチャーすることもできます。
    * 360 view - いわゆる VR 動画 (equirect angular) 形式の映像に変換してキャプチャーします。カメラから直接キャプチャーしているわけではなく、挙動的には Render Texture Asset に近いものになっています。
    * Render Texture Asset - 指定の RenderTexture をキャプチャーします。

とりあえず映像をキャプチャーしたい場合は

* 動画の場合は "Movie" で Format が "MP4"
* 連番静止画の場合は "Image Sequence" で Format が "JPEG" もしくは "PNG"
* Capture では "Game View" を選択。 Output Resolution は任意のもので。

他はデフォルトでよいと思います。

パネル上段の "Frame Rate" は Constant にして、 Target でキャプチャーしたいフレームレートを指定してください。基本的に速度より品質を優先すべきと思いますが、リアルタイム性を優先したい場合は Variable にするとよいと思います。

"Capture" で "Targeted Camera" または "360 view" を指定した場合、 Source を "MainCamera" にすると Tag が "MainCamera" のものを対象にするようになります。 "MainCamera" のタグがついたカメラがないと実行時エラーになります。同様に "Tagged Camaera" で指定した Tag のカメラがない場合もエラーになりますので注意。

### タイムラインから映像をキャプチャーする

タイムラインに対してキャプチャーの指定をするとタイムラインの特定範囲のみをキャプチャーすることができます。

1. キャプチャー対象の Timeline を開く。  
![img04.png](https://qiita-image-store.s3.amazonaws.com/0/211064/226b4606-d484-be2f-b754-98e91315a5d7.png)
2. "Add" ボタンを押し、 "UnityEditor.Recorder.Timeline - Recorder Track" を選択。  
![img05.png](https://qiita-image-store.s3.amazonaws.com/0/211064/eb957023-d504-ff1d-96ea-81e10d4ae620.png)
3. 追加された Recorder Track 上で右クリック "Add Recorder Clip" を選択。
4. 追加された "Recorder Clip" を録画したい位置、範囲になるように調整する。  
![img06.png](https://qiita-image-store.s3.amazonaws.com/0/211064/fbd17584-1829-885e-d2cc-c97049826ed4.png)
5. Recorder Clip の Inspector で Recorder Window と同様の出力設定項目があるので、希望の設定をする (前項を参照) 。
6. Unity Editor で Play をする (Timeline の Play は不可) 。 Recorder Clip で指定した範囲に来るとキャプチャーされます。

キャプチャーするのにシーン全体の再生が必要になるのがちょっと使い勝手悪い感じですね・・・

### Game Object の動きを Animation Clip に記録する

Unity Recorder の面白いところは、映像や音声のレンダリング結果をキャプチャーするだけではなく、 Game Object の動きを Animcation Clip に記録することができることです。 Blog によると Animation Clip だけではなく FBX もサポートする方針のようですが、 1.0.1 現在はサポートされていないようです。

* [Unity 2018.2、リリース](https://blogs.unity3d.com/jp/2018/07/10/2018-2-is-now-available/)

使い方は映像系と大体同じです。

![img07.png](https://qiita-image-store.s3.amazonaws.com/0/211064/eff92055-8d52-12d0-782e-d10f1deded19.png)

1. "Add New Recorders" で "Animation Clip" を追加する。
2. "Game Object" に記録対象の Game Object を指定する。
3. "START RECORDING" ボタンを押して記録開始。

タイムラインでも利用可能です。

出力された Animation Clip はそのまま利用可能ですので、録画対象にしていた Game Object で Animation が適用されるように設定して実行すると記録した通りの動きが再現されます。

## Tips

### 連番静止画出力を利用する

最終的にビデオファイルとして残すことになると思いますが、 Recorder アセット上で直接 MP4 で録画すると画質的に満足できない可能性が高いです。連番静止画で録画し、別途エンコーダーアプリケーションで MP4 などにエンコードすることをお勧めします。

ただ、 1.0.1 の段階では Audio Recorder がなくなっているので音声のキャプチャーができません。音声のキャプチャーをする場合は映像側を負荷のかからない低画質キャプチャーをする Movie 出力で行い、出力した MP4/WEBM ファイルの音声のみを利用するといった形になるかと思いますがこの段階で AAC 等にエンコードされてしまっているのでベストとはいえない状況になっています。

### RenderTexture をソースにする

通常は "Game View" や "360 View" をソースにすると思いますが、意図した映像がキャプチャできないケースがありました。 

* Unity Recorder がキャプチャするタイミングのレンダリング状況が最終パスのものではなかった
* 透明な PNG 画像 (α値が 0) がキャプチャされた
* ガンマが意図通りにならないことがあった
    * Game View ではガンマがかかった映像がキャプチャされた (ディスプレイ出力の映像だから)
    * 360 View では sRGB ガンマではなくリニアのまま出力された (おそらく内部的に中間バッファで RenderTexture にレンダリングしてそのまま出力している)

そういった場合、 RenderTexture にレンダリングをし、それを Recorder アセットでキャプチャーすることで回避しました。 RenderTexture にレンダリングする事を自前で行うことで、意図した映像をキャプチャーする事を目的としています。特にリニアで取得したい場合は必須と思われます。

流れ的には

1. プロジェクトに Render Texture を用意する。
    * Size は出力したい映像サイズに合わせる。
    * Color Format は通常は "ARGB32" でよいですが、  HDR を扱う場合は "ARGB Float" にする。
2. 用意した RenderTexture にレンダリングする仕組みを入れ込む。
3. Unity Recorder の Capture を "Render Texture Asset" にし、 "Render Texture" に用意した RenderTexture を指定する。
4. キャプチャー実行。

のような形になります。

RenderTexture へのレンダリングは次の 2 通り。

* Camera の Target Texture に RenderTexture を指定する。
* 任意のタイミングで RenderTexture にレンダリングするコードを実装する。

ガンマの問題だけであれば前者のやり方でよいと思います。後者は自前で VR 映像のキャプチャーをする場合など、通常の Camera のレンダリングで対処できない場合に適用します。

RenderTexture を通すと "Capture Alpha" の設定に関わらずα値がそのまま出力されてしまう (ので PNG や EXR だと困ることがある) ので OnRenderImage を使って加工をした方がよいケースもあります。

* Shader
    1. Unlit シェーダーを追加する (ここでは名前は PostEffect にしました)
    2. Fragment シェーダーの戻りを次のようにする (αを単純に不透明にする場合の例)

```glsl
return fixed4(col.xyz, 1.0);
```
* C#
    * C# Script を追加、次のようなコードを実装してキャプチャー対象のカメラに追加する。

```csharp
using UnityEngine;

public class PostEffect : MonoBehaviour
{
    private Material _material = null;

    private void Awake()
    {
        _material = new Material(Shader.Find("Unlit/PostEffect"));  // .shader の定義名に合わせる
    }

    private void OnDestroy()
    {
        if (_material != null)
        {
            Destroy(_material);
            _material = null;
        }
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(source, destination, _material);
    }
}
```
 
### OpenEXR 出力を活用して HDR 動画を作成する

一般的に扱いやすい画像形式は PNG/JPEG ですが、 Unity Recorder では OpenEXR 形式でファイル出力をすることができます。

 OpenEXR は映像を HDR で記録することができますので、うまく使えば Unity で HDR ビデオを作成することも可能でしょう。 Unity は中間レンダリングは HDR で行えますが、ディスプレイ (Game View) への出力は HDR に対応してなく、 SDR へトーンマッピングすることになります。そこで SDR へのトーンマッピング前の映像をうまい事 Unity Recorder でファイルに落として HDR の画像ファイル (ピクセルの輝度値が 1.0 を超える画像) を取得します。

ポイントは

* "Project Settings - Player" の Color Space は Linear にする
* Render Texture を通したキャプチャーにする (前項を参照)
    * RenderTexture の Color Format は "ARGB Float" にする。
    * 特に必要なければ Camera の Target Texture に RenderTexture を設定するやり方でレンダリングする。

また、 Render Texture を通してキャプチャーするとまさに "そのまま" 出力されてしまうのでα値が 1.0 より大きい値になることがあります。出力した OpenEXR を処理するアプリケーションによってはそのような画像だと適切に処理をしてくれない場合もあります。よって必須ではないですが OnRenderImage を使ってα値を調整した方がよいでしょう (前項参照)。

![img08.png](https://qiita-image-store.s3.amazonaws.com/0/211064/ec8bb75c-cfbc-7879-5c59-3d439e02a153.png)
![img09.png](https://qiita-image-store.s3.amazonaws.com/0/211064/48da3050-a826-9b95-d034-3880a0afe38c.png)

キャプチャーした EXR は "DJV Imaging" というオープンソースのビューアーを使うと HDR になっているかどうかの確認ができますのでお勧めです。

* [DJV Imaging](http://djv.sourceforge.net/)

![img10.png](https://qiita-image-store.s3.amazonaws.com/0/211064/2ac20c49-bb2d-9b61-b8b7-0fbc3c14518f.png)

表示している映像の任意位置でマウスボタンを押下するとステータスバーにその位置のピクセルの輝度値が表示されますので、明らかに輝度値が SDR 越えしていると思う部分をチェックしてみてください。

![img11.png](https://qiita-image-store.s3.amazonaws.com/0/211064/a244e361-3124-8195-3571-447d25a9bbfb.png)

OpenEXR の設定で Color Profile を "None" にするとリニアで確認できます。デフォルトは "Gamma" になっているので変更することをお勧めします。 (上記輝度値の表示も Color Profile 設定の影響を受けます)

Windows 10 で HDR ディスプレイ環境を用意されている方は HDRImageViewer を使うと HDR 環境でのプレビューができます (DJV Imaging でのレンダリングは SDR のみ) 。

* [shaderjp/HDRImageViewer](https://github.com/shaderjp/HDRImageViewer)

これまでは HDR レンダリングをしていても最終的に SDR にトーンマッピングをするのでそのように HDR レンダリングの映像を調整していたと思いますが、それをそのまま HDR (HDR10) として出力してみてもあんまり HDR 感のある映像に見えなかったりしています。この辺りは「最終的に HDR でディスプレイ出力する」という前提での調整も必要になりそうです。 

Unity でも列挙型には HDR10 などの定義がされているので、今後 Unity の HDR ディスプレイ出力対応に期待したいところです。 (実際やってみると Unity 上でリアルタイムに HDR プレビューできないので相当つらい)

#### HDR ビデオファイルへのエンコード

せっかくなので HDR のビデオファイルを作成したいところです。

* HDR の OpenEXR が入力できる
* HDR10 などの HDR 規格に準拠したビデオファイルにエンコードできる

上記を満たすエンコーダーソフトに入れることで一般的な HDR ディスプレイ環境で視聴できるビデオファイルが作成できます。

ちなみに現在のところ一番手軽に HDR ビデオの頒布、視聴ができるのは Youtube だと思いますので Youtube の HDR フォーマットも一つの基準として検討されるとよいと思います。

* [ハイ ダイナミック レンジ（HDR）動画をアップロードする](https://support.google.com/youtube/answer/7126552?hl=ja)

Youtube は HLG ガンマのビデオもアップロード可能ですが、対応する再生環境が限定的になってしまうので PQ ガンマを強く推奨します。

### "360 view" キャプチャーはうまくいかない事がある

* [Unity 2018.1 でステレオ VR 動画を作成する](https://qiita.com/tan-y/items/ea824684077b0a544421)
* [Unity でステレオ VR 動画を作成する (ほぼ完全 (?) 版)](https://qiita.com/tan-y/items/941de5c8bc3309f835d5)

"360 view" は条件によりますが、うまくいかない事があります。 (Unity 2018.2.3f1 / Unity Recorder 1.0.1)

* "Project Settings - Player" の Color Space は **Gamma** にする。 Linear にするとガンマが適用されません。 HDR レンダリングをして EXR 以外の形式でキャプチャー、保存したいのであれば自前でガンマ変換をする必要があります。
* **(Unity 2018.3b1 で修正されました)** ~~"Stereo" は使わない。一般的な 3D VR 動画は上が左目、下が右目なのですが Unity Recorder の 360 view を Stereo でキャプチャーした場合は逆になっています。~~

![img12.png](https://qiita-image-store.s3.amazonaws.com/0/211064/dfb4f1ca-c827-5a07-11f4-cd6a674cfeb0.png)

* [aosoft/UnityConvertToEquirect](https://github.com/aosoft/UnityConvertToEquirect) (再現プロジェクト)

RenderTexture.ConvertToEquirect の不具合により、左目側が下、右目側が上にレンダリングされてしまっています。

他、以前は「任意の方向を正面にできない」という問題がありましたが Unity の Camera.RenderToCubemap の挙動が変わり、カメラの向きに合わせるようになったようです。確認した限りでは 2018.2 系と 2018.1 でも 2018.1.9f1 ではそのような動作になっていました。

上記の記事はこれらの問題を回避してステレオ VR 映像のキャプチャーをする方法をまとめています。うまくいかない場合は参考にしてください。

### いくつかの機能がオミットされている (Unity Recorder 1.0.1 時点 → v2.0 で復活)

(2019/10/8 追記)

* Audio Recorder が v2.0.1 で復活しました
* G Buffer Recorder に相当する "Unity AOV Recorder" が v2.0.0 と合わせて追加されました。 Unity Recorder とは別パッケージになっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/ab297f20-a1c5-8b68-5368-31ab30696253.png)


<font color="LightGray">Recorder 0.2 までと比較し、下記の機能がなくなっています。</font>

* <font color="LightGray">Audio Recorder</font>
* <font color="LightGray">G Buffer Recorder</font>

<font color="LightGray">G Buffer Recorder は 0.2 の段階でも [FrameCapturer](https://github.com/unity3d-jp/FrameCapturer) からの Legacy 扱い (かつ未修正では動作しなかった) でした。</font>

<font color="LightGray">Audio Recorder は .wav など非圧縮でのキャプチャーをする手段なので復活がしてほしいですね。</font>

## おわりに

Unity Recorder は非常に簡単に使うことができますので、 Unity でのコンテンツ制作に興味がある方はとりあえず軽く試してみるとよいのではないかと思います。是非活用してみてください。

(2019/10/8 追記)
Unity Recorder について LT 大会で発表した際のフォロー記事を書きました。こちらで当記事で扱っていない Unity Recorder の検証結果をまとめていますので合わせてご参照ください。

* ["[非公式] Unite Tokyo 2019 Eve2 LT Fes" (2019/9/23) で登壇しました](http://tan-y.hatenablog.com/entry/2019/10/07/010000)