この記事はUnreal Engine 4 (UE4) Advent Calendar 2016の12日目の記事になります。
アニメーションブループリントで使う、ボーンを制御するカスタムアニメノードグラフを作る手順についてまとめたいと思います。
情報は公式サイトとかぶっている部分があるのですが、一連の手順と注意点を含めてまとめたいと思います。
以下公式の情報
UnrealEngineのサイト
https://www.unrealengine.com/ja/blog/creating-custom-animation-nodes
ドキュメント「アニメーションノードのテクニカルガイド」
https://docs.unrealengine.com/latest/JPN/Programming/Animation/AnimNodes/index.html
この記事の前提
- バージョンはUE4.14
- 独自のアニメノードグラフを作るのが目的で便利さは二の次です。
アニムノードグラフを自作する前に
通常通りにUE4のプロジェクトを作るとゲームモジュールのみ作られ、エディタモジュールが作られませんので独自に作る必要があります。
作らなくても一応は動くのですが、パッケージを作った際にエラーが起きるので作ったほうがいいと思います。
AnimGraphノードはエディタ時のみに必要なだけでパッケージしたゲーム起動時には不要な機能になるからです。
モジュールの追加方法
今回は例としてMyProjectのエディターモジュールとしてMyProjectEditorモジュールを追加します。
1.フォルダ、ファイルの追加
最低限必要なのはモジュールルールとモジュールクラスのソースを追加してください。
#pragma once
#include "ModuleManager.h"
class FMyProjectEditorModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
#include "AdvC2016Editor.h"
// 特にモジュールロード時に特にすることがないので空
void FMyProjectEditorModule::StartupModule()
{
}
void FMyProjectEditorModule::ShutdownModule()
{
}
IMPLEMENT_MODULE(FMyProjectEditorModule, MyProjectEditor);
モジュールルールはMyProjectのMyProject.Build.csをコピーしMyProjectEditor.Build.csファイルを作り、MyProjectをMyProjectEditorに置換すればOKです。
2.モジュールルール C#ソースコードの編集
AnimGraphの宣言をもとに必要なモジュールをMyProjectEditor.Build.cs追加します。
PublicDependencyModuleNames.AddRange(
new string[]
{
"MyProject",
"Core",
"CoreUObject",
"Engine",
"BlueprintGraph",
"AnimGraph",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"UnrealEd",
"GraphEditor",
"PropertyEditor",
"EditorStyle",
}
);
念のためモジュールの循環参照を許可するモジュールも追加します。
CircularlyReferencedDependentModules.AddRange(
new string[]
{
"UnrealEd",
"GraphEditor",
}
);
3.uprojectファイル(MyProject.uproject)にエディタモジュールの情報を追加
"Modules": [
{
"Name": "MyProject",
"Type": "Runtime",
"LoadingPhase": "Default"
},
{
"Name": "MyProjectEditor",
"Type": "Editor",
"LoadingPhase": "PreDefault"
}
]
※エディタモジュールのLoadingPhaseはPreDefaultにしないと起動に失敗します。
アニメノードグラフに必要なもの
1つのアニメノードグラフを作るためにはAnim BehaviorとAnim Graph Nodeの2つを用意する必要があります。
Anim Behavior 構造体(AnimNode)
アニメーションの処理
アニメーションノード
struct FAnimNode_Base
スケルタルコントロール
struct FAnimNode_SkeletalControlBase
Anim Behaviorは構造体ですので「新規C++クラス」で親クラスに設定できないため、エンジンのソースコードを元に作る必要があります。
Anim Graph Node クラス
エディター上で操作するノード
主なAnim Graph Node
アニメーションノードグラフ基本クラス
UAnimGraphNode_Base
スケルタルコントロールグラフ基本クラス
UAnimGraphNode_SkeletalControlBase
ステートMachine
UAnimGraphNode_StateMachineBase
予めエディタモジュールを作成しておくと「新規C++クラス」で追加することができます。
機能実装
Anim Graph Node
AnimBehaviorノードを持つ必ず持つ必要があります。
FAnimNode BasePose;
UIの見た目を変更した場合は以下の処理をオーバーライドして変更しましょう
ノードのタイトルのテキスト
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
ToolTipのテキスト
virtual FText GetTooltipText() const override;
タイトルの色
virtual FLinearColor GetNodeTitleColor() const override;
AnimBehavior
ボーンの制御、アニメーションのプロパティや処理はこちらで定義します。
Anim Behavior 固有のプロパティ
ポーズノードピン
各アニメーションノードをつなげるピンを追加します。
ポーズ入力ピン
FPoseLink BasePose;
コンポーネントスペースポーズピン
FComponentSpacePoseLink ComponentPose;
ボーンリファレンス
ボーンの参照を行う構造体
FBoneReference
ノードのピンやプロパティの表示非表示を制御
UPROPERTYマクロを使用して設定することが可能
例
UPROPERTY(Category=Settings, meta(PinShownByDefault))
mutable float Alpha;
ノードグラフのピンにするためには以下のUPROPERTYのメタデータを設定する必要がある
例
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Anim, meta=(PinShownByDefault))
metaデータ | |
---|---|
NeverAsPin | プロパティはデータピンとしてエクスポーズされない。[詳細] パネルのみで編集が可能です。 |
PinHiddenByDefault | データピンとして使用可能になる。デフォルトでは非表示になっています。 |
PinShownByDefault | デフォルトで可視化されています。 |
AlwaysAsPin | プロパティは常に表示になる。 |
UPROPERTYその他の設定方法として、以下の設定でBool型プロパティの値により編集可能か不可能か切り替えることが可能です。
EditCondition="プロパティ名"
SkeletalControlBaseの処理
初期化
書式
virtual void Initialize(const FAnimationInitializeContext& Context)
親クラスFAnimNode_BaseとComponentPoseのInitialize関数を呼び出す。
他にポーズを参照するピンがあればoverrideして各ポーズのInitialize関数を呼び出す。
ポーズピンを追加していなければ、特に処理を書く必要は無いですが、初期化処理はここに
ノードの処理を行うかどうかの判定
書式
virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
ブレンド率やLODレベルのチェック以外でこのノードの処理を行わない条件を付けたい場合はこれをoverride
ボーンの参照の初期化
書式
virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones)
ボーン参照の初期化処理をここで行います。
例:スケルタルコントロールノードのボーンリファレンスを初期化
初期化をしないとGetComponentSpaceTransform等ボーンを取得できずに失敗するので
Update時処理
書式
virtual void UpdateInternal(const FAnimationUpdateContext& Context)
Update処理が呼ばれた際に呼ばれる処理
注意する点として
- ブレンド率が0のときや現在の表示されるLODレベルにより呼ばれない
- FAnimationUpdateContextから1フレームの経過時間を取得するようにする
※アニメーションの処理がゲームスレッドで動作していないため、GetWorld()から時間の取得は使用しないほうが良いです。
ボーンのTransformの計算時の処理
書式
virtual void EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
これをオーバーライドし、ボーンを制御するため処理を記述します。
ボーンの制御のために必要な処理をまとめておきます。
ボーンのインデックスを取得
const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();
FCompactPoseBoneIndex CompactPoseBoneToModify = ControlBone.GetCompactPoseIndex(BoneContainer);
制御するボーンの現状のTransformnの取得
FTransform NewBoneTM = MeshBases.GetComponentSpaceTransform(CompactPoseBoneToModify);`
各スペース座標への変換
計算するそれぞれのボーンスペースに変更するには
FAnimationRuntime::ConvertCSTransformToBoneSpace(SkelComp, MeshBases, NewBoneTM, CompactPoseBoneToModify, BCS_BoneSpace);
コンポーネントスペースに戻すには
FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, NewBoneTM, CompactPoseBoneToModify, BCS_BoneSpace);
例としてボーンスペース空間にしていますが、BCS_BoneSpaceを以下に変更することにより他の空間座標に変換されます。
Enum | |
---|---|
BCS_WorldSpace | ワールド空間座標 |
BCS_ComponentSpace | コンポーネント空間座標 |
BCS_ParentBoneSpace | 親ボーンスペース空間座標 |
BCS_BoneSpace | ボーンスペース空間座標 |
変更するボーンのTransformの設定
OutBoneTransformsにどのボーンをどんなTransformにするかを追加するとボーンが変更されます。
OutBoneTransforms.Add( FBoneTransform(ControlBone.GetCompactPoseIndex(BoneContainer), NewBoneTM) );
とりあえずこれでできるはず…
以上のことを実装すればボーンを操作することができるアニメーショングラフノードを作ることができると思います。
といっても、今回は必要最低限しかここにまとめていません。
ほかにオレオレIKやオレオレ物理アニメーションを作ってみたいと思った方はGitHubからソースコードを落として参考に実装してみると良いと思います。
明日は@dgtanakaさん、裏は@yoshikataです