UE中自带的动画蓝图节点有限,在实现一些功能时需要通过C++编写一些自定义的动画蓝图节点,本文就来讲解其基础实现,自定义节点最终效果如下:
源文件下载:https://download.csdn.net/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 interfacevirtual FText GetNodeTitle(ENodeTitleType::Type titleType) const override;virtual FText GetTooltipText() const override;// End of UEdGraphNode interfaceprotected:// UAnimGraphNode_SkeletalControlBase interfacevirtual 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 interfaceprivate: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。