参考:Animation Blend Profile in Unity
参考:Unreal Engine - How to make a Blend Profile
参考:blend-masks-and-blend-profiles-in-unreal-engine

什么是Blend Profile

Animation Blend Profile is a UE4 animation system feature that enables us to set blend speed of each bone separately.

这个概念是在UE4的动画系统里提出的feature,可以让我们设置每个Bone的blend speed。如果没有这玩意儿,正常动画Blend时,所有的Bone的Blend Speed都是相同的。

这个功能可以有效解决movement动画之间的transition造成的滑步问题,同时保证上半身动画的流畅性。

这种动画的转态,比如Idle和Moving的切换,悬空和落地的切换,都是极度需要Blend Profile功能的,我估计这个原理是让上半身的Blend Speed和下半身的BlendSpeed不同,从而保证上半身动画流畅的同时,解决下半身的滑步问题。

举个细节的例子,从动画A到动画B的Transition Time为0.5s,如果是线性Blend,那么正常Joint X在Blend时的A的权重为1,B的权重为0,那么0.5s后,A的权重会从1线性减少到0,B的权重从0线性增加到1。如果此时我把Joint Y的Blend Speed设置为X的两倍,那么Y会在0.25s内从A动画过渡到B,如下图所示:

UE的动画过渡里就可以使用Blend Profile,如下图所示:

而且Blend Space里也可以设置Blend Profile,因为Blend Space的本质就是处理动画的Blend,如下图所示是在Blend Space里的设置:

Blend Mask是什么

在UE的源码里,Blend Mask类型为EBlendProfileMode的一种,也就是说UE认为它是一种Blend Profile:

enum class EBlendProfileMode : uint8
{// The bone's transition time is a factor based on the transition time. // For example 0.5 means it takes half the time of the transition.// Values should be between 0 and 1. They will be clamped if they go out of this range.// A bone value of 0 means the bone will instantly transition into the target state.TimeFactor = 0,// 值必须<=1// The bone's transition weight is multiplied by this factor.// For example 2.0 means the bone's blend weight is twice as high as the transition's blend weight.// Values should typically be equal or greater than 1.0.// If you want certain bones to instantly transition into the target state// the Time Factor based method might be a better choice.WeightFactor,// 值必须>=1// Used for blend masks. Per bone alphaBlendMask UMETA(Hidden),
};

感觉UE里认为,能够改变joint影响Blend时的joint的权重设置的东西,都属于Blend Profile,所以它才把Blend Mask也归类为Blend Profile的一种。Blend Mask跟其他类型的Blend Profile不同,它并不会加速blend过程中各个joint的权重值的改变,它只能决定各个joint的权重值的改变是否随着MainWeight改变,改变的程度是多少(范围在[0, 1]区间),类似于Unity的AvatarMask

Blend Mask的用法

创建和编辑的操作跟其他类型的Blend Profile是差不多的:

默认Blend Mask的每个Bone的BlendScale值为0,可供选择的范围在[0, 1]区间,0代表此Bone完全不受Blend Profile影响

具体使用时要通过动画蓝图的Layered Blend Per Bone节点实现,如下图所示:

蓝图连接逻辑如下图所示,其实这里的Blend Mask很像Unity里的Avatar Mask

Blend Profile的使用场景

Blend Mask应该是只能用在Layered Blend Per Bone里,而Weight Factor和Time Factor类型的Blend Profile会被用在这五个地方:

  • Blend Poses by bool.
  • Blend Poses by int.
  • Blend Poses by enum.
  • State Machine Transitions.
  • Animation Montages.

BlendSpace里有类似的设置,不过不是BlendProfile,而是叫Target Weight Interpolation Speed Per Sec。

