3月27日, Epic Games在深圳举行虚幻引擎Unreal Circle线下技术沙龙活动。会上,游戏科学的客户端技术负责人招文勇带来了关于《黑神话:悟空》在动作技术实现方面的主题演讲。
《黑神话:悟空》的角色数量非常庞大,而且对动作游戏而言,角色也需要非常细致的动作品质,这导致团队在品质和数量这两个维度上都面临非常多的技术挑战。本次演讲招文勇分享了他们在《黑神话:悟空》中所运用到的Motion Matching等动作技术,以及他们如何充分利用技术解决动作难题。
以下为演讲原文(有节选):
大家好,我是《黑神话:悟空》的招文勇,来自游戏科学。2010年我参加了《斗战神》项目,后来就跟尤卡、杨奇出来创立了游戏科学,然后就一直做到现在。
很多人都知道,其实我们的动作技术是用了Motion Matching,那为什么我们要用这个东西呢,今天我们也专门来讲这个事情。
产能和质量,让我们选择了Motion Matching
首先我们会面临一些挑战。这个项目里面我们会有很多的怪物,而这么多的怪物,我们又要保证很高的动作产能,这样才能满足我们这么多怪物的动作量,而我们又是一个3D动作游戏,3D动作游戏意味着一个角色它需要的动作量是非常多的,比方说做locomotion,locomotion要做得好的话,是要处理各种加减速、折返跑,原地转身等等这些动作。
动作的制作量大,就意味着我们要搞出一个足够简单的管线,可以让外包来帮我们做这个事情。然后我们还有很丰富的角色种类,比方说最简单的人形,人形就有双正足,双反足(像野兽一样,足膝盖是往后的,而不是往前的)。还有什么四足兽、昆虫、蛇形等等。这些复杂又大量的动作需求,我们怎么应对呢?
我们刚刚开始做游戏的时候,刚好Paragon出来了。然后我们参考了一下,做了一波反推,发现这个系统非常庞大,角色的整个运动是非常流畅的,看起来也非常自然,但是为什么我们最后没有用?
第一个原因是它对动画分拆的要求非常高,动画师要理解分拆是很困难的。举个例子,以前我们让动画师做一个让角色原地转身的动作。就这么一个简单的东西,但是动画师会有自己的想法,他可能会在里面加上一些他想表达的东西,比方说他很想让这个角色看起来很惊恐,很快速的这种反应。
但最后这个东西进到了游戏之后,我只要稍微走两步,这个角色就开始原地跳舞。其实并不是动画师的问题,动画师有这样的想法是合理的。但是因为他并不理解这个东西在程序层面是怎么拼装的,而程序又没有办法用一个很简单的思路把动画师的想法完美的套入到我们的框架里面,所以就会产生这种制作上的矛盾。
第二个,动画要标注的数据非常多,具体我就不细讲。然后还有它是基于动画图的,就是Anim Graph制作的各种动画状态机,还有各种各样的动画蓝图的逻辑,是非常复杂的系统,我们花了大概一个月的时间反推,然后制作,发现维护起来非常地不容易。
所以基于这么多的考虑,最后我们刚好遇到了一个新的东西:Motion Matching。其实这个东西是育碧的动画方案,最早在《荣耀战魂》这款游戏里面用到了,它的原理是通过穷举你在游戏里会用到的所有动作,比方说跑步、转向、启停,穷举所有可能用到的动画帧。
程序可以搜索每一帧,看哪一帧最合适。然后它会根据当前和未来状态计算一个所谓的叫cost的东西,选择cost最小的一帧。比方说我往前走,并且想着要向左转,而cost最小的一帧,就是它会尽量的去用向左走的动画来作为你的下一帧。
那么我们选择Motion Matching的原因就是,第一,它的工作流非常简洁,不需要让一个动画师去理解这个动作是怎么拆的;
第二,因为它整个搜索过程都是在程序这边就做完了,你下一步要什么动画,程序就会帮你搜出来。然后这也让我们可以把各种人行运动的动画外包出去,极大地提高我们的产能;
第三,在动画的质量上面,它的演示是比较精良的,而且还支持各种locomotion的需求,包括各种转向折返,还有加减速等等。然后像刚才动画师想做一些演绎,结果出现问题的这种情况,Motion Matching也能很好地应对上,因为它会根据各种条件搜出最合适的动作,然后动作演员会在录制的过程中更加容易地做出更多的细节演绎。而且这个是经过产品验证的,其可控性我们在用过之后发现也还不错,整个事情都是可以执行下来的。
如何使用Motion Matching开发动作?
我们目前是把Motion Matching用在人形动画上。很多人讲我们是魂游戏,虽然我个人不是很认同,但是像这种类型的动作游戏,它会有两种移动方式,第一种就是自由移动,自由移动就是我往哪边跑,我的脸就要朝哪边;第二种是锁定,就是我不管往哪个方向走,我的脸都是朝着同一个方向。
然后不同的运动速度、不同的风格和姿势都是需要单独录制的,比方说同一个角色,他跑和走,拿着刀,或者过会儿再举出一个盾,这些都是需要分开录制的。这些路线的核心逻辑是想尽办法穷举出所有可能用到的转向,或者是运动速度。这里用我们的路线图来讲一下。
先介绍下如何看路线图。这个视频的右边是正面,你可以看到狼的头部是向着右边的,里面有几个标识,大家可以看到下面对这些标识都有一个说明:灰色箭头是它脸部的朝向;蓝色的双向箭头就代表这条路线需要来回走;白色方块就代表要停顿一下,结合起来就像米字步,米字步就是8个方向都走一遍,但是只有走到中间的时候是要停一下。
现在我们进入正题。
首先是自由移动。第一个,原地转身,就是录各种来来回回的旋转;第二个是蛇形,就是沿着S路线跑,然后脸跟着你跑的方向;第三个,自由转圈,跑两个不同方向的螺旋;还有就是一个加减速。育碧认为是要录两个方向的,但是我们实际操作的时候一般是录一段,感觉好像问题也不大。这种运动的目的是提供一个足够长的加速,然后匀速再减速的这么一个过程。
然后再看锁定。像转圈,就是我要绕着一个中心点走一个螺旋路线,而螺旋的路线是要正反走两次的,但走的过程中全程要把脸朝着一个方向,和刚才米字步类似,蛇形也是。
第四个是方块+钻石。这里有具体的视频,可以对比一下,在这个过程里面脸都是朝着一个方向的,然后是沿着这个路线走两遍。
录制的时候,演员需要注意的除了记住路线以外,主要的就是包括要不要停顿、脸部的朝向、要不要来回移动。
移动速度也是非常重要的,因为它的一个特点就是你的角色摆进游戏里面的移动速度是由动画决定的,而不是由你希望的速度决定的。所以为了一开始就让动画最后出来的结果符合游戏的预期,那么这个移动速度是要估算一下的,就是说你不能差太远。
还有一个制作动画的经验就是,录这种locomotion的动画时,武器一定要持稳。它的解决方式是你可以动手肘,但是不要轻易去动手腕。这个方式可以保证你的动画有一定的自然晃动,但是又不会出现大幅度的旋转。
另外我们实际在做的时候还要注意的一些点。一个就是刚才说的速度;第二个是演员的运动能力是有一定的要求的,最麻烦的是9段折返跑;演员本身的表演感也会极大地影响最终成品的品质;还有就是疲劳度的问题。这些路线数量很多,如果频繁NG的话,其实整个过程是非常需要他有充足的体力的;录制场地也需要比较大。
讲完大家都能听懂的,现在开始讲一些枯燥的。Motion Matching这个插件目前是作为一个AnimNode来实现的。AnimNode的实现用这种方式来做的话,可以跟AnimGraph的绝大部分功能来结合,比如说需要后期加AK,或要把它放在动画状态机里面,这些是完全都可以做得到的。
而且它天然地支持多线程。其实Motion Matching的运算压力是非常大的,所以它如果不支持多线程的话,还是蛮恐怖的。
目前我们会把我们录好的一组动画,所谓一组是一个角色所需要的动画,这个动画我们是需要去算它的cost。
计算cost的话,其中一个很重要的就是要算它每一帧骨骼。Motion Matching在我们选用什么样的骨骼之后,它会有一个预计算的步骤,会把每一帧各种各样的信息算出来并保存,方便我们后面在实际跑的过程中去算cost。
cost的计算是需要自己定义的,其公式非常重要。如果设计失误,会极大地影响Motion Matching的品质,因为你会经常匹配到错误的下一帧,可能会出现各种抖动,或者你想让它往左走,结果它走不出来,只能往前走。
而plugin提供的默认公式基本上没有什么实用性,就只能跑它提供的Demo,所以我们后面做了很多的优化,包括减少骨骼match,以此驱动run cycle。
然后设计公式时要注意二义性,二义性的意思就是说我去搜下一帧,发现另一帧好像也可以,那一帧好像也行,因为他们算出来的cost可能差不多,很容易会导致一个问题,就是我好好地跑着,但会突然跳到另外一个动画去,然后就会出现抖动。
导致二义性的原因是因为默认公式只算了速度和Bone Match,维度太少了,很容易导致有两帧可能会算出差不多的结果,但实际的匹配度中明显会有一个高于另外一个,所以我们参考了育碧建议的一些考虑因素,增加了一些额外的维度,包括未来几帧的位置、朝向、加速度和减速度。
像加减速度会很影响你的匹配。比方说我只考虑速度的话,或许能匹配上一个匀速运动的动作,也可能会匹配上一个正在加速到最后几帧的动作,但这两个动作可能是不一样的,而加上了这些维度之后,能在两个都能用的动画中排除掉一个,选择最适合的动画,这就解决了二义性的问题。
还有设计公式时要考虑各种当前因素,比方说速度匹配、当前脚步的位置等等,接着还有未来因素。这里需要提到一个概念叫Responsive,它是公式里面的最后一项,未来相关的因素都要乘以Responsive,Responsive越大的时候,未来因素的权重就越大。这个参数我们是可以控制的,参数越大意味着越有希望保证操作的灵敏度。
Motion Matching仍有不足,5大问题可以解决
我们一直在说Motion Matching是动画驱动移动,它自身也是有一些问题的,比方说他的动作很写实,动作写实这个事情本身就是跟操作的灵敏度有矛盾。你可以想象一下,现实中你在高速地往前跑,突然有人要让你往后,你肯定是来不及的,要一个急刹车,然后再回去才行。如果游戏里面也是这样的话,它确实会影响操作的灵敏度。所以用了Motion Matching之后,本身就要权衡这个东西。所以需要在录制的时候也要考虑好加减速的敏捷程度,要求演员要尽可能做到敏捷,这个对演员的运动能力也是有一定的要求。
第二个是它的各种性能问题,比方说它的内存占用是非常高的,动画数据量非常大,应对策略就是可以删除没有实际用到的帧。其实在录制的时候,做一些统计工具,会发现中间有很多帧,到最后成品时是没有用到的,这些可以抽掉,抽掉之后并不会影响动画的质量,而且又可以节省内存。
第三个是它的运算量非常大的,因为前面说过他理论上就是去算每一帧到底哪个更合适。所以这个问题首先可以用多线程来解决,第二个是由于它的搜索其实是一个多维搜索,所以可以用KD去变成一个树状的搜索,这样可以极大地减少它的搜索量。优化效果非常显著,可以节省80%左右的CPU时间。
还有我们的cost计算是需要自己设计的,我们设计的维度越多,就会导致运算量越大。所以我们可以通过砍掉不必要的维度来减少运算量。其中Bone Match数量最好降到最少,我们只用选择一些关键的骨骼,比方说脚、头、手这些东西就行,当然这个也是需要根据项目来确定的,因为他并不是一个很固定的方式。
另外我们在录制动画的时候,一般会录制2~3个循环,但就算是这样,其实可能偶尔还是会有重复感的。比方说你们第一次看这个视频的时候,会注意到火头狼会转刀,而这个到实际上在录Motion Matching的时候是没有录在里面的,这个是通过叠加动画的方式叠加上去的。所以我们实际制作的时候先是自动摸索Motion Matching,Motion Matching的时候只要简单地走就好了,然后再制作一个转刀的动画,把转刀的动画用addictive的方式叠加上去,就可以把这两个动画合起来。而且我还可以随机决定他什么时候转刀,来避免这种重复的感觉。
最后对于一个庞大的体系,如果说每一个骨骼都要做一套的话,这个是很恐怖的。我们动画蓝图目前是可以跨骨骼复用的,这也给我们一个好处就是我们可以做非常复杂的逻辑。右边这个图是我们实际的动画蓝图,其实它还有很多别的内容,但是一屏截不下来,非常复杂。
在实操中,我们可以把动画蓝图指定到一个本来不属于它的骨骼上面,然后通过它再来组织我们的动画数据。这样对美术或者策划来说比较易于配置,而且也比较容易实现加载,因为它还可以直接作为一个streaming的载体来完成动画的加载。
好的,谢谢大家!
来源:游戏陀螺
原文:https://mp.weixin.qq.com/s/lyGQsjICOQemy5jIBfTJsg