Unity AnimationClip详解(2)——动画数据的优化

【内存优化】

首先要意识到运行时和编辑时的区别,当运行时和编辑时所需的数据相差不大时,我们用同一套数据结构即可,当两者差异较多或者数据量很大时,需要有各自的数据结构,这意味着在打包或构建时需要将编辑时数据转为运行时数据。

(所以Unity中的AnimationClip Curve数据不提供给非editor情况下使用)

(内存优化把握三个核心方向:一是内存中只存在当前或最近需要的资源及数据;二是需要的资源及数据在内存中仅存在一份;三是简化资源和数据的结构,运行时和编辑时的数据区分是方向1)

由前文可知,动画至少有30个骨骼节点,每个至少有9条Curve曲线,每个Curve曲线有60个KeyFrame,按照编辑时的Keyframe的结构,1s的动画至少需要30*9*60*8*4/1024 =506.25kb的内存

高品质的动作游戏的骨骼节点会更多,1s内的动画数据占用的内存会超过506.25kb。

一般而言,内存中存在的所有动画数据时长加起来超过30分钟很正常,那么占用内存至少为506.25*60*30/1024 = 889.89MB

这么大的内存在移动端是不可接受的。

根据计算公式,我们可以从多个方面优化内存。

优化关键帧结构

在运行时我们只需要知道曲线函数即可,编辑时点的数据可直接转为函数参数,从前文可知函数,可以有:

  • 水平线(即常量),点的值
  • 直线,y= ax+b ,两个值
  • 三次多项式,y= ax^3 + bx^2 + cx + d 四个值
  • 二次贝塞尔曲线  B(t) = (1-t)^2 * P0 + 2t(1-t) * P1 + t^2 * P2,展开后为y= ax^2 + bx + c,三个值
  • 三次贝塞尔曲线  B(t) = (1 − t)^3 *P0 + 3t (1 − t)^2 *P1 + 3t^2 (1 − t)*P2 + t3* P3,展开后为y= ax^3 + bx^2 + cx + d 四个值
  • 三次埃尔米特曲线,展开后为y= ax^3 + bx^2 + cx + d 四个值

可以看到,他们都是同样的形式,不必再区分具体的类型,只要有四个参数值即可。

那么运行时关键帧的数据结构A为:

    ///Struct KeyFrame{
    ///     float a
    ///     float b
    ///     float c
    ///     float d
    ///}

按照这个优化,内存将降低为原来的一半,为444.95MB。

接下来还按照核心方向3来优化:

uint类型有32位,分成4份,每份有8位,我们用高位标记其实小数点后几位,剩余7位表示参数值,可表示的最大精度为0.0000001,这个精度基本够了

按照这个方式运行时关键帧结构B为:uint keyFrame

内存将降低为原来的1/8,为:111.24MB(下文以这个为准)

优化曲线结构

曲线核心数据是关键帧数据的组合,优化要依靠不同关键帧之前的关联(类似数据压缩中上下文联系)来简化数据(核心方向3),有以下关联:

1.如果曲线中所有关键帧都是常量,我们用一个数据就可以,在关键帧数据结构A中,内存占用降低为原来的1/(60*4);在关键帧数据结构B中,内存占用降低为原来的1/60。例如:盆骨节点的部分曲线基本都是常量

2.如果曲线中有部分连续的常量,我们可以需要标识出从第几帧到第几帧是常量,这是不用一个数组表示了,需要用一个类封装,这也是划算的

3.如果曲线中所有关键帧都是直线,在关键帧数据结构A中,可以去掉c、d,内存占用降低为原来的1/2;在关键帧数据结构B中,可以用short类型,内存占用降低为原来的1/2

以上优化都属于核心方向3中的方法1:转换数据结构,其特点是不损失数据精度

在允许精度损失的情况下,我们有了方法2:朝着符合转换数据结构的情况精简数据

针对关联1:我们可以设置一个阈值N,凡是变化在阈值内的数据,都认为是常量

