创建自定义动画节点需要两个类:

一个是您在编辑器中看到的图表节点

一个是真正在运行时工作的行为节点

动画图表节点,派生自:UAnimGraphNode_Base

例如:class UAnimGraphNode_SequencePlayer : public UAnimGraphNode_Base

动画行为节点,派生自:FAnimNode_Base

例如:struct ENGINE_API FAnimNode_SequencePlayer : public FAnimNode_Base

两个节点的基类是不同的:一个基类是UObject(UAnimGraphNode_Base),另一个的基类是UStruct(FAnimNode_Base)

动画图表节点类的构建:

所有的图表节点包含了类似这样的对应行为节点:

class UAnimGraphNode_SequencePlayer : public UAnimGraphNode_Base

{

    GENERATED_BODY()

    UPROPERTY(EditAnywhere, Category=Settings)

    FAnimNode_SequencePlayer Node;

}

这就是最简单的 动画图表节点,其中包含动作行为节点对象。 

动画行为节点的执行,是通过FPoseLink或FComponentSpacePoseLink进行串联的。

FPoseLink 是本地骨骼空间的(其实是相对于父节点来说的), FComponetSpacePoseLink是控件空间的。

动画图表节点默认带有FPoseLink输出(也就是右侧的小人, 如果需要改变成FComponetSpacePoseLink, 需要重写CreateOutputPins,其中调用CreatePin。

virtual void CreateOutputPins() override;

void UAnimGraphNode_LocalToComponentSpace::CreateOutputPins()

{

       CreatePin(EGPD_Output, UAnimationGraphSchema::PC_Struct,  FComponentSpacePoseLink::StaticStruct(), TEXT("ComponentPose"));

}

动画行为节点类的构建

让我们看下FAnimNode_Base节点:

struct ENGINE_API FAnimNode_Base

{

    // Interface to implement,这就是你在你的动画行为节点中应该重写的几个函数

    virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) {}

    virtual void Update_AnyThread(const FAnimationUpdateContext& Context) {}

    virtual void Evaluate_AnyThread(FPoseContext& Output) { check(false); }

    virtual void EvaluateComponentSpace_AnyThread(FComponentSpacePoseContext& Output) { check(false); }

    virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {}

    virtual void GatherDebugData(FNodeDebugData& DebugData){}

};

有三个决定了您的节点如何表现的主要函数。它们是Initialize_AnyThread、Update_AnyThread和Evaluate_AnyThread,这里是对它们应用的简单描述:

  • Initialize_AnyThread - 任何时候当您需要进行初始化或重新初始化时调用该函数(当修改实例的网格物体时)。

  • Update_AnyThread - 调用该函数来更新当前状态(比如更新播放时间或混合权重)。该函数取入一个FAnimationUpdateContext,它知道更新的DeltaTime和当前的节点混合权重。

  • Evaluate_AnyThread - 调用该函数来生成一个‘姿势’(一系列的骨骼变换)。//当动画图表节点的输出是FPoseLink时,执行的是该函数, 如果是FComponetSpacePoseLink,执行的应该是EvaluateComponentSpace_AnyThread

  • EvaluateComponentSpace_AnyThread- 调用该函数来生成一个‘姿势’(一系列的骨骼变换)

最重要的就是Evaluate_AnyThreadEvaluateComponentSpace_AnyThread,其中最终的操作是骨骼变换的设置。

