UE5——动画混合

news2025/4/17 18:10:41

一、引言

关于动画的一些基础可以看我往期的文章:《UE5——动画重定向》

二、动画混合

1、动画混合的原理

动画: 我们知道动画实际上就是控制静态模型中的某些点按照一定的预定轨迹移动,简言之就是 “一组变换信息的集合”

动画混合: 多个动画里的每一条变换信息相互之间基于权重的运算

2、混合的方式

混合的方式有两种:覆盖、叠加
请添加图片描述

覆盖混合: 目标变换 = 原变换 * 权重

template<>
FORCEINLINE void BlendTransform<ETransformBlendMode::Overwrite>(const FTransform& Source, FTransform& Dest, const float BlendWeight)
{
	const ScalarRegister VBlendWeight(BlendWeight);
	Dest = Source * VBlendWeight;
}

叠加混合: 目标变换 = 目标变换 + (源变换 * 权重 )

template<>
FORCEINLINE void BlendTransform<ETransformBlendMode::Accumulate>(const FTransform& Source, FTransform& Dest, const float BlendWeight)
{
	const ScalarRegister VBlendWeight(BlendWeight);
	Dest.AccumulateWithShortestRotation(Source, VBlendWeight);
}

/**
* Accumulates another transform with this one, with an optional blending weight
*
* Rotation is accumulated additively, in the shortest direction (Rotation = Rotation +/- DeltaAtom.Rotation * Weight)
* Translation is accumulated additively (Translation += DeltaAtom.Translation * Weight)
* Scale3D is accumulated additively (Scale3D += DeltaAtom.Scale3D * Weight)
*
* @param DeltaAtom The other transform to accumulate into this one
* @param Weight The weight to multiply DeltaAtom by before it is accumulated.
*/
FORCEINLINE void AccumulateWithShortestRotation(const FTransform& DeltaAtom, float BlendWeight/* default param doesn't work since vectorized version takes ref param */)
{
	FTransform Atom(DeltaAtom * BlendWeight);

	// To ensure the 'shortest route', we make sure the dot product between the accumulator and the incoming child atom is positive.
	if ((Atom.Rotation | Rotation) < 0.f)
	{
		Rotation.X -= Atom.Rotation.X;
		Rotation.Y -= Atom.Rotation.Y;
		Rotation.Z -= Atom.Rotation.Z;
		Rotation.W -= Atom.Rotation.W;
	}
	else
	{
		Rotation.X += Atom.Rotation.X;
		Rotation.Y += Atom.Rotation.Y;
		Rotation.Z += Atom.Rotation.Z;
		Rotation.W += Atom.Rotation.W;
	}

	Translation += Atom.Translation;
	Scale3D += Atom.Scale3D;

	DiagnosticCheckNaN_All();
}

3、为什么要动画混合

根源: 动画混合能将多个原始动画姿势混合在一起,创建出新的动画姿势

混合在游戏中的应用

游戏中我们看到的动画往往都不是一个完整的动画,而是由多个动画片段组合起来的,常用的混合方式有以下几种:

1、线性插值: 角色的Idle动作walk动作 ,游戏中当这两个动画切换的时候我们并不会看到很突兀地动作变化,因为在Idle动作walk动作 之间添加了混合(平滑过渡)

2、动画叠加: 在原有的动画上叠加上另一个动画,比如角色的 Idle动作装弹动作 ,我们假设 Idle动作 只有下半身在动, 装弹动作只有上半身在动,那么将两者叠加得到的就是一个下半身在做 Idle动作 而上半身在做 装弹动作 的融合动作

3、骨骼的分层混合: 可以理解为我们可以控制两个动画的两块对应骨骼,按照不同的权重进行混合!比如角色的 run动作装弹动作run动作 作为基础动作,取 装弹动作上半身的动作进行权重为1的融合,那么将两者叠加得到的就是一个下半身在做 run动作 而上半身在做 装弹动作 的融合动作