这里的五种节点都会最终调用UBlendProfile::CalculateBoneWeight函数,计算每个Bone在Blend过程中的权重值,无非调用地点有所区别:

  • Blend Poses by bool,Blend Poses by int和Blend Poses by enum都继承于FAnimNode_BlendListBase类,会在里面的Update_AnyThread函数里被调用
  • State Machine Transitions则是在FAnimationActiveTransitionEntry::Update里被调用
  • Animation Montages则是通过AnimationSlot,在FAnimInstanceProxy::SlotEvaluatePoseWithBlendProfiles里被调用的,当AnimationSlotNode在其Evaluate函数里发现了处于Blend状态下的Montage,且设置了BlendProfile时,会调用SlotEvaluatePoseWithBlendProfiles函数

UE相关源码记录

这里拿动画状态机里BlendProfile的应用举例,我在动画的转态上加了个Blend Profile,源码里的CallStack顺序如下:

图中的展示顺序表示,最终调用的UBlendProfile::UpdateBoneWeights的caller是statieMachine对应的AnimNode(FAnimNode_StateMachine::Update_AnyThread函数),对应的状态机节点会遍历每个动画Transition的对象,然后根据是否存在BlendProfile改变骨骼权重:

void FAnimationActiveTransitionEntry::Update(const FAnimationUpdateContext& Context, int32 CurrentStateIndex, bool& bOutFinished)
{bOutFinished = false;// Advance timeif (bActive){ElapsedTime += Context.GetDeltaTime();Blend.Update(Context.GetDeltaTime());// If non-zero, calculate the query alphafloat QueryAlpha = 0.0f;if (CrossfadeDuration > 0.0f){QueryAlpha = ElapsedTime / CrossfadeDuration;}Alpha = FAlphaBlend::AlphaToBlendOption(QueryAlpha, Blend.GetBlendOption(), Blend.GetCustomCurve());if (Blend.IsComplete()){bActive = false;bOutFinished = true;}// Update state blend data (only when we're using per-bone)if (BlendProfile){for (int32 Idx = 0 ; Idx < 2 ; ++Idx){const bool bForwards = (Idx == 0);StateBlendData[Idx].TotalWeight = bForwards ? Alpha : 1.0f - Alpha;BlendProfile->UpdateBoneWeights(StateBlendData[Idx], Blend, 0.0f, StateBlendData[Idx].TotalWeight, !bForwards);}FBlendSampleData::NormalizeDataWeight(StateBlendData);}}
}

Montage里的Blend Profile

相关设置不在LayeredBlendPerBone或者AnimationSlotNode的蓝图Details面板上,而是在Montage资产里,如下图所示,可以选择在Blend In Montage和Blend Out Montage时使用Blend Profile:

三种模式下的BlendProfile

UE的枚举叫EBlendProfileMode:

/** The mode in which the blend profile should be applied. */
UENUM()
enum class EBlendProfileMode : uint8
{// The bone's transition time is a factor based on the transition time. // For example 0.5 means it takes half the time of the transition.// 注意这里设置0.5并不是0.5秒的意思, 而是指的TransitionTime的一半// Values should be between 0 and 1. They will be clamped if they go out of this range.// A bone value of 0 means the bone will instantly transition into the target state.TimeFactor = 0,// The bone's transition weight is multiplied by this factor.// For example 2.0 means the bone's blend weight is twice as high as the transition's blend weight.// Values should typically be equal or greater than 1.0.// If you want certain bones to instantly transition into the target state// the Time Factor based method might be a better choice.WeightFactor,// Used for blend masks. Per bone alphaBlendMask UMETA(Hidden),
};

TimeFactorWeightFactor模式的区别在于权重的计算方法不同,其他基本没任何区别,WeightFactor算法其实很简单,直接根据原本的PoseWeight乘以对应的BlendProfile即可:

