UE中自带的动画蓝图节点有限,在实现一些功能时需要通过C++编写一些自定义的动画蓝图节点,本文就来讲解其基础实现,自定义节点最终效果如下:
源文件下载:https://download.youkuaiyun.com/download/grayrail/87654290
1.流程简介
自定义动画蓝图节点并不像扩展蓝图那样方便,需要编写AnimNodeGraph与AnimNode两个类,分别负责编辑器绘制与具体执行,逻辑关系如下:
AnimGraphNode中存放AnimNode的字段,UE会去找对应的AnimNode,AnimNode里存放动画蓝图暴露在编辑器上的可编辑字段。
2.编写AnimGraphNode
我们使用UE4.27版本,并继承AnimNode的Skeletal中间基类,方便处理骨架逻辑。
首先来编写AnimGraphNode:
MyAnimGraphNode.h
#pragma once
#include "AnimGraph/Classes/AnimGraphNode_SkeletalControlBase.h"
#include "MyAnimNode.h"
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "MyAnimGraphNode.generated.h"
UCLASS(MinimalAPI)
class UMyAnimGraphNode : public UAnimGraphNode_SkeletalControlBase
{
GENERATED_BODY()
public:
// UEdGraphNode interface
virtual FText GetNodeTitle(ENodeTitleType::Type titleType) const override;
virtual FText GetTooltipText() const override;
// End of UEdGraphNode interface
protected:
// UAnimGraphNode_SkeletalControlBase interface
virtual FText GetControllerDescription() const override;
virtual const FAnimNode_SkeletalControlBase* GetNode() const override { return &Node; }
virtual void Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* previewSkelMeshComp) const override;
// End of UAnimGraphNode_SkeletalControlBase interface
private:
UPROPERTY(EditAnywhere, Category = Settings)
FMyAnimNode Node;
};
MyAnimGraphNode.cpp
#include "MyAnimGraphNode.h"
#include "Components/SkeletalMeshComponent.h"
#define LOCTEXT_NAMESPACE "UMyAnimGraphNode"
FText UMyAnimGraphNode::GetControllerDescription() const
{
return LOCTEXT("MyAnimNodeDesc", "My Anim Node Desc");
}
FText UMyAnimGraphNode::GetNodeTitle(ENodeTitleType::Type titleType) const
{
return LOCTEXT("MyAnimNodeTitle", "My Anim Node Title");
}
FText UMyAnimGraphNode::GetTooltipText() const
{
return LOCTEXT("MyAnimNodeTooltip", "My Anim Node Tooltip");
}
void UMyAnimGraphNode::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* previewSkelMeshComp) const
{
}
#undef LOCTEXT_NAMESPACE
上述脚本逻辑主要定义编辑器外观、颜色等信息,注意头文件上的FMyAnimNode Node
字段,定义该字段才会找到对应的AnimNode。
2.编写AnimNode
该节点负责编写动画蓝图节点内的具体逻辑、暴露编辑器下的修改字段等。
MyAnimNode.h
#pragma once
#include "AnimGraphRuntime/Public/BoneControllers/AnimNode_SkeletalControlBase.h"
#include "BoneContainer.h"
#include "BonePose.h"
#include "CoreMinimal.h"
#include "MyAnimNode.generated.h"
USTRUCT(BlueprintInternalUseOnly)
struct MYPROJECT_API FMyAnimNode : public FAnimNode_SkeletalControlBase
{
GENERATED_BODY();
public:
FMyAnimNode();
//输出调试信息
virtual void GatherDebugData(FNodeDebugData& debugData) override;
virtual bool NeedsOnInitializeAnimInstance() const override { return true; }
//更新逻辑
virtual void EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& output, TArray<FBoneTransform>& outBoneTransforms) override;
//验证是否可以执行更新逻辑
virtual bool IsValidToEvaluate(const USkeleton* skeleton, const FBoneContainer& requiredBones) override;
private:
//初始化骨骼时调用
virtual void InitializeBoneReferences(const FBoneContainer& requiredBones) override;
UPROPERTY(EditAnywhere)
FBoneReference TargetBone;
};
MyAnimNode.cpp
#include "MyAnimNode.h"
#include "Animation/AnimInstanceProxy.h"
#include "AnimationCoreLibrary.h"
#include "AnimationRuntime.h"
FMyAnimNode::FMyAnimNode()
{
}
void FMyAnimNode::GatherDebugData(FNodeDebugData& debugData)
{
FString DebugLine = debugData.GetNodeName(this);
DebugLine += "(";
AddDebugNodeData(DebugLine);
DebugLine += FString::Printf(TEXT(")"));
debugData.AddDebugItem(DebugLine);
ComponentPose.GatherDebugData(debugData);
}
void FMyAnimNode::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& output,
TArray<FBoneTransform>& outBoneTransforms)
{
check(outBoneTransforms.Num() == 0);
const FBoneContainer& boneContainer = output.Pose.GetPose().GetBoneContainer();
const FCompactPoseBoneIndex boneCPB = TargetBone.GetCompactPoseIndex(boneContainer);
if (boneCPB == INDEX_NONE) return;
FTransform boneTransform = output.Pose.GetComponentSpaceTransform(boneCPB);
boneTransform.SetScale3D(FVector::ZeroVector);
outBoneTransforms.Add(FBoneTransform(boneCPB, boneTransform));
outBoneTransforms.Sort(FCompareBoneTransformIndex());
}
bool FMyAnimNode::IsValidToEvaluate(const USkeleton* skeleton, const FBoneContainer& requiredBones)
{
if (TargetBone.IsValidToEvaluate()) return true;
return false;
}
void FMyAnimNode::InitializeBoneReferences(const FBoneContainer& requiredBones)
{
TargetBone.Initialize(requiredBones);
}
3.配置build.cs
依赖项参考了其他动画蓝图节点的配置,可能有冗余:
using UnrealBuildTool;
public class MyProject : ModuleRules
{
public MyProject(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"HeadMountedDisplay",
"AnimGraph",
"AnimGraphRuntime",
"BlueprintGraph"
});
}
}
最后编译即可。
上述节点执行后将对选中的骨骼,设置缩放为0。