UnityでGif動画を撮影したい

# 概要

Unity上でGif動画を読み込む方法はいくつかありますが、Gif動画を撮影するとなるとあまり情報が出てきません。
今回は「UnityでGif動画を撮影する方法」を紹介します。

# 紹介するライブラリ - Moments

- [Moments](https://github.com/Chman/Moments)

カメラにコンポーネントをアタッチして、`Record()`を呼び出すだけでGif動画の作成および書き出しを実行してくれるライブラリです。
Zlibライセンスです。

## 使い方

### 1. カメラに `Moments Recorder` をアタッチする

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47146/4c487b66-b203-2e5b-6cb1-de3e6c3c7d76.png)


カメラに`Moments Recorder`コンポーネントをアタッチします。

インスペクタから録画するGif動画の設定を行うことができます。
（解像度やフレームレート、圧縮の設定ができる）

なお、 `Record Time`の値は「最大で録画できる時間（秒数）」を表しています。
ここで設定した時間を超えて録画することはできないので、実際に録画する秒数より少し長めにしておくとよいでしょう。

### 2. スクリプトから録画処理を呼び出す

ちょっとAPIにクセがあるので注意です。

1. `Recorder.State`が`RecorderState.PreProcessing`（前の録画データの書き出し準備中）だったらいったん待つ
2. `Recorder.Record()`を呼び出して録画を開始する
3. 任意の秒数自分で待つ
4. `Recorder.Pause()`を呼び出して録画を完了する
5. `Recorder.Save()`を呼び出してファイルに書き出す（`RecorderState.PreProcessing`ステートになる）
6. 書き出しが完了する



```cs
using System.Collections;
using Moments;
using UnityEngine;

public class RecordSample : MonoBehaviour
{
    [SerializeField] private Recorder _recorder;

    private void Start()
    {
        // １回録画した後に、次の録画準備が整ったことを伝えるコールバック
        _recorder.OnPreProcessingDone += () => { Debug.Log("録画準備が完了しました"); };

        // ファイルの書き出しが完了したコールバック
        _recorder.OnFileSaved += (i, s) => { Debug.Log($"{s} に保存しました"); };

        StartCoroutine(RecordeCoroutine());
    }

    IEnumerator RecordeCoroutine()
    {
        _recorder.SaveFolder = Application.dataPath;

        // 録画準備が整うまで待つ
        yield return new WaitWhile(() => _recorder.State == RecorderState.PreProcessing);

        // 録画開始
        _recorder.Record();

        // ２秒間録画する
        yield return new WaitForSeconds(2.0f);

        // 録画停止
        _recorder.Pause();

        // 保存
        _recorder.Save(filename: "RecordedFile");
    }
}
```

### 3. Gifファイルができあがる

![TestGifRecord.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47146/e922803a-1d48-f85c-1bb7-b0a782032bca.gif)



## Moments、すごい。けどちょっと物足りない。

たったこれだけでGif動画が記録できるので、すごい便利です。
ファイル書き出しも別スレッドで実行してくれます。


こんなすごい`Moments`ですが、ちょっと足りない部分があります。
それはAPIが同期しかないところです。


# UnityGifRecorder - Momentsをラップして使いやすくしたライブラリ

- [UnityGifRecorder](https://github.com/TORISOUP/UnityGifRecorder)


ということで、`Moments`をラップする形で非同期APIを提供するライブラリを作ってみました。  
（といっても本当に数行APIをラップしただけなので、こんな大層な名前つけるほどでも無いんですが…。ライセンスもいっちょ前にMITライセンスですが、正直中身の9割9分は`Moments`そのまんまです）

[UniTask](https://github.com/Cysharp/UniTask)に依存しているのでこちらとセットで導入してください。

## 使い方

基本は`MomentsRecorder`と同じです。
というか中身は`MomentsRecorder`そのもので、それを`UnityGifRecorder`が薄くラップしてるだけです。

違いとしては録画と書き出しが非同期APIになっているところです。

```cs
public class RecordSample : MonoBehaviour
{
    // MomentsRecorder と UnityGifRecorder をセットでカメラに貼り付けてね
    [SerializeField] private UnityGifRecorder _recorder;

    private async UniTaskVoid Start()
    {
        var ct = this.GetCancellationTokenOnDestroy();

        // 録画パス指定
        _recorder.SaveFolder = Path.Combine(Application.dataPath, "TORISOUP", "UnityGifRecorder", "Demo", "output");

        // 指定秒数、録画する
        await _recorder.RecordAsync(seconds: 2.0f, DelayType.DeltaTime, token: ct);

        // ファイルに書き出す
        await _recorder.SaveAsync(fileName: "TestGifRecord");
    }
}
```

# まとめ

- [Moments](https://github.com/Chman/Moments)を使えば簡単にUnityでGif動画が撮影できる
- 非同期APIが恋しい人は[UnityGifRecorder](https://github.com/TORISOUP/UnityGifRecorder)と合わせて使ってみるといいかも