英雄联盟设计师:游戏动画压缩如何保质量

转自:http://www.gamelook.com.cn/2015/08/226312

Gamelook报道/不论是哪个平台的游戏,开发商最为头疼的问题之一就是包体大小,因为它不仅影响玩家硬件的存储空间,还直接决定玩家从发现到体验游戏的时间差。而游戏动画则是占用资源最大的部分,所以如何压缩动画是所有开发者都需要面对的问题。

最近,《英雄联盟》开发商Riot Games发布了相关的技术贴,设计师Jaewon Jung通过博客的形式讨论了如何在不降低动画质量的情况下进行动画压缩的话题,并且在文章中讲述了Riot公司所使用的一些技巧,希望给遇到这类问题的开发者提供一些帮助。

以下是Gamelook编译的完整博文(小编非技术出身,翻译失误之处恳请大牛指正):

《英雄联盟》的英雄数量已经超过了125个(目前正式推出126个),每个都有一套独特的动画设定,要问我最喜欢的是哪个?毫无疑问是亡灵勇士-塞恩的跳舞动画(下图),而这只是他38个动画中的一个。这些动作的加入才让英雄们变得栩栩如生,从角色的移动到强大技能的释放以及悲惨的死亡动画,都可以让英雄变得更有个性。随着我们不断的增加和重做英雄,动画数据的总量已经形成了很大的资源负担,比如运行内存、补丁大小以及存储空间等等。

除了动画数据之外,最近发布的《召唤师峡谷》视觉更新则增加了内存需求,这次的更新使用了Unique-texel的做法,比此前的Tiling方式更能带来优秀的视觉效果,然而它也不可避免的增加了地图对于内存的占用。

我们认为支持多种不同配置的硬件是非常重要的,这样所有人才能同时享受到游戏的乐趣。随着新的动画和地图更新的内存需求不断增加,我们开始寻找降低内存使用的方法。我们发现的其中一个方法就是压缩游戏内骨骼动画数据来减少内存占用,同时维持最低的质量损失,还要保证不对性能产生任何影响。

我们可能用了很多方式进行动画数据压缩,但在这个博客中,我会介绍我们主要使用的2个:量化(Quantization)和曲线拟合(Curve Fitting)。压缩的做法总会带来质量降低和释放内存空间两者的矛盾,所以,我会讲述我们发现的可以让人接受的方案,还会解释我们是如何管理数据并且做到最大化性能的。我会使用一些像四元数(quaternions)以及样条曲线(Spline Curves)这样的概念,所以,如果你们对这些不熟悉的话,可以参考博客结尾中非常有用的参考资料。

我需要说明的是,这篇博客里提到的所有东西都不是什么新技术,而是从事游戏开发的伙伴们分享的一些非常实用的知识,我还想补充的是,游戏引擎开发商BitSquid(已被Autodesk收购)的博客是非常有帮助而且值得一看的。

量化(Quantization)

量化指的是把一系列连续的可能性限制在相对小而分离的设定的处理过程。骨骼动画(Skeletal animations)有位置、旋转和量化数据,我们很容易量化3D矢量(用于表示位置和量),只要通过获得他们的最大/最小值范围并且在这个范围内统一分割即可。但骨骼动画数据的复杂性通常来自于旋转。

我们这里使用四元法指代3D空间里的旋转,我们量化旋转数据的方式使用了四元数的特殊数学性质,我们使用了单位四元数(unit quanternions),所有组件的范围都是[-1,1],并且找出最大绝对值的元素定义x,y,z,或者w。然后放弃(绝对值最大的)并保留其余三个,因为我们可以很容易计算出被省略的组件,只要这个单位四元数满足x² + y² + z² + w² = 1方程式即可。通过省略最大的组件,我们可以把其余三个组件的范围限制在[-1/sqrt(2), 1/sqrt(2)]之间,要知道,在单位四元数当中,这个范围之外的一个组件必须具备最大的绝对值,所以这也是我们将会忽略掉的组件。我们通过量化到比[-1,1]更小的范围来最大化精确度,如果不排除最大组件的话,我们原本可能会(误)用这个范围。这样的做法还让我们避免了对一个较小价值的组件进行重做,从而避免了更多的错误。