在游戏行业,动画数据生成的方式一般有三种:1.美术在3D软件中手K 2.动捕 3.AI生成。其中动捕或AI生成会产生较多抖动细节,都可以去掉以生成更多的常量。

针对关联2:我们需要在曲线的所有位置都检测是否存在常量,一些斜率很小的直线可以简化为常量

针对关联3:有些其他曲线完全很小,可以近似简化为直线,以尝试获得更多的直线

(有些算法常识,你应该可以知道,上述所有阈值,都可以做自适应。

理论上,自适应是针对不同情况的,对当前曲线有自适应值,对不同情况下生成的近似曲线也要有不同的自适应值;对不同的肢体,例如手部、腿部、面部的自适应值不同,越靠近根骨骼,所需精度越高,允许的误差阈值越小。

实际上,为了简化,可能都是一样的自适应值。)

允许有精度损失时,还有其他关联:

4.连续多个关键帧数据可以通过一条曲线拟合,实际上这种情况是很常见的,只要不是突兀的变化,时间是在1/60s这样小的时间尺度下,多个连续帧是按照同一规律渐变的,可以用同一条曲线拟合。

注意,我们并不是一次性拟合整条曲线,而是对曲线分段拟合

综合以上关联,优化后的曲线结构中,关键帧数据不再是数组,而是一个封装关键帧数据的类或结构体。在Unity中,表现为IntPtr m_Ptr。

一般来说,常量占到曲线的60%-80%,直线占比为20%~30%,其他各类曲线占比20~30%,假设30%关键帧数据可以做拟合。

做保守估计,常量取60%,直线取20%,其他各类曲线取20%,优化后的内存为:111.24*60%/60 + 111.24*20%/2 + 111.24*20%*(60 - 60*30%+1 )/60 = 28.181MB

优化关键帧数量

有些动作变化简单,例如walk、run等,实际上不需要60帧,2D动漫也常用做这样的减帧处理。(核心方向3的方法3:减少数据量)

因为大部分动作都是平滑的,我们可以预测下一帧的数据,从而减少帧数。曲线拟合也可以看作是减帧,与预测不同的是,曲线拟合有精度要求,无论动画正放还是倒放都无影响,且不需要前置数据。

而预测首先的有几帧的前置数据,由于是从前到后预测,动画不能倒放,预测最好是完全准确的,在阈值内有偏差也可,超过阈值,记录一个delta即可校正。

假设通过上述方式,可以将平均帧数降低为40帧,那么优化后的内存为:28.181 * 40 / 60 = 18.787MB

优化曲线数量

上述的优化都是基于数据本身做优化,并没有考虑到数据所在的场景。在动作中,节点位置、朝向、缩放的三条曲线之前是有关联的,我们完全可以将其做进一步的封装。

例如:xz可能共同绕着y做同样规律的变化,或者xy绕着z做同样规律的变化,考虑人体结构和肢体动作,这是很常见的,减少30%-50%的数据是可能的。例如Unity内部的QuaternionCurve,Vector3Curve

对于缩放,一般情况下角色没有缩放,可以直接去掉缩放曲线。

假设去掉Scale曲线,并做30%优化,那么优化后的内存为:18.787 * (6/9)*70% =  8.767MB

优化节点数量

角色骨骼节点数量在项目之初就确定好的,不会随意更改,这里要结合核心方向1来做优化。

更多的骨骼节点是为了走更精致、品质更高的动作,在不在视野内、或距离视野很远的角色而言,精致的动作也看不到,角色不需要或仅需要很少的动画,也相当于一些节点的数据直接可以省略掉,不用在内存中存在。

假设只能优化10%的节点点,那么优化后内存为:8.767 * 90% = 7.908MB

综上,内存可以从889.89MB优化到7.908MB,至少可以优化88%

压缩优化

按照数据压缩中的方法,将动画数据做压缩(注意选择高性能的压缩方法),使用时再解压数据。