PS:“动画叠加” 和 “骨骼的分层混合” 的不同之处在于,“动画叠加” 是进行叠加,而“骨骼的分层混合”是进行混合
①“骨骼的分层混合”的能够在原有的动画的基础上得到更多选择的融合动画;
②“动画叠加” 也是有他的优势的,例如表情,游戏中人物的面部骨骼排布大体上都是一致的,我们完全可以做出不同的表情动画到不同的人物上进行叠加,相比“骨骼的分层混合”是要更快并且方便!

三、UE5上实现

1、将两个动画按照权重进行混合

UE动画蓝图提供了一个最基础的节点 混合(Blend),可以将多个动作按照权重混合创建出新的动作。如下图
黄色(dest):融合后的动画
绿色(A):"run"动画
紫色(B):"jump"动画
下图权重(weight):0.5

请添加图片描述
请添加图片描述

请添加图片描述
通过观察不难发现,其混合方式为:
dest = A ×(1-weight) + B × weight, 0<weight<1
dest = A, weight≤0
dest = B, weight≥1

2、线性插值

请添加图片描述

图二:未添加线性插值

请添加图片描述
图一:添加了线性插值

请添加图片描述

通过线性插值的方式,将源动画逐渐混合至目标动画,达到了平滑过渡的效果

骨骼动画A、B可以表示为如下
在这里插入图片描述
动画内每个骨骼关节的线性插值表示为如下
在这里插入图片描述
因此整个动画的插值表示如下
在这里插入图片描述
上述β为 混合因子,β∈[0,1],上述过渡一般采用的都是时间混合,即 β ( t ) = t − t 1 t 2 − t 1 β(t) = \frac {t-t_1}{t_2-t_1} β(t)=t2t1tt1

上述混合节点还提供了除线性以外的其他混合类型,此处不展开介绍
在这里插入图片描述

3、动画叠加

我们采用 趴下动作装弹动作 ,我们在 动画蓝图中创建这两个动画片段以及一个 应用叠加型姿势(Apply Additive)节点 如下
请添加图片描述
趴下动作(源动作):
请添加图片描述
装弹动作(叠加动作):
请添加图片描述
叠加后的动作:
请添加图片描述
需要注意的是,对于叠加动作,我们需要在其动画片段内将其设置为Addtive,如图
请添加图片描述
Addtive的类型还有“网格体空间”,对应的如下节点,其余用法相同
请添加图片描述

4、骨骼的分层混合

UE动画蓝图提供了节点 按骨骼分层混合(Layered blend per bone),可以用于基于指定的一组骨骼在任意数量的动态混合姿势之间进行混合。如下图
黄色(dest):融合后的动画
蓝紫色(BasePose):"run"动画
天蓝色(BlendPose):"装弹"动画
下图权重(weight):1
请添加图片描述
请添加图片描述
请添加图片描述
如上面最后一图可以看到,角色上半身运行的是 “装弹动作”, 下半身运行的是 “run”动作,由于**“装弹动作”** 的下班身动作被过滤了,上面的 黄色(dest) 和 蓝紫色(BasePose) 是重叠的!!

下面主要讲一讲 “骨骼的分层混合”中的 骨骼名称(Bone Name)、混合深度(Blend Depth) 两个参数
在这里插入图片描述
请添加图片描述
结合官方文档及代码可以理解 混合深度(Blend Depth)

骨骼名称(Bone Name) 开始的整条骨骼链参与混合,权重为1;Blend Depth = 0
骨骼名称(Bone Name) 开始到第N层依次参与混合,权重为 w e i g h t ( n ) = n N , n 为 当 前 层 数 weight(n) =\frac{n}{N},n为当前层数 weight(n)=Nn,n,即越下层的混合程度越深;Blend Depth = N(N≠-1 & N≠0)
骨骼名称(Bone Name) 开始的整条骨骼链不参与混合;Blend Depth = -1

针对 Blend Depth = N(N≠-1 & N≠0) 举个例子说明:
骨骼名称 = spine
混合深度 = 2