通过这种方式,我们为每三个保留下来的组件都分配15 bits,被省略的组件分配2 bits,因此每个四元数都总共占据48 bits(其中1 bit是不使用的),细节如上图。作为对比,未经处理的四元数需要为每个组件使用32 bits的浮点数(floating-point number),所以最终使用128 bits,通过我们的处理,原本的128 bits降低到了48 bits,也就是说,我们的压缩率达到了0.375。

这种48-bit的四元数量化可以保证数值精度(numerical precision)达到0.000043。所以你可以想象,这个精度几乎可以适用于所有的案例。实际上,当我们把这种量化方式应用到所有动画的时候,没有任何一个动画出现质量下降。另外,我们可以把这些转化应用到加载时间而不是持续的大批量转化过程,所以也不需要以后再为此打补丁,所以这种量化方式是非常简单可行的。

样条曲线适配(Curve Fitting)

为了进一步压缩,我们使用了样条曲线适配的方式来改变四元数的值,这是一个创造曲线的过程,或者说是数学功能,能够最佳适应一系列的数据点。我们特别使用了Catmull-Rom样条曲线,可以用一个三阶多项式(3rd-order polynomial)表示。你需要四个控制点来确定Catmull-Rom样条曲线,下面借用维基百科提供的数据图可以更好的说明:

为了做到准确的适配,我们使用了迭代(iterative)方式来减少失误,这个过程一开始只有2个关键帧(keyframes),并且包含了动画的开始和结束。我们通过迭代的方式增加更多的关键帧来减少曲线的整体失误,把它降低到一个可以接受的水平。在每一次的迭代中,我们都找出关键帧之间的最大错误,并且插入一个中间点关键帧作为替代,这个找错并且替代关键帧的过程是不断重复的,直到每一个部分的错误都降低到可以接受的程度。

你可以看上图的红色适配曲线和绿色初始曲线在迭代过程中的对比。黄点代表每次迭代过程中增加的(新的)关键帧。通过这种做法,我们经过88次的迭代之后,把最初的661帧降低到了90帧。

在做曲线插值(curve interpolation)之前,千万不要忘记调整四个四元数控制点。一个四元数Q和它的相反数-Q代表的是同样的旋转,但如果不调整的话,最终旋转可能无法实现最短途径的插值。比如,一艘向北行驶的船准备转向东方,如果没有合适的四元数调整,那么它可能直接逆转270度才能做到,而不是顺时针转90度。

曲线适配可以对量化结果进行进一步的压缩,而且压缩率在25%-75%之间。我们发现为定位、旋转和量化数据设置合适的误差值对于不损失视觉体验情况下获得最大化压缩率是至关重要的。

为了更好的压缩,我们还考虑了样条曲线节点参数,比如在动画数据的案例中,基于关键帧时序(keyframe timings)的参数是最自然的。不过,你仍然可以看一下的数据(也是来自维基百科),四个同样控制点的曲线形状取决于使用哪种节点参数:比如uniform、chordal或者我们使用的centripetal。

这些技术会对于某些动画造成明显的质量损失,但通过使用严密的误差值,我们可以把损失降低到最小,但这样做的压缩率也会降低。因此,我们的动画师对每个案例都进行审查,以求做到质量和压缩率方面的平衡。而且,和量化过程不同的是,由于曲线适配过程需要大量计算,所以不可能转换到加载时间上,因此我们必须对所有现存的动画数据进行预处理。

降低损失

压缩过程导致最明显的现象就是foot sliding,这会导致动画中出现角色的脚或者任何末端执行器(end-effector)一直不动。