加载优化

主要是按照方向1别把不需要的动画数据加载到内存中。

unity中的优化设置

Unity针对AnimationClip提供三种压缩格式:

1.Off——不做压缩处理,动画中每一帧都生成关键帧

2.Keyframe Reduction——Stream格式存储,使用关键帧缩减算法(简单来讲,就是对去除关键帧前后的曲线进行比较,如果对应的曲线值的差小于容错值/误差宽容度,则去掉关键帧)

3.Optimal——Unity会使用启发式算法,从而决定使用Keyframe Reduction算法进行压缩(Stream格式存储),或者使用Dense格式压缩存储动画曲

Stream格式可以认为是带有曲线的;Dense格式是存储所有关键帧数据,用线性插值,可以看作是直线的,内存占用比Stream少

Inspector上可以看到不同类型曲线占据的大小

Rotation/Position/Scale Error是压缩时的阈值

可以对不同的动画资源选择合适的压缩格式和阈值

包体优化

一般来说,游戏内所有的动画数据时长加起来有6个小时比较正常,内存优化的某些方式,也会减少包体大小。

同时,压缩优化是必须的,在内存中的动画数据可以是非压缩的,在硬盘上的动画数据一般是压缩后的,读取文件时要先解压。

【性能优化】

这里的优化仅针对AnimationClip,由于解压、采样、计算都由引擎内部做处理,在不改源码的情况下,可以做的不多。

加载优化

在合适的时机做加载,以减少峰值卡顿等

缓存友好

 让数据的排布更符合读取的顺序,减少CPU cache miss的情况,例如由三条曲线,四个关键帧的数据,一般都是这样的:

    /// 曲线1:关键帧1 关键帧2 关键帧3 关键帧4
    /// 曲线2:关键帧1 关键帧2 关键帧3 关键帧4
    /// 曲线3:关键帧1 关键帧2 关键帧3 关键帧4
    /// 曲线4:关键帧1 关键帧2 关键帧3 关键帧4

改成:

    /// 关键帧1:曲线1 曲线2 曲线3 曲线4
    /// 关键帧2:曲线1 曲线2 曲线3 曲线4
    /// 关键帧3:曲线1 曲线2 曲线3 曲线4
    /// 关键帧4:曲线1 曲线2 曲线3 曲线4

由于各类压缩和优化内存的方式,缓存友好的方式改动难度很大

Job计算

多个不同的AnimationClip的数据的采样、计算可以放在Job中进行

采样降频

动画数据采样是指,输入一个时间,从曲线中得到一个值,每秒要进行很多次这样的采样。一般来说,会有预设的固定值,或者按照Update的频率采样。

但我们可以结合业务实际去调整采样的频率,类似常见物体LOD的概念,我们可以根据角色和相机的距离来设置动画的采样频率。

在Unity中,如果项目使用了Playable做动作系统,可以使用Playable.Evaluate来手动更新,降低频率

【加载优化】

加载关乎到内存和性能,这里拿出来单独说,从加载系统的交互看,动画资源和其他资源没什么区别,以下加载优化的方式适用其他任何资源的加载优化

内存上

按需加载

动态卸载

性能上

提前加载:有些基础性的动画资源是必然会存在的,可以在切场景时提前加载到内存中

设置加载优先级:动画资源的加载优先级设置高些,让加载系统优先加载动画

异步加载:动画资源从同步加载改成异步加载,且需要加上时间限制,固定多少帧内必须加载完成

分帧请求加载:一次性需要加载的动画资源较多,分成多帧去请求

预测加载:可以在逻辑上预测哪些动画资源可能在接下来需要加载,提前做加载,以避免集中加载导致卡顿

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

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

相关文章

【Linux探索学习】第七弹——Linux的工具(二):Linux下vim编辑器的使用详解