void FAnimNode_MYAnimNode::Evaluate_AnyThread(FPoseContext & Output){FName BoneName(TEXT("boneName"));//Output.Pose.GetBoneContainer()返回的FBoneContainer中,包含有当前网格体用到的骨架的引用,以及当前网格体用到的骨架中的真正用到的骨骼的索引数组。索引数组包含骨架的部分或全部。//OutPut.Pose中包含用到的骨骼的变换数组,骨骼变换数组与FBoneContainer中的索引数组相互对应。//GetPoseBoneIndexForBoneName是根据骨骼名称,获取骨骼的索引int32 MeshIndex = Output.Pose.GetBoneContainer().GetPoseBoneIndexForBoneName(BoneName);if (MeshIndex != INDEX_NONE){//MakeCompactPoseIndex 是根据骨骼的索引,找到骨骼索引在索引数组的位置,也就是OutPut.Pose中对应骨骼变化的变换数组的位置。FCompactPoseBoneIndex CPIndex = Output.Pose.GetBoneContainer().MakeCompactPoseIndex(FMeshPoseBoneIndex(MeshIndex));if (CPIndex != INDEX_NONE){FTransform boneTransfrom(FRotator(0.0f, 0.0f, 90.0f));Output.Pose[CPIndex] = boneTransfrom;}}//注意这时候当output.IsNormalized()返回false, Output.ContainsNaN() 返回true,这时候表示没有正确设置。尤其是当该节点与使用AnimNode_SaveCachePose一起使用,output传进来时,所有骨骼都没有设置正确的变换,这时候可以使用Output.ResetToRefPose(),将所有骨骼变换设置为参考姿势。}

在这些基本函数的基础上,您需要提供两个函数的实现,以确保您的节点可以正常同图表的其他部分协同工作

virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) {}

virtual void GatherDebugData(FNodeDebugData& DebugData){}

CacheBones_AnyThread用于刷新该节点所引用的骨骼索引,GatherDebugData用于使用"ShowDebug Animation"数据进行调试。为了保持到子项的连接,使用这些是很重要的。

FPoseLink 应该调用它下面的所有节点,以确保您的节点连接的任何姿势连接都会被调用。知道FPoseLink如何工作非常重要,因为任何时候当您调用任何动画函数时,您也必须调用该Pose函数。比如在您的Update_AnyThread函数中您应该调用BasePose->Update。同样,如果您有BasePose作为成员变量,您也应该在CacheBones_AnyThread函数中调用BasePose->CacheBones。(调用FPoseLink的对应函数,FPoseLink会找到它所连接的上一个节点,然后执行上一个节点的对应函数,节点对应函数调用的次序有点类似于递归,从最终动画姿势开始,一直到最开始,见下图)

请参照该示例:

void FAnimNode_BlendListBase::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)

{

    for(int32 ChildIndex=0; ChildIndex<BlendPose.Num(); ChildIndex++)

    {

        BlendPose[ChildIndex].CacheBones(Context);

    }

}

void FAnimNode_BlendListBase::Evaluate_AnyThread(FPoseContext& Output)

{

。。。

              for (int32 i = 0; i < PosesToEvaluate.Num(); ++i)

              {

                     int32 PoseIndex = PosesToEvaluate[i];

                     FPoseContext EvaluateContext(Output);

                     FPoseLink& CurrentPose = BlendPose[PoseIndex];

                     CurrentPose.Evaluate(EvaluateContext);

                     FilteredPoses[i].MoveBonesFrom(EvaluateContext.Pose);

                     FilteredCurve[i].MoveFrom(EvaluateContext.Curve);

              }

。。。

}

参见:https://www.unrealengine.com/zh-CN/blog/creating-custom-animation-nodes

