自作アニメーションノードをつくってみよう、その2です。その1はこちら。
Transform(Modify) ノードに必要なノードをまとめてみる
今回は、アニムグラフで配置するノードを一つにまとめたノードを C++ で作ってみます。
まとめるノードはこちら。
- LocalToComponent ノード
- Transform(Modify) Bone ノード
- ComponentToLocal ノード
変更されていることがわかるように、Transform(Modify) Bone ノードでルートボーンを少しだけ上に上げてみます。
(変更するパラメータは赤枠で括っています。)
Anim Behavior ノードを用意する
では、Anim Behavior ノードを用意します。
今回も規模は大きくないので、ソースコードをそのまま載せます。
#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;
};
#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 という関数が追加されました。
これは何なのか?というと、アニムグラフで言うところのポーズとノードを繋ぐ部分に相当します。
例えば、
ModifyBoneNode.ComponentPose.SetLinkNode(&LocalToComponentNode);
今回の場合は、
ComponentToLocalNode.ComponentPose.SetLinkNode(&ModifyBoneNode);
ModifyBoneNode.ComponentPose.SetLinkNode(&LocalToComponentNode);
このように記述するだけで3つのノードをつなげたことになります。
入力ポーズを内包するノードに渡す
カスタムノードの入力ポーズを内包するノードに渡したい場合は、以下のようにポーズを代入してやります。
LocalToComponentNode.LocalPose = SourcePose;
これは Initialize で一度代入すれば大丈夫です。
ルートノードの関数の呼び出しだけでカスタムノードを更新する
このようにノードやポーズをつなげた場合、**ルートノード(アニムグラフで見て、一番最後に実行されるノード。今回の場合は ComponentToLocal ノード)**の Initialize や Update、Evaluate を呼び出すだけで、繋がっている全ノードの処理が実行されます。
例えば、今回のカスタムノードの Evaluate はコレだけです。
void FAnimNode_MyTransformBone::Evaluate(FPoseContext& Output)
{
ComponentToLocalNode.Evaluate(Output);
}
Anim Graph ノードを用意する
Anim Behavior ノードの用意が終わったら、Anim Graph ノードを用意します。
今回もタイトルを変えただけなので、ポーズを返すだけのノードと全く同じ構成です。
念のため、コードを載せておきます。
#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;
};
#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