受け取ったポースを返すだけのアニメーションノードを作ってみた

自作アニメーションノードを作ってみようということで、シンプルなところから始めてみました。

# アニメーションノードの構成

アニメーションノードは、以下の２つで構成されています。

* Anim Behavior ノード<br>
アニメーションノードの実処理（更新、ポーズ反映など）が定義されたノードです。<br>
<br>
* Anim Graph ノード<br>
UE4Editor の「**アニムグラフ**」で配置するノードの情報（ノード名やノードの色など）が定義されたノードです。<br>

これらのノードを定義するだけでアニメーションノードが使用可能になります。

# 受け取ったポーズを返すだけのアニメーションノードを作ってみる

アニメーションノードの参考となるソースは数多くあります。
しかし、「**結局、何が正しいのか？**」と言うのはこれらのソースを見ただけでは判断が付きづらいです……。

そこで、まずは一番シンプルな実装になるであろう「**受け取ったポーズを返すだけのアニメーションノード**」を作ってみます。

## Anim Behavior ノードを用意する
まずは、Anim Behavior ノードを用意します。

Anim Behavior ノードは構造体 **FAnimNode_Base** を継承して定義します。
また、継承した構造体はモジュールのタイプが「**Runtime**」のモジュールに定義します。
（モジュールについての説明は、ヒストリアさんの[こちらの記事](http://historia.co.jp/archives/3097)が参考になります。）

規模は大きくないので、ソースコードをそのまま載せます。

```cpp:AnimNode_MySimple.h
#pragma once

#include "Animation/AnimNodeBase.h"

#include "AnimNode_MySimple.generated.h"

USTRUCT()
struct MYSANDBOX_API FAnimNode_MySimple : public FAnimNode_Base
{
	GENERATED_USTRUCT_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
	FPoseLink SourcePose;

public:
	FAnimNode_MySimple();

	virtual void Initialize(const FAnimationInitializeContext& Context) override;
	virtual void CacheBones(const FAnimationCacheBonesContext& Context) override;
	virtual void Update(const FAnimationUpdateContext& Context) override;
	virtual void Evaluate(FPoseContext& Output) override;

};
```

```cpp:AnimNode_MySimple.cpp
#include "MySandbox.h"
#include "AnimNode_MySimple.h"

// ----------------------------------------------------------------------------
FAnimNode_MySimple::FAnimNode_MySimple()
{
}

// ----------------------------------------------------------------------------
void FAnimNode_MySimple::Initialize(const FAnimationInitializeContext& Context)
{
	FAnimNode_Base::Initialize(Context);

	SourcePose.Initialize(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MySimple::CacheBones(const FAnimationCacheBonesContext& Context)
{
	SourcePose.CacheBones(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MySimple::Update(const FAnimationUpdateContext& Context)
{
	SourcePose.Update(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MySimple::Evaluate(FPoseContext& Output)
{
	SourcePose.Evaluate(Output);
}
```

後で別のモジュールで定義する Anim Graph ノードがこの構造体を内包するため、**モジュール API 指定子（このソースでいうところの MYSANDBOX_API）**が必要です。
（モジュール API 指定子については、[こちらのページ](https://docs.unrealengine.com/latest/JPN/Programming/Basics/index.html)の「Module API」の項目に載っています。）

以下、各メンバの簡単な説明です。

|メンバ名|種類|概要|
|---|---|---|
|SourcePose|変数|ポーズの入力ピンです。<br><br>![MySimple01.png](https://qiita-image-store.s3.amazonaws.com/0/43814/f7042c06-eb2e-903a-b4c3-d70da3fc3800.png)<br><br>ポーズには、リンクされているノードの参照先などが含まれています。<br><br>変数名は Pose 以外にする必要があります。|
|Initialize|関数|ノードの初期化処理を記述します。<br>初期化が必要な場合に随時呼び出されます。|
|CacheBones|関数|ノードが参照するボーン情報（ボーンインデックスなど）をキャッシュする処理を記述します。<br><br>この関数はメッシュが再設定されるなど、キャッシュを生成し直す必要が出てきた場合に随時呼び出されます。|
|Update|関数|アニメーションノードの更新処理を記述します。<br>DeltaTime を必要とする処理はここで記述します。|
|Evaluate|関数|アニメーションノードのポーズ生成処理を記述します。<br>ボーンのトランスフォームはここで反映されます。|

メンバ関数に関しては、ノード自身が処理を必要としない場合でも「**メンバに入力ポーズがある場合**」や「**別のアニメーションノードを内包している場合**」は、それらの各種関数を必ず呼ぶ必要があります。
（今回の場合、入力ポーズである SourcePose があるため、各関数内で SourcePose の関数を呼んでいます。）

もし呼ばなかった場合、入力ポーズの先にリンクされているノードや内包されているノードでそれらの処理が実行されなくなり、正しく処理されない可能性があります。

## Anim Graph ノードを用意する

次に、Anim Graph ノードを用意します。

Anim Graph ノードはクラス **UAnimGraphNode_Base** を継承して定義します。
また、継承したクラスはモジュールのタイプが「**Developer**」のモジュールに定義します。
（モジュールのタイプが「**Editor**」のモジュールに定義した場合は、「**Play > Standalone Game**」でアニメーションが流れなくなります。）

こちらも規模が大きくないので、ソースコードをそのまま載せます。

```cpp:AnimGraphNode_MySimple.h
#pragma once

#include "AnimGraphNode_Base.h"

#include "Animation/AnimNode/AnimNode_MySimple.h"

#include "AnimGraphNode_MySimple.generated.h"

UCLASS()
class UAnimGraphNode_MySimple : public UAnimGraphNode_Base
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(EditAnywhere, Category = Settings)
	FAnimNode_MySimple Node;

public:
	virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;


};
```

```cpp:AnimGraphNode_MySimple.cpp
#include "MySandboxDeveloper.h"
#include "AnimGraphNode_MySimple.h"

#define LOCTEXT_NAMESPACE "MySandboxDeveloper"

// ----------------------------------------------------------------------------
UAnimGraphNode_MySimple::UAnimGraphNode_MySimple(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

// ----------------------------------------------------------------------------
FText UAnimGraphNode_MySimple::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return LOCTEXT("AnimGraphNode_MySimple_Title", "My Simple");
}

#undef LOCTEXT_NAMESPACE
```

前述の通り、Anim Graph ノードが Anim Behavior ノードを内包する形になっています。
また、今回は「**ノードのタイトル名**」のみを変えています。

このクラスを定義する際、以下のモジュールを「**～.Build.cs**」の「**PublicDependencyModuleNames**」に追加する必要があります。

* AnimGraph
* BlueprintGraph

## UE4Editor で確認してみる

これで必要となるクラスを2つとも定義できましたので、UE4Editor で配置して確認してみます。
問題なく動作しているようであれば、以下のようにアニメーションが再生されているはずです。
![MySimple02.png](https://qiita-image-store.s3.amazonaws.com/0/43814/9302dc6f-3894-29a8-0a03-d81f275c7f23.png)

ちなみに、ポーズのリンクに失敗した場合（入力ポーズの変数名を Pose にした場合）はこのように接続されていないときと同じ状態になります。
![NOLINK02.png](https://qiita-image-store.s3.amazonaws.com/0/43814/67705980-969c-6dd2-d7c2-9f5023acbc97.png)