Linux的工具(一):【Linux探索学习】第六弹——Linux的工具(一):Ubuntu系统下的软件包管理器_ubuntu软件管理器-CSDN博客 前言: 在学习Linux之前,相信大家都或多或少的学习过一些计算…

微信小程序用开发工具在本地真机调试可以正常访问摄像头,发布了授权后却无法访问摄像头,解决方案

今天开发上线了一个拍照的微信小程序&#xff0c;用uniapp的Vue3开发的&#xff0c;调用的camera组件&#xff0c;相关代码如下&#xff1a; <!-- 微信小程序相机组件 --><view v-if"showCamera" class"camera-container"><camera :device…

Adobe Acrobat DC 打印PDF文件,没有打印出注释的解决方法

adobe acrobat在打印的时候&#xff0c;打印不出来注释内容&#xff08;之前一直可以&#xff0c;突然就不行&#xff09;&#xff0c;升级版本、嵌入字体等等都试过&#xff0c;也在Google找了半天和问了GPT也么找着办法。 无奈之下&#xff0c;自己通过印前检查&#xff0c;…

免费开源AI助手,颠覆你的数字生活体验

Apt Full作为一款开源且完全免费的软件&#xff0c;除了强大的自然语言处理能力&#xff0c;Apt Full还能够对图像和视频进行一系列复杂的AI增强处理&#xff0c;只需简单几步即可实现专业级的效果。 在图像处理方面&#xff0c;Apt Full提供了一套全面的AI工具&#xff0c;包…

Windows环境下Qt Creator调试模式下qDebug输出中文乱码问题

尝试修改系统的区域设置的方法&#xff1a; 可以修复问题。但会出现其它问题&#xff1a; 比如某些软件打不开&#xff0c;或者一些软件界面的中文显示乱码&#xff01; 暂时没有找到其它更好的办法。

《YOLO目标检测》—— YOLO的简单介绍及Map评估指标

文章目录 一、简单概述二、YOLO中的Map指标1.定义与计算2.应用与意义3.注意事项 一、简单概述 YOLO&#xff08;You Only Look Once&#xff09;是一种目标检测算法&#xff0c;由Redmon等人在2016年提出。它的主要特点是速度快且准确性高&#xff0c;非常适合用于实时目标检测…

C# WebApi 接口测试工具:WebApiTestClient应用技术详解

目录 一、引言 二、WebApiTestClient介绍 1、特性 2、应用场景 三、WebApiTestClient具体使用 1、WebApi项目引入组件 2、如何使用组件 1、修改Api.cshtml文件 2、配置读取注释的xml路径 3、测试接口 四、总结 一、引言 由于最近项目需要开发WebApi接口&…

热更新解决方案2 —— Lua语法相关知识点

概述 开发环境搭建 Lua语法 1.第一个Lua程序 2.变量 print("******变量*******"); --lua当中的简单变量类型 -- nil number string boolean -- lua 中所有的变量声明 都不需要声明变量类型 它会自动的判断类型 -- 类似C# 中的var --lua中的一个变量 可以随便赋值 ——…

Java开发中知识点整理

正则表达式 测试网址 Git 分支和主分支有冲突 先checkout origin/分支把origin/master pull进本地分支 修改冲突MergeCommit and Push

旧电脑安装Win11提示“这台电脑当前不满足windows11系统要求”,安装中断。怎么办?

前言 最近有很多小伙伴也获取了LTSC版本的Win11镜像&#xff0c;很大一部分小伙伴安装这个系统也是比较顺利的。 有顺利安装完成的&#xff0c;肯定也有安装不顺利的。这都是很正常的事情&#xff0c;毕竟这个镜像对电脑硬件要求还是挺高的。 有一部分小伙伴在安装Windows11 …

用Python删除PDF文档页面的页边距

在处理PDF文档时&#xff0c;有时候我们会遇到PDF文件带有较大的页边距的情况。这样过大的页边距不仅浪费了页面空间&#xff0c;而且在打印或电子阅读时也可能影响用户体验。通过删除这些不必要的页边距&#xff0c;我们可以更有效地利用页面区域&#xff0c;使得内容更加紧凑…