各层的权重如下:

├─spine (0.5)
│  ├─spine1 (1)
│  │  ├─spine2 (2)

UE的问答上的参考例子(可以对着看)
What does the ‘Blend Depth’ parameter in ‘Layered Blend Per Bone’ do

参考资料

UE5混合节点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/49804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多功能手持读数仪VH03如何连接手机蓝牙

VH03 内置有基于 SPP&#xff08;Serial Port Profile&#xff09;协议的蓝牙接口&#xff0c;蓝牙名称为“VH03”。 使用任何支持 SPP 协议的蓝牙设备均可实现与 VH03 的连接。当蓝牙建立连接后&#xff0c;可向 VH03 发送指令进行交互&#xff08;前述 MODBUS、AABB、字符串…

CET-4 week9 阅读 写译

去# 阅读 question 定位 寻找有意义有目的 的动词符号 – &#xff0c; 转折词从句的解释说明理解超刚词不完全一样的地方要注意 注意匹配对应 answer 是否出现比较 比较对象 结果 article 重点长难句考点不在简单词上 选相反的答案或其他 仔细阅读 严格翻译题目 知道重点…

采用策略分布曲线评估信用风险模型的效果

在信贷业务的风控体系中&#xff0c;模型的构建与应用始终是一项重点内容&#xff0c;最常见的莫过于贷前环节的申请信用风险模型。作为典型的二分类模型&#xff0c;为了有效识别好坏用户群体&#xff0c;我们经常选取某些评价指标来量化模型的综合性能&#xff0c;例如KS、AU…

Java定时任务技术分析

《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成Spring Data JPA项目实操 数据库变更管理 数据库变更管理&#xff1a;Liquibase…

内存 管理

内存管理c/c中内存分布sizeof 与 strlenc 语言中动态内存管理方式malloccallocreallocc 中动态内存管理new 与 delete自定义类型空间的动态分配new 与 delete 的实现operator new 与 operator delete基本概念辨识malloc/free 与 new/delete 区别 *****内存泄漏c/c中内存分布 c…

手把手教你:CSS + JS实现文本交替

1. Koa 中间件 Koa 的中间件通过一种更加传统的方式进行级联&#xff0c;摒弃了以往 node 频繁的回调函数造成的复杂代码逻辑。使用异步函数&#xff0c;我们可以实现"真正" 的中间件。与之不同&#xff0c;当执行到 yield next 语句时&#xff0c;Koa 暂停了该中间…

Qt 在linux上检测内存泄漏,用valgrind的问题

我在ubuntu上装了Qt5.15.2, 打开我的项目后&#xff0c;准备检测内存泄漏问题。 此时&#xff1a; 内存检测工具都是可用状态&#xff0c;但点击内存检测后&#xff0c;进度条走完后&#xff0c;就结束了。项目都没启动起来&#xff0c;这怎么检测内存问题&#xff1f; 然后&…

11月30日(第二天)

序列化&#xff1a;implements Serializable&#xff0c;public final static Long SeriaVersionUid 1L;MP的使用步骤&#xff1a;在BookBO类上使用TableName(“表名")去关联&#xff0c;在字段上使用TableId&#xff0c;TableField进行字段关联。(最好新建一个BookVO类,…

嫦娥五号探测器详细介绍

嫦娥五号&#xff08;Change 5&#xff09;&#xff0c;即嫦娥五号探测器&#xff0c;是由中国空间技术研究院研制的中国首个实施无人月面取样返回的航天器&#xff0c;是完成中国探月工程重大科技专项“绕、落、回”三步走发展战略最后一步的关键任务。 中国探月工程三步走 嫦…

Linux 主机间ssh相互免密

Linux 主机间ssh相互免密两步实现ssh主机免密详细教程请往下看主机间ssh相互免密 —— 方法一主备两台未配置密钥主机作为测试生成公私密钥拷贝公钥到目标主机ssh免密测试主机间ssh相互免密——方法二实验准备分发密钥对免密测试MobaXterm免密登录服务器&#xff08;以ecs-4207…

