目的:在AnimationBlueprint中使用自定义动画控制节点。
主要过程:
1. 引用相关模块。在Client.Build.cs文件中,PublicDependencyModuleNames.AddRange里加入”AnimGraphRuntime”,“AnimGraph”, “BlueprintGraph”,添加引用模块后可在使用时直接包含头文件名称,而不用指定具体路径。
2. 实现AnimNode类,用于处理更新骨骼位置等具体逻辑;
3. 实现AnimGraphNode类,用于在编辑器中显示信息等;
4. 编辑工程后即可在AnimationBlueprint中使用该节点
下面以我的自定义动画节点CopyParentBone为例,该节点作用是更改当前Component内某骨骼的Transform为Parent Component内同名称骨骼的Transform:
一、添加引用模块
Client.Build.cs
- PublicDependencyModuleNames.AddRange(new string[]
- {
- "Core",
- "CoreUObject",
- "Engine",
- "InputCore",
- "AIModule",
- "GameplayTasks",
- "Landscape",
- "Foliage",
- "AnimGraphRuntime",
- "AnimGraph",
- "BlueprintGraph"
- });
二、AnimNode类
Public/AnimNode_CopyParentBone.h
- /*
- * \file AnimNode_CopyParentBone.h
- *
- * \author: Jia Zhipeng
- * \date: 2016/02/24
- */
- #pragma once
- #include "AnimNode_SkeletalControlBase.h"
- #include "AnimNode_CopyParentBone.generated.h"
- USTRUCT()
- struct FAnimNode_CopyParentBone :public FAnimNode_SkeletalControlBase
- //父类可以是FAnimNode_SkeletalControlBase或者FAnimNode_Base
- //FAnimNode_SkeletalControlBase一般用于对骨骼的控制,通过EvaluateBoneTransforms更改骨骼位置。
- //FAnimNode_Base一般用于对整体MeshBase的更改,通过Evaluate或者EvaluateComponentSpace更改Output.Pose更改全身的位置
- //自定义类继承父类后,override部分接口即可,以下是我用到的主要接口
- {
- GENERATED_USTRUCT_BODY()
- /** Name of bone to control. **/
- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalControl)
- FBoneReference BoneToModify;
- public:
- // Constructor
- FAnimNode_CopyParentBone();
- // // FAnimNode_Base interface
- // 显示Debug信息
- virtual void GatherDebugData(FNodeDebugData& DebugData) override;
- // // End of FAnimNode_Base interface
- // FAnimNode_SkeletalControlBase interface
- // 更改位置的逻辑实现函数
- virtual void EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms) override;
- // 判断用到的骨骼是否有效
- virtual bool IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones) override;
- // End of FAnimNode_SkeletalControlBase interface
- private:
- // FAnimNode_SkeletalControlBase interface
- // 初始化骨骼引用
- virtual void InitializeBoneReferences(const FBoneContainer& RequiredBones) override;
- // End of FAnimNode_SkeletalControlBase interface
- };
Private/AnimNode_CopyParentBone.cpp
- /*
- * \file AnimNode_CopyParentBone.cpp
- *
- * \author: Jia Zhipeng
- * \date: 2016/02/24
- */
- #include "Client.h"//自己的Game.h
- #include "AnimNode_CopyParentBone.h"
- FAnimNode_CopyParentBone::FAnimNode_CopyParentBone()
- {
- }
- //控制骨骼运动的逻辑实现。在OutBoneTransforms里Add需要修改的BoneTransform
- void FAnimNode_CopyParentBone::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
- {
- check(OutBoneTransforms.Num() == 0);
- FTransform NewBoneTM = FTransform::Identity;
- const FBoneContainer BoneContainer = MeshBases.GetPose().GetBoneContainer();
- USceneComponent* ParentComponent = SkelComp->GetAttachParent();
- if (ParentComponent)
- NewBoneTM = ParentComponent->GetSocketTransform(BoneToModify.BoneName, RTS_Component);
- else
- {
- UE_LOG(LogAnimation, Warning, TEXT("FAnimNode_CopyParentBone cannot get parent component"));
- }
- OutBoneTransforms.Add(FBoneTransform(BoneToModify.GetCompactPoseIndex(BoneContainer), NewBoneTM));
- }
- void FAnimNode_CopyParentBone::GatherDebugData(FNodeDebugData& DebugData)
- {
- FString DebugLine = DebugData.GetNodeName(this);
- DebugLine += "(";
- AddDebugNodeData(DebugLine);
- DebugLine += FString::Printf(TEXT(" Target: %s)"), * BoneToModify.BoneName.ToString());
- DebugData.AddDebugItem(DebugLine);
- ComponentPose.GatherDebugData(DebugData);
- }
- bool FAnimNode_CopyParentBone::IsValidToEvaluate(const USkeleton* Skeleton, const FBoneContainer& RequiredBones)
- {
- return (BoneToModify.IsValid(RequiredBones));
- }
- void FAnimNode_CopyParentBone::InitializeBoneReferences(const FBoneContainer& RequiredBones)
- {
- BoneToModify.Initialize(RequiredBones);
- }
三、AnimGraphNode
Public/AnimGraphNode_CopyParentBone.h
- /*
- * \file AnimGraphNode_CopyParentBone.h
- *
- * \author: Jia Zhipeng
- * \date: 2016/02/24
- * \purporse: 自定义动画节点,在Parent Component中获得与当前Component的根骨骼同名的骨骼Transform,然后设置为当前骨骼的Transform
- */
- #pragma once
- #include "AnimGraphNode_SkeletalControlBase.h"
- #include "AnimNode_CopyParentBone.h"
- #include "AnimGraphNode_CopyParentBone.generated.h"
- UCLASS(MinimalAPI)
- class UAnimGraphNode_CopyParentBone : public UAnimGraphNode_SkeletalControlBase
- {
- GENERATED_UCLASS_BODY()
- UPROPERTY(EditAnywhere, Category=Settings)
- FAnimNode_CopyParentBone Node;
- // UEdGraphNode interface
- // 鼠标悬浮在Node上的提示文本
- virtual FText GetTooltipText() const override;
- // Node的名字文本
- virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
- // End of UEdGraphNode interface
- protected:
- // UAnimGraphNode_SkeletalControlBase interface
- // 返回controller的描述
- virtual FText GetControllerDescription() const override;
- // 返回引用的AnimNode
- virtual const FAnimNode_SkeletalControlBase* GetNode() const override { return &Node; }
- // End of UAnimGraphNode_SkeletalControlBase interface
- };
Private/AnimGraphNode_CopyParenBone.cpp
- /*
- * \file AnimNode_CopyParentBone.cpp
- *
- * \author: Jia Zhipeng
- * \date: 2016/02/24
- */
- #include "Client.h"
- #include "AnimGraphNode_CopyParentBone.h"
- #define LOCTEXT_NAMESPACE "A3Nodes"
- UAnimGraphNode_CopyParentBone::UAnimGraphNode_CopyParentBone(const FObjectInitializer& ObjectInitializer)
- :Super(ObjectInitializer)
- {
- }
- FText UAnimGraphNode_CopyParentBone::GetTooltipText() const
- {
- return LOCTEXT("AnimGraphNode_CopyParentBone_Tooltip", "Copy parent bone's transform to this component's root. Their names must be same");
- }
- FText UAnimGraphNode_CopyParentBone::GetNodeTitle(ENodeTitleType::Type TitleType) const
- {
- return LOCTEXT("AnimGraphNode_CopyParentBone_Title", "Copy Parent Bone");
- }
- FText UAnimGraphNode_CopyParentBone::GetControllerDescription() const
- {
- return LOCTEXT("CopyParentBone", "Copy Parent Bone");
- }
- #undef LOCTEXT_NAMESPACE
参考内容
1.Animation Node, Entire Source for a TurnIn Place Node
https://wiki.unrealengine.com/Animation_Node,_Entire_Source_for_a_Turn_In_Place_Node
2. 创建自定义动画节点
https://www.unrealengine.com/zh-CN/blog/creating-custom-animation-nodes
3.UE引擎中部分节点如AnimNode_CopyBone,AnimNode_ModifyBone的源代码