UE4 创建自定义动画节点相关推荐

  1. 信创办公–基于WPS的PPT最佳实践系列 (创建自定义动画)

    信创办公–基于WPS的PPT最佳实践系列 (创建自定义动画) 目录 应用背景 操作步骤 1.动画效果创建 应用背景 动画效果能使幻灯片更加吸引人们,比单纯的文字和图片PPT更有趣味性,那该如何设置动画 ...

  2. UE4 创建自定义 Slate UI 控件

    UE4 创建自定义 Slate UI 控件 文章目录 UE4 创建自定义 Slate UI 控件 前言 一.什么是 Slate 二.创建自己的 Slate 控件 1.模块引用 2.定义 Slate 控 ...

  3. 用maya的api创建自定义的节点Creating Custom Locator

    原文地址 http://www.fevrierdorian.com/blog/post/2010/02/12/Creating-custom-locator-with-Maya-s-Python-AP ...

  4. 自定义动画属性java_创建酷炫动画效果的10个JavaScript库

    原标题:创建酷炫动画效果的10个JavaScript库 1) Dynamics.jsDynamics.js是设计基于物理规律的动画的重要Java库.它可以赋予生命给所有包含CSS 和SVG属性的DOM ...

  5. Android官方开发文档Training系列课程中文版:动画视图之创建自定义转场动画

    原文地址:http://android.xsoftlab.net/training/transitions/custom-transitions.html 自定义转场可以创建自定义动画.比如,可以定义 ...

  6. 13、Kanzi插件——通过Kanzi Engine插件创建自定义节点+代码解析

    一.通过插件创建自定义类型的节点 在类Plugindemo 中添加一行 static kanzi::PropertyTypeEditorInfoSharedPtr makeEditorInfo(); ...

  7. UE4 创建暂停和结束游戏UI

    效果: 步骤: 1.创建控件蓝图,命名为Pause 2.双击打开Pause,拖入一个边界控件并调整大小 3.更改下边界的颜色和透明度 4.将锚点居中,这样屏幕改变时,边界控件会向中间移动和缩放 5.将 ...

  8. Mr.J-- jQuery学习笔记(十八)--自定义动画

    animate(params,[speed],[easing],[fn]) 概述 用于创建自定义动画的函数. 这个函数的关键在于指定动画形式及结果样式属性对象.这个对象中每个属性都表示一个可以变化的样 ...

  9. JQuery中的animate自定义动画

    animate()方法用于创建自定义动画. 概述    .animate( properties [, duration ] [, easing ] [, complete ] )   propert ...

最新文章

  1. 40年产权的商业地产,个人投资者决不能碰
  2. 将数组按指定大小分组
  3. 电脑复制粘贴_手机扫一扫,现实物体隔空复制粘贴进电脑!北大校友的AI新研究,现在变成AR酷炫应用...
  4. 思达报表工具Style Report基础教程—创建一个多数据块的联合(Union)、镜像(Mirror)...
  5. python计数器Count
  6. FDDB数据集(人脸检测)
  7. 武汉互联网公司和生活成本
  8. 快手提前批--Java开发面经
  9. “金三银四“,敢不敢“试”?
  10. 关于VLOOUP函数与index match函数
  11. 天才啊!仅用四个整数编写一个贪吃蛇游戏!
  12. 【Linux】Linux命令详解
  13. 数据可视化(python代码实现)
  14. 抖音seo源码,抖音seo矩阵系统源码搭建技术+二开开源代码
  15. 【历史上的今天】11 月 16 日:RISC-V 领导者出生;微软发布 Windows CE;电子管问世
  16. Hold不住的老师 HNUST 1588
  17. 个人前端一些常用的网站
  18. 动态磁盘和基本磁盘转换
  19. LVS负载均衡与DR模式
  20. java系统自启动类和在线计数器

热门文章

  1. babylonjs创建坐标轴
  2. thinkpad重装系统不引导_联想电脑为什么重装win7系统后引导不了
  3. 【渝粤题库】国家开放大学2021春1040公司概论题目
  4. 【文献阅读笔记】KAM Theory Meets Statistical Learning Theory: Hamiltonian Neural Networks with Non-Zero Trai
  5. java腾讯滤镜接口_文档中心
  6. Mac安装与配置jmeterjmeter的使用jmeter生成性能测试报告
  7. Python随机生成一注双色球彩票
  8. IBM X3850 m2的一次win2003系统艰难的安装
  9. 【matlab应用】:生成老电影海报
  10. 【网络】为什么巨型帧会影响延迟?|网络的带宽,吞吐量,时延的理解|MTU