SAP中的PI接口

文章目录1 Pi overall2 Create pi process3 Inbound interface4 Outbound interface5 Matter need attention6 Pi test7 View log8 Transport CTS1 Pi overall What is the pi ? Pi is Sap’s middle software . it is interacted with SAP an external system. 2 Create p…

【Python】Python 中实现数据序列化

文章目录一、前言二、为什么要进行序列化三、Python 中的数据序列化1. json模块2. pickle模块3. shelve模块4. 总结参考链接一、前言 首先&#xff0c;要了解什么是序列化&#xff0c;请参考我的另一篇文章&#xff1a;序列化与反序列化介绍 本文主要介绍 Python 中的数据序列…

i.MX 6ULL 驱动开发 二十七:块设备

参考&#xff1a;【块设备】通用块层 struct bio 详解 | zzm (aliez22.github.io) 一、Linux 中块设备驱动框架 二、块设备基本概念 1、扇区的概念来自硬件&#xff0c;扇区是硬件最小操作单位。 2、块的概念来自文件系统&#xff0c;是文件系统数据处理的最小单位。 3、段…

django 开启CSRFtoken校验,以及postman实现问题

1.0 Django默认的CSRFtoken 表现&#xff1a; 后端使用的是Django的表单验证 post请求携带参数的问题 2.0 先处理post请求携带数据的csrfmiddlewaretoken 在登录界面 在input输入框中隐藏&#xff0c;所以需要提取input的value值&#xff0c;在【tests】脚本中进行提取&…

小样本关系分类(原型学习):Better Few-Shot Relation Extraction with Label Prompt Dropout

Better Few-Shot Relation Extraction with Label Prompt Dropout core idea 在小样本关系分类中&#xff0c;prompt信息是relation name是信息&#xff0c;这篇文章为了保持train和test的一致性&#xff0c;将train中的一些relation name信息删除掉了。&#xff08;相反&…

linux应用移植问题

背景 公司设备降成本&#xff0c;设备运行平台从armv7架构mpu换成了armv5架构的mpu&#xff0c;应用移植过程都挺顺利的&#xff0c;只是牵涉到一个引用外部库的应用时&#xff0c;运行该应用到引用库中的函数时&#xff0c;应用抛出illegal instrution异常。 问题分析 初步…

HTML(超文本标记语言)

HTML(超文本标记语言) 网页的基本信息 、等成对的标签&#xff0c;分别叫**开放标签**和**闭合标签**&#xff0c;单独呈现的标签(空元素)&#xff0c;如&#xff1b;意为用 / 来关闭空元素 DOCTYPE&#xff1a;告诉浏览器&#xff0c;我们要使用什么规范 head&#xff1a;代…

Jenkins安装与配置Windows11系统

目录 Jenkins安装 一、下载 官网地址&#xff1a;Jenkins download and deployment 点击LTS&#xff08;长期稳定版&#xff09;下的Windows 二、安装 基本就是一路Next即可 三、配置 访问地址 http://localhost:8080/&#xff0c;会出现如下界面&#xff1a; 安装 注&…

Redis实战——优惠券秒杀(一人一单业务)

需求&#xff1a;修改秒杀业务&#xff0c;要求同一个优惠券&#xff0c;一个用户只能下一单 我们只需要在增加订单之前&#xff0c;拿用户id和优惠券id判断订单是否已经存在&#xff0c;如果存在&#xff0c;说明用户已经购买。 代码实现&#xff1a; package com.hmdp.serv…

狂神说Go语言学习笔记(二)

一、匿名变量 匿名变量的特点是一个下划线 “_”&#xff0c;它本身就是一个特殊的标识符。它可以像其他标识符那样用于变量的声明或赋值&#xff08;任何类型都可以赋值给它&#xff09;&#xff0c;但任何赋给这个标识符的值都将被抛弃&#xff0c;因此这些值不能在后续的代…