你可以从上面图中很容易的看到本来应该摆动脚却一直不动。这是因为skeletal rigging中的骨骼是分等级的,错误的累积会造成很大的影响。我们解决这种问题的方法是使用了一种我们称之为‘可适应错误率(adaptive error margins)’的技术,它意味着如果一个节点有较长的派生数,你需要把误差值降到最低,而不是为所有的节点使用同样的误差值。比如,一个末端执行器使用特定的比例,但其母单位则使用半数,那么更上一级的则使用三分之一数,诸如此类。这种自上而下的误差率降低可以最大化限制派生值发生错误的概率。

《Game Programming Gems 7》一书介绍了另一种被称为‘在骨骼动画中减少累积误差’的方法,我们内部把这种方法叫做“连接销(joint pinning)”。对一个连接销(比如足部),我们不使用源数据流(source data stream),而是计算新的本地转换数据,这样可以抵消早代数据压缩中所产生的误差,这本书中还有更多在这个话题是非常不错的材料,值得同行们一读。

允许缓存的数据结构(Cache-friendly Data Organization)

最后,我们来讨论有效实现了以上概念的方法,在研发这些技术的同时,我们同时非常清醒的知道玩家们的硬件存在很大差异,而且对于降低性能方面的做法十分谨慎,我的团队专注的其中一件事就是实现允许缓存的数据结构。

我们采取的非常关键的一步就是把所有的关键帧(每一个连接销的位置、旋转和量化帧)放到一个相连的存储块里。通常见到的做法都是为每个连接销创造不同的存储块,但这样看似自然的结构在特定时间段评估一个完整骨骼姿势的时候会导致严重的缓存丢失。我们把数据放到一个存储块是因为所有渠道类型的有效负荷都是48 bit,如我们此前所见,我们把四元数量化到了48 bits,还把3D矢量的每一个x,y以及z组件都分配同样的16 bits,你可以从下面的压缩帧数代码看到实际的代码连接销结构:

这里,我们还把key time量化到了16 bits,连接索引(jointIndex)基于各自帧数数据而不同。V箭头包含了量化的有效负荷,确定有效负荷是属于旋转、位置还是量化是非常重要的,我们使用这两种最重要的连接索引来完成。这种方法可以把连接索引控制到14 bits,我们一共有16384个连接销,这对于《英雄联盟》的英雄来说是足够用的了,因为通常一个英雄只使用不到100个。

所以对着这些连接销做恰当的关键帧顺序是非常重要的,不管是那种连接销或者类型都很重要,我们本可以用key time进行琐碎的排序,但问题很快就出现了。你可以想象一下动画运行时会发生什么,从下面的图片就可以看出问题:

你可以看到被key time分开的四个关键帧以及一个标明了目前重放时间的计时针,你需要Tn、Tn+1、Tn+2以及Tn+3的信息,因为评估一个样条曲线需要四个控制点。如果计时针的目前位置是已经过了Tn和Tn+1,那么它应该是已经熟悉了的,可Tn+2和Tn+3怎么办?你可能会觉得自己可以快速的进行线性扫描,因为这两个帧是可以快速找到的。

然而这种方法并不是最优的,假如说这些T是帧数位置,如果动画包含很多旋转变化的话,那么很多的旋转帧可能会存在于两个临近位置的帧数之间(如下图)。这样的话,所有的帧都放在了一起,通过线性扫描的方式寻找Tn+2和Tn+3就是非常低效率的。

要让每一次线性扫描都实现回放的诀窍在于,你要按照时间需要的顺序组织帧数,而不是根据key time。一旦计时针通过了Tn的key time之后我们就需要Tn+2,因此我们应该把Tn+2根据Tn的关键数据进行安排。这样任何时候都可以获得需要的信息,所以缓存丢失就可以被最小化。下面的图表可以展示这个工作原理:

希望我们使用的压缩方法能够帮助到所有遇到类似问题的开发者们。

结论

