アニメーションノードをまとめたアニメーションノードを作ってみた

自作アニメーションノードをつくってみよう、その2です。その1は[こちら](http://qiita.com/go_astrayer/items/accf6772c38979ffecb5)。

# Transform(Modify) ノードに必要なノードをまとめてみる
今回は、アニムグラフで配置するノードを一つにまとめたノードを C++ で作ってみます。

まとめるノードはこちら。

* LocalToComponent ノード
* Transform(Modify) Bone ノード
* ComponentToLocal ノード

アニムグラフで配置すると、このようになります。
![node_combine.png](https://qiita-image-store.s3.amazonaws.com/0/43814/9b677354-0556-b266-0745-e434e80f40d4.png)

変更されていることがわかるように、Transform(Modify) Bone ノードでルートボーンを少しだけ上に上げてみます。
（変更するパラメータは赤枠で括っています。）

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

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

```cpp:AnimNode_MyTransformBone.h
#pragma once

#include "Animation/AnimNodeBase.h"
#include "Animation/AnimNodeSpaceConversions.h"

#include "BoneControllers/AnimNode_ModifyBone.h"

#include "AnimNode_MyTransformBone.generated.h"


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

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

public:
	FAnimNode_MyTransformBone();

	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;

private:
	FAnimNode_ConvertLocalToComponentSpace LocalToComponentNode;
	FAnimNode_ModifyBone ModifyBoneNode;
	FAnimNode_ConvertComponentToLocalSpace ComponentToLocalNode;

};
```

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

#include "Animation/AnimInstanceProxy.h"

// ----------------------------------------------------------------------------
FAnimNode_MyTransformBone::FAnimNode_MyTransformBone()
	: LocalToComponentNode()
	, ModifyBoneNode()
	, ComponentToLocalNode()
{
}

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

	// ノードやポーズを接続する
	ComponentToLocalNode.ComponentPose.SetLinkNode(&ModifyBoneNode);
	ModifyBoneNode.ComponentPose.SetLinkNode(&LocalToComponentNode);
	LocalToComponentNode.LocalPose = SourcePose;

	// Transform(Modify) Bone ノードでルートボーンを少しだけ上に上げる。
	ModifyBoneNode.BoneToModify.BoneName = FName("Root");
	ModifyBoneNode.BoneToModify.Initialize(Context.AnimInstanceProxy->GetSkeleton());
	ModifyBoneNode.Translation = FVector(0, 0, 100);
	ModifyBoneNode.TranslationMode = BMM_Replace;

	ComponentToLocalNode.Initialize(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MyTransformBone::CacheBones(const FAnimationCacheBonesContext& Context)
{
	ComponentToLocalNode.CacheBones(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MyTransformBone::Update(const FAnimationUpdateContext& Context)
{
	ComponentToLocalNode.Update(Context);
}

// ----------------------------------------------------------------------------
void FAnimNode_MyTransformBone::Evaluate(FPoseContext& Output)
{
	ComponentToLocalNode.Evaluate(Output);
}
```

今回は、FAnimNode_ModifyBone を内包しているため、以下のモジュールを「**～.Build.cs**」の「**PublicDependencyModuleNames**」に追加する必要があります。

* AnimGraphRuntime


## ノードとポーズを接続する

UE4 の 4.15 から **FPoseLinkBase::SetLinkNode** という関数が追加されました。
これは何なのか？というと、アニムグラフで言うところのポーズとノードを繋ぐ部分に相当します。

例えば、

```cpp
	ModifyBoneNode.ComponentPose.SetLinkNode(&LocalToComponentNode);
```

これをアニムグラフで表現すると、以下のようになります。
![node_combine2.png](https://qiita-image-store.s3.amazonaws.com/0/43814/78938591-efe4-01bc-5b14-70d218b94e7f.png)

今回の場合は、

```cpp
	ComponentToLocalNode.ComponentPose.SetLinkNode(&ModifyBoneNode);
	ModifyBoneNode.ComponentPose.SetLinkNode(&LocalToComponentNode);
```

このように記述するだけで3つのノードをつなげたことになります。

## 入力ポーズを内包するノードに渡す
カスタムノードの入力ポーズを内包するノードに渡したい場合は、以下のようにポーズを代入してやります。

```cpp
	LocalToComponentNode.LocalPose = SourcePose;
```

これは Initialize で一度代入すれば大丈夫です。

## ルートノードの関数の呼び出しだけでカスタムノードを更新する
このようにノードやポーズをつなげた場合、**ルートノード（アニムグラフで見て、一番最後に実行されるノード。今回の場合は ComponentToLocal ノード）**の Initialize や Update、Evaluate を呼び出すだけで、繋がっている全ノードの処理が実行されます。

例えば、今回のカスタムノードの Evaluate はコレだけです。

```cpp
void FAnimNode_MyTransformBone::Evaluate(FPoseContext& Output)
{
    ComponentToLocalNode.Evaluate(Output);
}
```

# Anim Graph ノードを用意する

Anim Behavior ノードの用意が終わったら、Anim Graph ノードを用意します。
今回もタイトルを変えただけなので、[ポーズを返すだけのノード](http://qiita.com/go_astrayer/items/accf6772c38979ffecb5#anim-graph-%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E7%94%A8%E6%84%8F%E3%81%99%E3%82%8B)と全く同じ構成です。

念のため、コードを載せておきます。

```cpp:AnimGraphNode_MyTransformBone.h
#pragma once

#include "AnimGraphNode_Base.h"
#include "Animation/AnimNode/AnimNode_MyTransformBone.h"

#include "AnimGraphNode_MyTransformBone.generated.h"

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

	UPROPERTY(EditAnywhere, Category = Settings)
	FAnimNode_MyTransformBone Node;

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


};
```

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

#define LOCTEXT_NAMESPACE "MySandboxDeveloper"

UAnimGraphNode_MyTransformBone::UAnimGraphNode_MyTransformBone(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

// ----------------------------------------------------------------------------
FText UAnimGraphNode_MyTransformBone::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return LOCTEXT("AnimGraphNode_MyTransformBone_Title", "My Transform Bone");
}

#undef LOCTEXT_NAMESPACE
```

# UE4Editor で確認する

こうして出来上がったノードがこちらです。前回と同じく、引数は入力ポーズのみです。
![node_combine3.png](https://qiita-image-store.s3.amazonaws.com/0/43814/58edc85b-94d9-ee32-b931-eb5979328da3.png)