[UE4][UE5] AnimationRecorderを使って、アニメーションの録画（ベイク）処理をBP・C++から行う方法について

# はじめに
UnrealEngineにはレベル上のActorの動きをLevel Sequenceとして記録できる**Take Recorder**と**Sequence Recorder**（UE5では非推奨）という機能があります。そして、Skeletal Mesh Componentを持つActorをその記録対象にすると、記録中の動きをAnimation Sequenceアセットとして保存してくれます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ブログ記事用：TakeRecorderで記録すると、キャラの動きがアニメーションアセットとして保存される様子 <a href="https://t.co/qPc2litlkG">pic.twitter.com/qPc2litlkG</a></p>&mdash; おかず (@pafuhana1213) <a href="https://twitter.com/pafuhana1213/status/1545311142045618176?ref_src=twsrc%5Etfw">July 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

また、Persona（アニメーションエディタ）の録画機能とデバッグ機能を併用することで、こちらでも実行中のキャラのアニメーションを録画することができます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ブログ記事用：PersonaのAttach, 録画機能を使って、実行中のキャラのアニメーションを記録している様子 <a href="https://t.co/vz6lnjTn5R">pic.twitter.com/vz6lnjTn5R</a></p>&mdash; おかず (@pafuhana1213) <a href="https://twitter.com/pafuhana1213/status/1545312762414366720?ref_src=twsrc%5Etfw">July 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

上記の機能により、Sequencer上で調整したアニメーションやAnim BPによる物理制御・補正込みの結果をAnimationSequenceアセットに保存（ベイク）することができます。

しかし、ただアニメーションをベイクしたいだけなのに機能が多すぎたり、下準備がある程度必要だったりします。一応TakeRecorderに関するノードはいくつかあるので下準備を自動化はできますが、痒い所に少し手が届かないというお話を先日いただきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/0db02a5d-dd55-09d9-f2c2-2ffe579149d7.png)
そういった方に便利なのが、今日紹介する **Animation Recorder** です！
これをEditorUtility機能と併用することで、自作のアニメーション録画ツールをかんたんに作ることができます！
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自動的にSequencerエディタ再生 &amp; アニメーション録画開始して、再生終了したら自動的に録画終了するEUW<br><br>ABPによる物理骨付きの挙動をベイクしたいけど、SequenceRecorder, Take Recorderだと少し複雑・準備が大変という話を聞いて作ってみました～。需要あれば少し整えて公開します<a href="https://twitter.com/hashtag/UE5?src=hash&amp;ref_src=twsrc%5Etfw">#UE5</a> <a href="https://twitter.com/hashtag/UEE5Study?src=hash&amp;ref_src=twsrc%5Etfw">#UEE5Study</a> <a href="https://t.co/ZdQPF6JX63">pic.twitter.com/ZdQPF6JX63</a></p>&mdash; おかず (@pafuhana1213) <a href="https://twitter.com/pafuhana1213/status/1544332376796409857?ref_src=twsrc%5Etfw">July 5, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# Animation Recorderとは
その名の通りアニメーションを録画するための機能で、Take Recorder、Sequence Recorder、Personaの録画機能で使われています。なので、決して怪しい機能ではありませんし、**録画対象のSkeletalMeshComponentをAnimation Recorderに渡すだけで良い**という非常な便利な機能です！

ただ…C++は必須です。でも凄くかんたんです。

# Animation Recorderのつかいかた
## エディタモジュールの準備
Animation Recorderはエディタ専用機能なので、エディタ用モジュールでAnimation Recorderにアクセスする処理を実装した方が安全です。たぶんランタイムモジュールでも動作しますが、パッケージ作成時に問題になるはずです。

エディタモジュールの作成方法については下記記事を参考にするか、

https://historia.co.jp/archives/3097/

https://qiita.com/unknown_ds/items/0e271b947cf05d281480

こちらの無料プラグインを使うのがオススメです。サクッとモジュールを追加できるので重宝してます。

https://www.unrealengine.com/marketplace/ja/product/c-module-generator

## Animation Recorderによる録画開始・終了処理を実装
作成したエディタモジュールにBlueprintFunctionLibraryを追加し、下記のように録画開始・終了をリクエストする処理を組みます。それぞれ一行コードを呼ぶだけなので超かんたんです。
```cpp:UMyBlueprintFunctionLibrary
// Build.cs
PublicDependencyModuleNames に "SequenceRecorder" 追加

// h
UFUNCTION(BlueprintCallable)
static bool RecordAnimation(USkeletalMeshComponent* Component, const FString& AssetPath, const FString& AssetName);

UFUNCTION(BlueprintCallable)
static void StopRecordingAllAnimations();

UFUNCTION(BlueprintCallable)
static void StopRecordingAnimation(USkeletalMeshComponent* Component, bool bShowMessage = true);

// cpp
#include "AnimationRecorder.h"

bool UMyBlueprintFunctionLibrary::RecordAnimation(USkeletalMeshComponent* Component, const FString& AssetPath, const FString& AssetName)
{
   return FAnimationRecorderManager::Get().RecordAnimation(Component, AssetPath, AssetName, GetDefault<USequenceRecorderSettings>()->DefaultAnimationSettings);
}

void UMyBlueprintFunctionLibrary::StopRecordingAllAnimations()
{
	FAnimationRecorderManager::Get().StopRecordingAllAnimations(); 
}

void UMyBlueprintFunctionLibrary::StopRecordingAnimation(USkeletalMeshComponent* Component, bool bShowMessage)
{
	FAnimationRecorderManager::Get().StopRecordingAnimation(Component, bShowMessage);
}

```