float UBlendProfile::CalculateBoneWeight(float BoneFactor, EBlendProfileMode Mode, const FAlphaBlend& BlendInfo, float BlendStartAlpha, float MainWeight, bool bInverse)
{switch (Mode){// The per bone value is a factor of the transition time, where 0.5 means half the transition time, 0.1 means one tenth of the transition time, etc.case EBlendProfileMode::TimeFactor:{// Most bones will have a bone factor of 1, so let's optimize that case.// Basically it means it will just follow the main weight.if (BoneFactor >= 1.0f - ZERO_ANIMWEIGHT_THRESH){return !bInverse ? MainWeight : 1.0f - MainWeight;}// Make sure our input values are valid, which is between 0 and 1.const float ClampedFactor = FMath::Clamp(BoneFactor, 0.0f, 1.0f);// Calculate where blend begin value is for this specific bone. So where did our blend start from?// Note that this isn't just the BlendInfo.GetBlendedValue() because it can be different per bone as some bones are further ahead in time.// We also need to sample the actual curve for this to get the real value.const float BeginValue = (ClampedFactor > ZERO_ANIMWEIGHT_THRESH) ? FMath::Clamp(BlendStartAlpha / ClampedFactor, 0.0f, 1.0f) : 1.0f;const float RealBeginValue = FAlphaBlend::AlphaToBlendOption(BeginValue, BlendInfo.GetBlendOption(), BlendInfo.GetCustomCurve());// Calculate the current alpha value for the bone.// As some bones can blend faster than others, we basically scale the current blend's alpha by the bone's factor.// After that we sample the curve to get the real alpha blend value.const float LinearAlpha = (ClampedFactor > ZERO_ANIMWEIGHT_THRESH) ? FMath::Clamp(BlendInfo.GetAlpha() / ClampedFactor, 0.0f, 1.0f) : 1.0f;const float RealBoneAlpha = FAlphaBlend::AlphaToBlendOption(LinearAlpha, BlendInfo.GetBlendOption(), BlendInfo.GetCustomCurve());// Now that we know the alpha for our blend, we can calculate the actual weight value.// Also make sure the bone weight is valid. Values can't be zero because this could introduce issues during normalization internally in the pipeline.const float BoneWeight = RealBeginValue + RealBoneAlpha * (BlendInfo.GetDesiredValue() - RealBeginValue);const float ClampedBoneWeight = FMath::Clamp(BoneWeight, ZERO_ANIMWEIGHT_THRESH, 1.0f);// Return our calculated weight, depending whether we'd like to invert it or not.return !bInverse ? ClampedBoneWeight : (1.0f - ClampedBoneWeight);}// The per bone value is a factor of the main blend's weight.case EBlendProfileMode::WeightFactor:{if (!bInverse){return FMath::Max(MainWeight * BoneFactor, ZERO_ANIMWEIGHT_THRESH);}// We're inversing.const float Weight = (BoneFactor > ZERO_ANIMWEIGHT_THRESH) ? MainWeight / BoneFactor : 1.0f;return FMath::Max(Weight, ZERO_ANIMWEIGHT_THRESH);}// Handle unsupported modes.// If you reach this point you have to add another case statement for your newly added blend profile mode.default:{checkf(false, TEXT("The selected Blend Profile Mode is not supported (Mode=%d)"), Mode);break;}}return MainWeight;
}

这里面没有对BlendMask这种模式的处理,因为BlendMask是专门用于 Layered Blend Per Bone节点上的,

这里的TimeFactor和WeightFactor的BlendProfile的使用机制是差不多的,但UE的文档告诉我,这里weightFactor模式下的值应该>=1,而TimeFactor下的值应该<=1,如下所示:

这说明Blend Profile只能加速动画转态里的特定joint的Blend速度,而不能减速,顺便看了下代码里面,也是这么个逻辑。感觉也比较合理,毕竟动画转态时间外部已经给定了,所以只能加速部分joints的转态,而不能减速。

附录

Unity里实现Blend Profile

首先,既然是逐Bone Blend,那么需要有个编辑的地方,去设置每个Bone的Blend速度,可以选择在AvatarMask界面里编辑,如下图所示(注意这里的时间至少是1, otherwise there would be some problem with transition time):

然后在动画状态机的Transition里设置加上对应的Blend Profile借助的Avatar Mask即可:

Unity的BlendTree里使用Blend Profile

其实就跟UE的Blend Space里用Blend Profile是一样的,UE里Blend Space有这么个设置:

也是类似的,在Blend Tree的Inspector界面里添加Avatar Mask即可:

UE的Blend Profile相关推荐

  1. UE4 Advance Locomotion V4 学习

    这是个人学习ALS过程中的一点笔记,不对的地方谢谢指出~ 从开始看 在跑步动画中进行脚落地,摄像机摇动,和左右脚区分,这个weight--gait曲线用于区分动画,使用见下面 针对小跑和快跑,使用当前 ...

  2. 5G QoS控制原理专题详解-基础概念(2)

    相关文章会在公众号同步更新.公众号:5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理,保证更新内容的准确性,避免通过二手,甚至多手的资料,以讹传讹误导网友. 在介绍完流程详解后,会整理专 ...

  3. UE动画节点 —— Blend Node

    参考:https://docs.unrealengine.com/5.0/en-US/animation-blueprint-blend-nodes-in-unreal-engine/ Blend N ...

  4. UE 手游在 iOS 平台运行时内存占用太高?试试这样着手优化

    性能优化,对游戏开发来说是一个需要不断钻研的课题,性能越好,游戏才会运行的更加顺畅,玩家的体验感才会更好.腾讯游戏学院专家.游戏客户端开发 Leonn,将和大家分享 UE 手游在 iOS 平台上的内存 ...

  5. cobalt strike profile

    cobalt strike 配置解读 此处以最新版 jquery-c2.4.3.profile文件解析 适应Cobalt Strike 4.3 版本 其他版本会有标注 cobalt strike 4. ...

  6. 5G系统——UE移动性

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/u010178611/article/d ...

  7. UE Gameplay实例49(高级蒙太奇动画连招)

    这个连招系统是在YTB上搬运过来的,也是自我接触UE以来,认为最好用,最高级的一个连招使用方式, 非常完美的利用了UE中强大的动画编辑器来实现连招,对于程序员来说轻松.省事:对于策划来说, 我可以随便 ...

  8. 学习在UE中导入 Morph Targets 资源

    前言 "Morph Targets" 指设定一个或多个目标,然后使顶点朝着目标变形. 我查到UE中有两种实现方式: 基于骨骼Mesh的. 基于StaticMesh的.详见Stati ...

  9. 90天入门UE引擎开发--学习日记(60/100)

    教程 Game艺视界 - Ben UE5着色器材质节点 快捷键 D键   缩小图片节点 A键   Add M键  Multiply D键   Divide 介绍面板 节点里第三层是最重要的 新建工程 ...

最新文章

  1. 实现人脸识别性别之路---open CV将图片显示出来
  2. 从尼古拉斯·泽卡斯开始学习
  3. Windows下编程需要看哪些书
  4. 孩子在华艺舞校的画画投稿-天女之梦
  5. spring boot 1.4默认使用 hibernate validator
  6. 继续畅通工程(HDU-1879 )
  7. Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine
  8. 量化策略回测01双均线
  9. Andorid Studio NDK 开发 - Hello World
  10. MongoDB实战-面向文档的数据(找到最合适的数据建模方式)
  11. VTD的文件结构和Project建立的思路
  12. python下载百度文库文档_Python百度文库爬虫之txt文件
  13. 校招行测笔试--资料分析
  14. mybatis 使用简单的增删查改
  15. 计算机高手如何操作键盘,从小白到高手 游戏键盘驱动全面解析
  16. 「干货」从动态的角度分析DDR的时序结构
  17. 采购证书有了解过吗?
  18. 基于Openwrt 拨号上网(SDX55) (PCIe)移植文档
  19. 新能源汽车应该何去何从?
  20. 四川大学计算机专业调剂,2019年四川大学计算机学院(软件学院)考研调剂信息

热门文章

  1. 有哪些冷门却好用的东西可以网购?
  2. cogs 944. [東方S3] 藤原妹红
  3. 05导航指示-04树状导航栏-navlistview
  4. Sigma Designs SMP8910媒体处理器的3DTV、蓝光和OTT体验
  5. 解决EMD端点效应的方法比较
  6. typora上传图片小白教程
  7. Java截取视频生成Gif动图
  8. 12306 java程序_基于java httpclient的12306 买票软件
  9. php中文数组按拼音排序问题
  10. (随时增加)linux编译错误集锦