• [UE4]CustomAnimationBlueprintNode 自定义动画蓝图节点


    目的:在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的源代码




  • 相关阅读:
    laravel 单元测试 phpunit 运行报错 RuntimeException: No application encryption key has been specified 解决
    pace.js 自动加载进度条插件的简单使用教程
    git push 报错 ERROR: Permission to xxx.git denied to someuser
    Laravel 框架对于分表进行统计合并查询的思路
    解决tail命令提示“tail: inotify 资源耗尽,无法使用 inotify 机制,回归为 polling 机制”
    phpredis 报错 “Function Redis::setTimeout() is deprecated” 解决方法
    laravel 5.5.39 升级到 5.5.45 出现 cookie 序列化异常问题的解决
    vue.js 实战 todo list
    BootstrapVue 安装指南
    05js语法检查、js兼容性处理
  • 原文地址:https://www.cnblogs.com/corgi/p/5405453.html
Copyright © 2020-2023  润新知