UE4 C++编写自定义动画蓝图节点

UE中自带的动画蓝图节点有限,在实现一些功能时需要通过C++编写一些自定义的动画蓝图节点,本文就来讲解其基础实现,自定义节点最终效果如下:
在这里插入图片描述
源文件下载https://download.csdn.net/download/grayrail/87654290

1.流程简介

自定义动画蓝图节点并不像扩展蓝图那样方便,需要编写AnimNodeGraphAnimNode两个类,分别负责编辑器绘制与具体执行,逻辑关系如下:
在这里插入图片描述
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。

猜你喜欢

转载自blog.csdn.net/grayrail/article/details/129965729