平均来说,在这篇文章中我所讨论的量化技术基本上让《英雄联盟》的英雄内存需求减半,我们还在努力把曲线适配技术做到更好,因为它需要预处理所有的数据,但从我们初期的结果来看,很可能实现另外50%的压缩率,也就是说,我们很肯能做到把最初的内存需求降低到25%,我对此感到兴奋,因为这样就有机会提高各种玩家设备的游戏体验。

我们未来还可能探索更多的方向,比如32-bit四元数量化、对不同的曲线适配做不同的节点参数、用最小二乘法适配替换迭代的做法、对增加新的key进行更多优化等等。动画压缩是一个广泛而且非常深度的话题,我们本文讨论的还只是冰山一角。不过,我仍旧希望这些是对你们做动画压缩有帮助的,下面是一些参考文献的链接,祝你们好运。

参考文献

动画压缩

The BitSquid low level animation system

Bitsquid Dev Blog – Low Level Animation — Part 2

Digital Rune Blog – Character Animation Compression

Unreal Engine 3 Animation Compression

Reducing Cumulative Errors in Skeletal Animation, Bill Budge (Game Programming Gems 7)

曲线适配

Curve fitting, Wikipedia

Catmull-Rom spline

Least Squares Fitting

通用压缩方法

Working With Compression, by Fabian Giesen

为准备本文材料所用到的工具

http://jsfiddle.net/6u7hm0m9/16/

https://screentogif.codeplex.com/

时间: 2024-11-08 14:51:51

英雄联盟设计师:游戏动画压缩如何保质量的相关文章

英雄联盟模型查看器

本人非常喜欢英雄联盟这个游戏,希望英雄联盟也能出个类似war3的世界编辑器那样的工具,可以利用英雄联盟的场景和模型制作自定义游戏.可是,官方是不太可能出这种工具的.于是,萌生了个制作英雄联盟世界编辑器的想法. 想制作类似世界编辑器的工具,第一步是要提取英雄联盟中英雄的模型和动画. 在网上搜索有关英雄联盟的资料,偶然间发现了lolking这个网站,上面提供了所有英雄(包含全皮肤)和中立生物的模型和动画,我感觉我都第一步就要完成了. 费了一周的时间,制作了英雄联盟模型查看器. 下面给出英雄联盟模型查

unity游戏开发之[英雄联盟]的美女设计师:Katie De Sousa

  狗刨学习网报道/此前SuperData的数据透露,<英雄联盟>2014年的收入将突破11亿美元,而作为近几年红遍全球的MOBA游戏,<英雄联盟>不仅推动了电子竞技的快速发展,还带动了多个领域的增长,比如游戏视频主播和衍生视频.游戏等等.不过,今天小编想要介绍的是该游戏的美女设计师,Riot Games公司的高级创意美术师Katie De Sousa. Katie De Sousa生于加拿大,最初居住在加拿大东部地区,只在艺术中心学习过2年的游戏动画,19岁时(2006年)就已经

腾讯勇夺全球游戏霸主地位,“英雄联盟”成基石

作者:楠沨 [IT战略家] <英雄联盟>世界总决赛于十月落下帷幕,成千上万粉丝观看了S6系列职业联赛,但鲜少有人知道的是,这是一个中国公司全球统治战略的一部分.(注:英雄联盟为当下最为火热的电子竞技类游戏.) 并购之路 & 合作伙伴自主性战略 腾讯作为亚洲最具价值的科技公司,目前市值高达2490亿美元,已经成为全球最大的游戏发行商,收入超过美国知名游戏公司艺电和暴雪.腾讯主导着中国的游戏市场,并不断通过与外国公司建立战略联盟走上全球扩张之路. 腾讯也在尝试出口自己的游戏,但它在全球取得

怕被虐所以玩英雄联盟?玩家们对比游戏心声