实现vlan间的通信

方法一&#xff1a;单臂路由 概述 单臂路由是一种网络配置&#xff0c;它允许在路由器的一个物理接口上通过配置多个子接口来处理不同VLAN的流量&#xff0c;从而实现VLAN间的通信。 原理 路由器重新封装MAC地址&#xff0c;转换Vlan标签 基础模型 1、配置交换机的链…

STM32F1+HAL库+FreeTOTS学习18——任务通知

STM32F1HAL库FreeTOTS学习18——任务通知 1. 任务通知1.1 任务通知的引入1.2 任务通知简介1.3 任务通知的优缺点 2. 任务相关API函数2.1 发送任务通知2.1.1 xTaskGenericNotify()2.1.2 xTaskNotifyGive()和xTaskNotifyGiveIndexed()2.1.2 xTaskNotify()和xTaskNotifyIndexed()2…

苹果仍在研发更大尺寸的 iMac | Swift 周报 issue 60

文章目录 前言新闻和社区消息称苹果仍在研发更大尺寸的 iMac 屏幕超过 30 英寸最新&#xff01;苹果大动作Apple Entrepreneur Camp 现已开放申请 提案通过的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主整理周报的第六十期&#xff0c;每个模块已初…

我谈傅里叶变换幅值谱的显示

在图像处理和分析中通常需要可视化图像傅里叶变换的幅值谱。通过幅值谱&#xff0c;可以直观地观察频率成分的分布&#xff0c;帮助理解图像的结构和特征。 很多刊物中直接显示傅里叶变换的幅值谱。 FFT fftshift(fft2(double(Img))); FFT_mag mat2gray(log(1abs(FFT)));由…

跨时钟域处理(单bit)_2024年10月21日

慢时钟域同步到快时钟域&#xff1a;打两拍 在快时钟域clk下对慢时钟域信号进行打两拍&#xff08;亚稳态概率很低&#xff09; 脉冲宽度改变&#xff0c;但不影响同步结果 快时钟域同步到慢时钟域&#xff08;两种方法&#xff09; ① 脉冲展宽同步 在快时钟域clk下对快时…

基于卷积神经网络的蔬菜识别系统,resnet50,mobilenet模型【pytorch框架+python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于卷积神经网络的蔬菜识别系统&#xff0c;resnet50&#xff0c;mobilenet【pytorch框架&#xff0c;python&#xff0c;tkinter】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷积神…

单神经元建模:基于电导的模型[神经元结构、静息电位和等效电路]

文章目录 神经元结构、静息电位和等效电路神经元结构静息电位能斯特方程1. **描述浓度比的非线性关系**&#xff1a;2. **化学势与电势的关系**&#xff1a;3. **对称性**&#xff1a;4. **热力学与平衡**&#xff1a;总结&#xff1a; GHK方程Nernst方程和GHK方程的对比 等效电…

《仓库猎手模拟》风灵月影游戏辅助使用教程

《仓库猎手模拟》是一款休闲独立的模拟经营佳作&#xff0c;让玩家沉浸于经济管理的乐趣中&#xff0c;亲手利用工具探索仓库的每个角落&#xff0c;发掘并鉴定珍稀物品。借助修改器&#xff0c;玩家能更轻松地享受游戏过程&#xff0c;体验寻宝与经营的双重乐趣。 修改器安装&…

【C语言】文件操作(2)(文件缓冲区和随机读取函数)

文章目录 一、文件的随机读取函数1.fseek函数2.ftell函数3.rewind函数 二、文件读取结束的判断1.被错误使用的feof2.判断文件读取结束的方法3.判断文件结束的原因feofferror判断文件读取结束原因示例 三、文件缓冲区 一、文件的随机读取函数 在上一篇的文章中&#xff0c;我们讲…