• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • YouClaw
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

逍遥流

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

Unreal4.21的骨骼动画BlendSpace的原理分析

Unreal动画混合权重(Weight)的原理分析

BlendSpace是unreal中动画二维混合工具,常见的应用有:主角战斗视角下速度和方向的locomotion动画混合,竖直方向和水平方向的lookat动画混合。

本文主要分析BlendSpace的实现原理,并不是使用教程。

编辑器Editor部分

基本原理

融合图中,所有白色的菱形点,都是策划拖动进来的动画(AnimSequence),这个在unreal引擎中叫BlendSamples,下文统一叫做采样点。

编辑器首先会对这些采样点从0开始进行编号,引擎后续对采样点的引用都用编号来表示;然后,会对这些采样点进行三角剖分,从而得到一系列的三角形。

在编辑器里,策划已经配置好了格子的行数和列数;编辑器会遍历所有格子点(GridElement),检查当前格子点所在的三角形,根据三角形的三个顶点,计算各自权重,融合得到格子点的动画信息。一个格子点的动画信息,就是三个采样点的编号和权重。

源码分析

编辑器的入口函数在:SAnimationBlendSpace.cpp SBlendSpaceEditor::ResampleData(),此函数的基本原理和我上述的描述类似,不再赘述。

下面重点介绍融合机制:就是如何从一个三角形的三个采样点,获取其中一个格子点的动画融合权重?

核心融合代码的调用关系为:

  • SBlendSpaceEditor::ResampleData  SAnimationBlendSpace.cpp
  • FBlendSpaceGrid::GenerateGridElements  AnimationBlendSpaceHelpers.cpp
  • FBlendSpaceGrid::FindTriangleThisPointBelongsTo  AnimationBlendSpaceHelpers.cpp
  • FMath::GetBaryCentric2D  UnrealMath.cpp
FVector FMath::GetBaryCentric2D(const FVector& Point, const FVector& A, const FVector& B, const FVector& C)
{
	float a = ((B.Y-C.Y)*(Point.X-C.X) + (C.X-B.X)*(Point.Y-C.Y)) / ((B.Y-C.Y)*(A.X-C.X) + (C.X-B.X)*(A.Y-C.Y));
	float b = ((C.Y-A.Y)*(Point.X-C.X) + (A.X-C.X)*(Point.Y-C.Y)) / ((B.Y-C.Y)*(A.X-C.X) + (C.X-B.X)*(A.Y-C.Y));

	return FVector(a, b, 1.0f - a - b);	
}

这里的数学知识可以温习下参考文献2

假设三角形为ABC,任意一格子点为P,A点对P的融合权重a == 三角形PBC的面积 / 三角形ABC的面积。

三角形PBC的面积 = PC X BC = (P.x - C.x) (B.y - C.y) - (B.x - C.x) * (P.y - C.y)

三角形ABC的面积 = AC X BC = (A.x - C.x) (B.y - C.y) - (B.x - C.x) * (A.y - C.y)

X表示向量叉乘运算,上面的简单推导证明了函数GetBaryCentric2D的正确性。

Runtime部分

基本原理

根据运行时输入的两个参数BlendInput,从而确定格子坐标GridIndex,找到所在格子,一个格子对应有四个格子点LeftTop、RightTop、LeftBottom、RightBottom。

引擎将每个格子,都Normalize为1 * 1的正方形,保证每个格子的总面积是 1。

BlendInput的点和LeftTop、RightTop、LeftBottom、RightBottom分别组成一个长方形,每个长方形的面积就是对应格子点的最终融合权重,基本原理和上面三角形融合类似。

源码分析

源码入口UBlendSpaceBase::TickAssetPlayer BlendSpaceBase.cpp
融合代码的调用堆栈:
  • UBlendSpaceBase::GetSamplesFromBlendInput BlendSpaceBase.cpp
  • UBlendSpace::GetRawSamplesFromBlendInput BlendSpace.cpp
  • UBlendSpace::GetGridSamplesFromBlendInput BlendSpace.cpp

Unreal的BlendSpace混合速率(timeScale)的原理分析

可以注意到,BlendSpace的每个Sample都有一个RateScale属性,表示当前Sample的播放速率。

BlendSpace允许出现两个Animation相同的Sample,而且这两个Sample的RateScale可以不同。

BlendSpace的最终播放速率的计算都在:Runtime阶段。

合并相同Animation的Sample

BlendSpace会把属性Animation相同的Samples,合并为一个Sample。

假设:Animation相同的Samples集合设为SameSamples,集合中第i个Sample用SameSamples[i]表示,合并后的Sample设为MergedSample。

MergedSample.RateScale的计算,可以按如下方式理解:

  • 先对SameSamples的Weights进行归一化(保证总和是1),设为NormalWeights
  • MergedSample.RateScale = Σ SameSamples[i].RateScale * NormalWeights[i]

MergedSample.Weight == Σ SameSamples[i].Weight

这块的代码在:UBlendSpaceBase::GetSamplesFromBlendInput BlendSpaceBase.cpp

按照Weight最高的Sample的RateScale进行播放

这块的源码直接看:UBlendSpaceBase::TickAssetPlayer BlendSpaceBase.cpp

 

参考文档:

1. https://api.unrealengine.com/INT/API/Runtime/Core/Math/FMath/GetBaryCentric2D/index.html
2. http://mathworld.wolfram.com/BarycentricCoordinates.html
3. https://docs-origin.unrealengine.com/latest/CHN/Engine/Animation/Blendspaces/index.html

posted on 2021-03-08 19:51  逍遥流  阅读(745)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3