很好用的第三方支付,不说不实际的话,有全国支付牌照,系统稳定,关键一点是不会乱扣钱,联系QQ:2990968116 不少玩家在提到<星际争霸2>,或者是其它RTS的时候往往摇摇头说:太难上手啦,不喜欢被虐.然后转身去玩那些被认为是相对“容易”的游戏,比如<英雄联盟>.说到游戏难度,还有人举例子说,游戏里妹子的多少与游戏的难度成反比,因此现在有许多女玩家选择了<英雄联盟>,然后众单身男玩家也蜂拥而上——啊,玩游戏到底是为什么啊? 据说1V1实在太难,心理压力太大受不了?

用Python抓取并分析了1982场英雄联盟数据,教你开局前预测游戏对局胜负!

英雄联盟想必大多数读者不会陌生,这是一款来自拳头,由腾讯代理的大型网络游戏,现在一进网吧,你就能发现一大片玩英雄联盟的人.在2017年中国战队无缘鸟巢的世界总决赛后,一大片人选择了弃游,只是终究没躲过"真香定理",在2018年的中旬,又有大批战友又回到熟悉的召唤师峡谷战场,时至今日,英雄联盟已经不仅仅是一款游戏,一个电竞项目了,它已经成为了我们生活的快乐源泉了. 问君能有几多愁,辅助闪现抢人头:问君能有几多愁,卡牌千里送人头.问君能有几多愁,皇子开大关队友:清明时节雨纷纷,各种队友各种

【个人计划】告别英雄联盟,开始学习Python

不知不觉中接触英雄联盟已经快两年了,记得是大四那年找完工作,一下比较清闲,宿舍刚好有lol的氛围,于是乎,四个新手在何大神的带领下,走上了lol的道路.不得不说,从那以后,花费在lol上的时间太多啦,据我估计,个人玩了将近2000了吧,别看局数这么多,其实就是个渣渣,技术太菜了,这也就是我告别英雄联盟的原因啦,根本没有玩这个游戏的天赋,技术上没有一点点提高,一直就是在浪费时间罢了. 就我个人而言,1.在补兵方面,时好时坏,而且有时候性子急,不太注重前期的补兵发育,往往导致输的结局:2.游戏中大部

【bzoj5018】[Snoi2017]英雄联盟 背包dp

题目描述 正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」.现在,小皮球终于受不了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!小皮球只会玩N个英雄,因此,他也只准备给这N个英雄买皮肤,并且决定,以后只玩有皮肤的英雄.这N个英雄中,第i个英雄有Ki款皮肤,价格是每款CiQ币(同一个英雄的皮肤价格相同).为了让自己看起来高大上一些,小皮球决定给同学们展示一下自己的皮肤,展示的思路是这样的:对于有皮肤的每一个英雄,随便选一个皮肤给同学看.比如,小皮球共有5个英雄,

寒假代练——英雄联盟

在放假之后,通过朋友给我介绍了一家游戏代练的工作室,由于第一次做代练所以就抱着试试的心态同意了,时间不长也不短刚刚好7天,想着既能玩游戏,还能拿到一些“工资”,何乐而不为呢.代练的游戏是当前正火的竞技类网络游戏:英雄联盟,这款游戏由于上手度适中,游戏内英雄的多样性以及适合多人一起游戏而深受各个年龄段玩家的喜爱. 英雄联盟在每一年的1月底或2月初会开启新的赛季,新赛季一直能持续到下一年的1月份,每个赛季当玩家的游戏内角色等级即“召唤师”等级到达30级后,并且拥有16个不同的英雄即可通过排位赛模式开

【BZOJ5018】[Snoi2017]英雄联盟 背包

[BZOJ5018][Snoi2017]英雄联盟 Description 正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」.现在,小皮球终于受不了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!小皮球只会玩N个英雄,因此,他也只准备给这N个英雄买皮肤,并且决定,以后只玩有皮肤的英雄.这N个英雄中,第i个英雄有Ki款皮肤,价格是每款CiQ币(同一个英雄的皮肤价格相同).为了让自己看起来高大上一些,小皮球决定给同学们展示一下自己的皮肤,展示的思路是这样的:对于有皮肤