## Animation Recorderによる録画開始・終了処理を呼び出し
あとは実装した各ノードを呼び出すだけです。今回はEditorUtilityWidgetにボタンを追加して、押すと録画開始・終了処理を呼ぶようにしました（説明用なのでSkeletalMeshComponentの取得がすっごく雑です）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/0117a358-219c-5a47-fbaa-4ef9802763f4.png)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ブログ記事用：エンジン標準のアニメーション録画機能をEUWから直接呼び出している様子 <a href="https://t.co/LUJ8nPR9K4">pic.twitter.com/LUJ8nPR9K4</a></p>&mdash; おかず (@pafuhana1213) <a href="https://twitter.com/pafuhana1213/status/1545331694512680961?ref_src=twsrc%5Etfw">July 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

かんたんですね！
ただ、**いくつか注意点があります。**

- エディタ専用機能なので、**EditorUtility系のBPで実装するのがオススメ**です。また、エディタ専用なのでパッケージでは使えません。
- 「Content/Record」に「RecordTest」というアセット名で保存したい場合、RecordAnimationに指定するAssetPathは「/Game/Record/RecordTest」、AssetNameは「RecordTest」になります。もし連番でアセット名を自動生成したい場合はAssetToolsの**CreateUniqueAssetName**ノードがべんりです。

https://pafuhana1213.hatenablog.com/entry/2022/07/06/040053

使用例（FolderPath =/Game/Record、AssetNameBase = RecordTest と指定する感じ ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/2ed1b50b-81f7-e943-e68c-a8f1b655e9d5.png)
- 録画フレームレート、録画最大時間などの録画設定のデフォルトは、Personaの**Recording Settings**で設定可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/7a85e563-1bc2-64b2-32e4-b5cd1e3fbc27.png)
もしプログラム側で制御したい場合は、RecordAnimationに渡す**FAnimationRecordingSettings**を生成・設定する必要があります。なおFAnimationRecordingSettingsはBPに対応していないので、FAnimationRecordingSettingsをBPノードの引数ピンとして使うことはできません。ので、よく似た構成の構造体などを用意する必要があります。
```cpp:UMyBlueprintFunctionLibrary
bool UMyBlueprintFunctionLibrary::RecordAnimation(USkeletalMeshComponent* Component, const FString& AssetPath, const FString& AssetName)
{
   FAnimationRecordingSettings Settings = GetDefault<USequenceRecorderSettings>()->DefaultAnimationSettings;
   Settings.SampleFrameRate = XXX;
   Settings.Length = YYY;

   return FAnimationRecorderManager::Get().RecordAnimation(Component, AssetPath, AssetName, Settings);
}
```
ちなみに、Length（単位は秒）は最大録画時間なので決められた時間・範囲だけ録画したいというケースで非常に有用です。

- アニメーション録画は複数同時に実行することができます。また、アニメーション録画を終了してアセットが生成される際にヒッチ（処理が重くてカクつく）が発生します。そして、そのタイミングで別のアニメーション録画処理が走っているとその録画処理が正常に行われない場合があります。そのため、「複数のアニメーションを同時に録画したい」「Sequencerで実装したアニメーションをサブシーケンス毎に録画したい」といったケースでは、StopRecording~は全録画対象のアニメーションが再生し終わってから呼ぶ方が安定する印象です。なお、その際は上述の最大録画時間を設定しないと録画時間が無駄に伸びてしまうので注意です。

# さいごに
これで自作のアニメーション録画ツールを作れるようになります。ただ前半で紹介した例のように、アニメーション録画とSequencerと組み合わせる場合はもう少し機能が必要です。具体的には現在開いているSequencerエディタに干渉したり、LevelSequenceの各TrackやSecitonの情報を取ってくる必要があります。
この辺りに関しても質問をいただくことが多くなってきたので、次回以降はその辺りについてご紹介できればと思います。

おしまい

# 追記
今回紹介した機能などを使ったサンプルを公開しました
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">以前にツイートした、自作アニメーション録画ツールをサンプルとしてGithubに公開しました！<a href="https://t.co/lZLCMN1jq3">https://t.co/lZLCMN1jq3</a><br><br>たぶん映像系のプロジェクトで役に立つ気がします。あと、EditorUtility機能を使ってSequencer作業を楽したい人にも参考になると思います。詳細はGithubのページで<a href="https://twitter.com/hashtag/UE5?src=hash&amp;ref_src=twsrc%5Etfw">#UE5</a> <a href="https://twitter.com/hashtag/UE5Study?src=hash&amp;ref_src=twsrc%5Etfw">#UE5Study</a> <a href="https://t.co/fhnf33ccDJ">https://t.co/fhnf33ccDJ</a> <a href="https://t.co/ANDIEyPMfX">pic.twitter.com/ANDIEyPMfX</a></p>&mdash; おかず (@pafuhana1213) <a href="https://twitter.com/pafuhana1213/status/1550395383146094593?ref_src=twsrc%5Etfw">July 22, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>