Epic Games 技术总监:如何让玩家爽!
整理/VR陀螺 杏仁
12月15日, 2016 UNREAL VR DEV DAY 在北京召开,Epic Games VR&AR项目部技术总监Nick Whiting在会上发表了主题演讲。他分享了Epic Games去年在OC2上发布的《Bullet Train》以及现在制作的Oculus Touch独占游戏《Robo Recall》开发过程中的一些改进,包括犯过的错误和积累的经验。
Ps.《Robo Recall》被誉为是《Bullet Train》的精神续作。
以下是Nick Whiting演讲内容整理:
大家好,我是Epic Games VR&AR项目部技术总监Nick Whiting,也是《Robo Recall》开发团队负责人。大家可以看到Epic一直有自己尝试做VR的内容,从Oculus四年前刚开始给出第一个硬件的时候就一直联系我们,我们就开始做VR游戏。我们希望使用我们的工具做引擎,改善工作流程和改善引擎效率,使得帮助开发者更好的使用引擎开发高质量的VR内容。
《Robo Recall》的由来在先讲《Robo Recall》之前,我们先谈谈《Robo Recall》的前身《Bullet Train》是怎么来的。当Oculus硬件有原型的时候,就给出了第一个原型给我们,希望我们做一个比较正规的VR项目,就像《战争机器》,所以这就是《Bullet Train》这个项目当时是怎样开始的。
《Bullet Train》是1年前的,刚开始只有两个人大概用了四周的时间,而整个项目总共也只有十周。当时开始这个项目的目的之一是希望能在Showdown基础上进一步提升画面效果,Showdown是我们在之前的一个VR Demo,运行在GTX 980上的,但在OC2之前,Oculus推荐的硬件是GTX 970。相对来说,Showdown在GTX970上的效果要比GTX980更好。另外一方面,我们希望用真实的项目来了解引擎在驱动VR内容时的效率。
介于《Bullet Train》在OC2和GDC上非常成功,Oculus希望我们把它做成一个完整的游戏,这次我们有一整年的时间完善当时很多没有做好的细节做好。
我们在制作《Robo Recall》主要参考两个方面,第一,怎么样在VR里面做出有意思的内容?第二,怎么样在提升画面品质做的技术上的改进?
《Robo Recall》中交互和移动设计从《Bullet Train》上得到的经验:观察玩家,交互让他们更爽
我们首先研究了为什么《Bullet Train》取得成功。当时成千上万用户在玩《Bullet Train》的时候,我们看到了一些关键的地方,比如我们把《Bullet Train》设计成如同黑客帝国里超人的存在。我们只需要看用户玩,观察他的反应,让用户感受到自己在游戏里面屌爆了,或者看哪里他感觉跟预期不太一样,说明是我们做的不够好的地方。
在这个过程中我们也发现用户非常乐意自己去探索和发现,规则是怎么样的,哪些可以交互,这是非常有意思的。就像钓鱼一样,你需要晃动钩,鱼就会咬上来。同样在游戏里,一旦设置了某一样东西在VR里面,用户会想交互它,一定要实现这样的预期效果。比如,火车里设置了拉环,用户会很自然地想用手去碰它,但发现它好像没有交互,他们就会很不爽。基于这一点,我们做了一些交互,用户就会觉得很酷。又比如,我们在手雷上面设计了一个拉环,而拉环完全是物理模拟,用户能看到晃动的时候它有物理的感觉。但是玩家在游戏过程中用另外一只手拉拉环,像真实的那样,发现不能交互。当时只是一个物理表现,实际上是只要把手雷扔出去就会炸掉,所以这是一个很失败的地方。好在我们有足够时间调整这个拉环的功能。刚开始是有问题的,按键是冲突的。我们的解决方案是从底层重新组装输入模块来满足这些逻辑。这其实是很值得的行为,用户非常满意这个效果。
解决《Robo Recall》中瞄不准的两个步骤
《Robo Recall》主要道具是枪,很多人没有用过枪,所以用枪方式基本是采用电影里的方式,但是和现实大有不同。有用枪经验的玩家,通过三点一线瞄准,都能打准。主要原因在于握手柄和实际持枪有差别。
我们思考有一些什么方法解决这个问题,一开尝试了Oculus Toybox里的方法,希望虚拟环境里面手的模型和真实世界的手保持完全一致。但因为模型的关系,和真实世界中手的还是不太一样,所以我们要做细微的调整。
怎么样的对齐方式是最好的?其实我们也还没有定论,最后的结果就是在两者之间,模型和手柄都是差不多可以对上。在做游戏测试的时候,大部分用户有些手偏高或偏低,两者之间恰合适。另外,我们需要做的是进入游戏先让玩家打靶调节准心,比如玩家始终瞄的有一些偏高,我们会帮玩家往下修正一点,在整个游戏中我们都会帮玩家往下修正一点,反之亦然。
枪的三种交互:重量、后坐力、抓取,《Robo Recall》如何思考?
就枪本身来说,有三部分的交互。第一,物理感,即握枪的重量感。第二,开枪的过程中有一些反馈,比如硝烟的味道,力的反馈。第三,电影中各种枪的杂耍动作。
传统中直接把引擎设置成物理对象的好处
直接使用引擎自带的模拟功能,能把枪作为一个Physics,只要玩家握着手枪的时候就设置完。另外,后坐力模拟直接加了一个物理的Impulses,能模拟真实情况下受到冲击的感觉。此外,把它设置成物理对象的好处是碰撞交互之类的,跟其他枪、物体碰撞的声音,以及给用户的力反馈感都是自然就有的。
传统中直接把引擎设置成物理对象的不足
当把它设置成物理对象时,枪可能会卡在某些地方,尤其枪大的时候,卡在桌角之类的就会不停抖动,有时候会突然再弹回来,这样会很不好,破坏了我们使用物理的方式。与其用引擎来做模拟,我们不如自己决定哪些地方有物理模拟,哪些地方不要。
《Robo Recall》中道具枪的交互方式
首先,VR里都想要降低延迟,但是对于枪是有问题的,因为枪是有重量感的,如果过快地挪动是不太可能的,所以反而加一些延迟。我们把前期帧的速度累计起来,让它更有重量感。虽然没办法让实际的物体变重,但是可以让玩家感受到好像它的重量变化了。
其次,后坐力不能用物理来加,我们需要用其他的手段Timelife功能。为什么用它不用线性的?因为手被后坐力往上玩家就会想压下来,所以开始比较快后面比较慢,不是线性的过程。游戏里加上Recall后的效果,全速的时候可以看到每枪开完后坐力往上之后很快就恢复。《Robo Recall》里的枪恢复时间比较慢,很明确地看到当玩家连续开枪的时候它是慢慢往上走的。
《Robo Recall》里所有的枪具有同样的功能,只不过我们针对不同枪有一些参数的微调,比如手枪回复速度比较快,因为比较轻比较小;AK回复速度比较慢,双手持枪后坐力的影响和回复都会比较小一点。但我们也有暂时还没有完成的东西,我们希望枪能跟虚拟世界里面的物理对象有其他的交互。
最后,在游戏中各种玩枪的动作,即抓取系统。我们大概花了足足六个月来做好抓取系统,
刚开始采用的方式类似于Oculus Toybox,当玩家去抓取的时候会有一个球体,这个球体的大小跟你的手掌展开差不多大, 按抓取键的时候,我们会去判断这个球体跟物体有没有发生接触。
但在抓取过程中,我们还发现了一些问题。用户经常会很远距离去尝试抓他肯定抓不到的东西,或者说对于深度判断不是那么准确,明明没碰到,就认为碰到,按抓取键。所以我们加入了一些感知的反馈系统,因为人类的感知系统是很敏感的,一旦反馈给他,他能比较清楚地知道发生了什么情况。比如,通过振动反馈,手慢慢接近物体时,就开始有微小的振动,随着距离越来越接近,振动感越来越强劲。这样能很好地判断玩家的手是不是离它越来越近。另外,通过颜色来区分。用一个后处理材质把用户当前能抓到的东西高亮表现出来,当他发现哪个东西变成黄颜色,就会按下抓取键。即使不是玩家想要的,经过大脑的反馈以后,也可以抓过来扔掉,再去抓想要的东西。
然后我们尝试让玩家的手变的更长,可以抓到更远的东西。尤其是Oculus的追踪系统,当玩家弯下腰的时候它很可能会被遮蔽掉,玩家就可能捡不到东西,延长距离后,玩家就很容易捡到东西。我们希望有更好的体验,比如地上有一把枪,你可以把枪捡起来。接下来的问题是扩展距离要设置的多远?而根据测试2米是最好的。
第三个问题是朝向的标准。比如说如果我们把抓取的延伸的朝向按照你手的朝向来做,那如果玩家是瞄着它用手来,其实是很简单的。但是当物体在玩家手斜下方时,玩家是抓不到的。如果知道机制是工作的,其实是有很好体验的,但如果不知道,玩家就会很厌烦。
我们尝试的方案是通过从眼睛到手生成的方向来计算延伸出去的位置。但是如果从侧面这样拿东西,手从侧面来看是偏的,这样又是拿不到的。虽然这个方法看起来已经好了很多,但还是存在我刚刚说的某些情况下导致用户的预期没有办法被满足。
最终我们的解决方案就是把刚刚算出来的两个朝向取了一个平均值。我们希望能有更高级的方案,比如说能有眼球追踪,我知道玩家注视着什么,从而知道玩家现在关注的是哪样东西,然后就把它抓起来。
《Robo Recall》里有一个很重要的设计是同时可以抓这些机器人,那么第四个问题是机器人被抓以后像死掉了一样,看起来没有任何反抗。基于此我们加了物理动画的功能。比如在《Robo Recall》里面,那些机器人被枪打到的时候,他除了在做正常的动画,也会有受物理冲击以后的物理效果,两者可以混合到一起。
子弹交互的相关问题
子弹从发射开始就一直是以全速往前飞的,我们在它刚开始离开枪管的时候把速度降四分之一,最后再把速度提到本来的1.25倍,整个子弹飞行过程速度是差不多的,但是可以让玩家注意到子弹离开枪管的时候,跟随子弹的轨迹去打向目标。做了这个改动以后,其实大家也没有发现这个变化,感受就明显好了很多。
我们要潜在的帮助用户。比如在《Bullet Train》里最后关卡设计的Boss,玩家需要放导弹。玩家只要抓住导弹,用导弹瞄准Boss,然后松手就可以。
我们观察那些失败的行为,他们并不是瞄准直接放手就好了,而是像扔篮球一样。所以我们的解决办法是把它做成像真的在扔导弹一样。于是我们把用户扔的时候那个手位置的轨迹记录下来一部分,然后来平均计算出他出手的位置,我们故意做了一些扰动,让它看上去像是被你扔了以后慢慢朝向前面。这样以后其实大部分人都已经能扔中Boss了。
但还是有一些特别的用户可能还是会有问题。但当发生这个情况的时候,玩家每失败一次,我们会微调一个系数帮他自动标准一点。所以第二次扔,就会慢慢地看到它帮你修正的更接近Boss一点,最后随便怎么扔也能扔中。但是如果开始就打开辅助系统,用户是不爽的。在修正过程中,前半段还有个0.5秒左右的时间按照玩家扔出去的方向再慢慢修正的。却给玩家的感觉就是好像越扔越准,其实他一直没扔准过。
这个准则其实是你扔的时间越长,我们帮助玩家扔准的辅助越多。
虚拟空间移动的解决方案
《Robo Recall》有非常好玩的机制,接下来的问题是怎么在虚拟空间环境里移动?比较大的问题是玩家需要对准Oculus的Tracking系统,一旦转身,模型可能被自己的身体遮蔽掉。我们想尽可能避免让用户转来转去,既然在游戏里面看到这种分离的手和头,不是一个完整的人,那为什么不能传送?
就拿《Bullet Train》场景设计而言,所有的交互体验其实都发生在中间位置,所以玩家其实是可以游走整个场景中,我们会自动帮玩家把朝向对着事件发生的中心。除了定点的传送外,我们还能潜移传送。当某处出现一个敌人,玩家可以瞬间传送到敌人的面前。
虽然这个机制还是可以工作,用户也不会自己转来转去,因为玩家总是视角对准接下来要发生事件的位置,然而这个设计还是有很多的限制的。比如《Bullet Train》里是竟技场形式,可以让玩家永远朝向中间,随便传向哪里。但是《Robo Recall》这样的城市场景,我们希望玩家可以自由地到处走。
《Robo Recall》的场景相当复杂,高低的地方甚至小的拐角玩家都可以到达,所以我们希望有一些其他系统来帮忙。于是我们加入一个功能叫带方向的传送,即玩家瞄准的方向就是传送的方向。
传送方向是可以控制的,传送到的位置我们不是用直线的,而是曲线,这样可以限制传送的距离,也能更好地传到玩家需要的位置。另外,当传送距离远了以后,直线传送稍微一抖就会偏离。还有一些更小的细节,比如传送的目标点,其实上面还有玩家的形象,就是他的头盔和两只手,头盔和手的朝向能指示出你当前和正确的定位相差多少。
虽然比之前应用在《Bullet Train》的方案灵活,但还是有一些问题。因为在实际过程中玩家还是可以真实转动,转动就会造成模型可能被自己的身体遮蔽掉的问题。所以我们在屏幕上设计了一些辅助的箭头,一直把玩家引向正面的朝向。但是玩家还是会有一些混乱,因为真实世界不会传送的。比如玩家突然到达某个位置,他会搞不清楚他是从哪里来的。所以我们沿用一些在《Bullet Train》的技巧,比如传送过来的道路上会有一条轨迹,让玩家看到他来时的轨迹。
技术角度谈提高画面品质立体渲染对画面的提升效果
接下来我们谈谈怎么样从技术角度更进一步提高画面品质?这个比较老的技术,我们就很快过一下,就是Instanced Stereo Rendering在降低CPU 的功能。传统是先画左眼再画右眼,用了Instanced Stereo Rendering是左右眼一起画的。
Hidden Area指我们在周边,最后没有用的那些地方,先在裁减面画出来,最后所有的Test都会失败,接下来的操作、计算都不会发生。Visible Area Mesh是反向,可见区域画出之后,在做后处理的时候,实际的计算处理就变成了Mesh区域,象素处理变少,会进一步提高效率。这两个东西一起结合起来我们在《Bullet Train》的Demo里面节省了相当多的GPU时间,在Oculus上面节省了0.25-0.3ms。
全效渲染和延迟渲染在游戏上的对比
接下来我们要讲一些功能在4.14里面有的场景,主要我们希望能使用同样的《Robo Recall》表现不同的环境效果,比如一个城市有夜景也有白天的场景,我们尽可能用静态的光照来做场景的光照环境。因为都是静态的光照所以相率还是相当高的。
全效渲染器是怎么回事?在《Bullet Train》的时候我们用的还是一个延迟渲染器,因为有GBuffer可以做特别的技巧,所以可以用GBuffer里面的各种信息和技巧。比如《Bullet Train》里面我们关掉Scene,通过扰动做出了这种反射效果。
还有就是这个火车刚开始的场景,本来一开始我们用75个动态光非常费,后来我们因为可以访问到GBuffer,只用了一个动态光把效果做到了现在这样。在我们做《Bullet Train》的时候,Oculus也做了一个基于UE4的全效渲染器,我们也参考了他们的全效渲染器做了我们自己的版本。
比较一下我们自己的全效渲染器和延迟渲染器,最大的区别是抗锯齿部分,延迟渲染器我们只能用TTA,在这种本来分辨率不是很高的VR环境下会显得更加模糊、不太清晰。然而这种情况下可以访问整个GBuffer,从功能性角度来讲是最完善的,所有的引擎渲染功能你都可以用得到。
用全效渲染器可以选择用TAA还是用MSAA,在《Robo Recall》里我们有很多直线条的街道,MSAA会带来非常好的帮助。全效渲染器总体来看是更快一点的,但是是损失了屏幕空间的效果之类的,但是全效渲染器能够适配更低一些的硬件。
Oculus的实现是完全独立的Render的分支,我们的做法是在我们的延迟渲染器加了一个前向的path,你可以把延迟的path关掉,或者同时开启延迟和前项。这样的好处可以在全效渲染器用一些延迟渲染的内容。
在一块Nvidia GTX 970上的测试,可以看到延迟管线延迟是12.3ms,全效渲染器延迟是9.56ms,同样超采量是135% ,其中0.7秒的时间主要节省在GBuffer的带宽占用包括各个地方的拷贝之类的,接下来还有一个比较大的部分,是因为你可以单独开关某一个物体的选项。
还有一个好处是你用全效渲染器的时候渲染分辨率的调整的范围可能可以更大,因为TTA比较大,你不能延迟选项设的太小,但是全效你可以用MSAA,你可以设置Oversampling比较低一些。
其实这两个渲染器都有各自的优势,不是说哪个全效就是可以帮助你解决所有的问题,比如你要做虚拟的人类或者皮肤的效果可能还是需要用延迟渲染器的一些功能。在《Robo Recall》当中我们一开始用延迟,换到了全效渲染器,我们用了MSAA,还是有一些地方我们我要特别的注意和改进。
MSAA对于轮扩的效果还是不不错的,但是对于这种亚象素级的没有什么办法,可以看到右边的图越来越小以后就会有一圈一圈的效果,《Robo Recall》因为里面有很规整的城市,比如窗户之类的建筑,很远看过去就是有亚象素级的就会产生比较明显的效果。
一个很简单的解决方案是刚好我们这些建设是比较规则的形状,简单的方法就是把它换成一个没有什么细节,直接靠贴图。还有一个问题MSAA没法解决特别明显的闪烁的效果,TAA一直可以很好的缓释这个效果,但是MSAA不行。
CPU上的性能时间调整
刚刚说的是一些渲染的东西,接下来我们看看CPU方面开销的性能调整。第一大功能是我们的把蓝图转成C++后端的功能,《Robo Recall》将会成为第一个正式使用并发布这一个功能的项目,因为《Robo Recall》有大量的主要的Game Play都是用蓝图来写。我们这个功能能帮助你改进多少CPU时间,取决于用了多少的蓝图,在这个项目里面大部分情况下我们也只省了0.25毫秒左右,但是一个比较大的改进是不太会有那种卡顿的现象,本来用蓝图的时候有一些特别的地方会卡个将近四五十毫秒的样子。虽然这相当的有帮助,但是我们还是要做很老套的优化。
我们后来发现有两大块导致CPU的开销比较高。第一大问题是在BP里面的一些数学计算。因为我们比如枪械各种各样的计算,有大量的数据计算在蓝图里,我们开始觉得用到蓝图转到C++应该没有什么开销,直到看到生成的代码。
比如说一个App,在蓝图转向C++以后,跑在类似虚拟机的环境下其实加了很多指令,本来这个东西编译器应该可以自动消除这一行,这样就做不了。于是我们把一些特别底层重要的一些函数以及数学库里面的函数做了一些优化。大概是BP生成C++代码的优化,直接可以让它运行起来,这是一个相当大的性能改进。
另一块是将近5毫秒的时间是耗费在移动处理上。比如一个机器人在运动的时候,因为自己发生了位置的变化,所以他会更新自己的Scene Component,下面挂了一些子Scene Component,所以所有的级都要计算,并且有时候他还要去判断有些区域的碰撞之类的情况,开销相当大。
《Robo Recall》里一个很重要的功能就是交互,所以我们专门做了一个Component,而且Scene Component上面会挂一些碰撞和其他的Component。我们来看一下比如双组的机器人,分了头、躯干、双手、双脚,总共加起来有五十个Scene Component,是相当多的。
大部分时候用户并不会跟那么多机器人都发生交互,所以更新那么多非视觉的Component是很浪费的。所以大家可以看到这条黄线所在的区域是你用户周围的人触手可及的区域,这个区域内我们如果敌人跑到这个区域我们才会把所有的Scene Component放到root上去更新,而在黄线之外的Component都不需要更新。
Component功能写到专门的Component里,根据距离决定是不是要把其中的一部分没有必要的Scnens Component省略掉。最终省了4毫秒,我们发现有一些枪在做中间版本加了很多不必要的Component,最后有二十几个,最后减少到五六个。
画面再优化的三个细节:超级视觉裁减+关注点渲染+monoscopic
在发布前还有什么我们还没有做的打算做的?其中之一叫超级视觉裁减,现在的视觉裁减会在每只眼睛各做一遍,还是有一些额外的开销的。我们打算把两只眼睛看到的东西都算进去计算一遍,预期可以节省一毫秒左右。
还有一个就是叫棋盘格的关注点渲染,其实中间注视的地方渲染可能比较高,其实分辨率是不变的,只不过周围用一些棋盘格的样子,然后实际的象素计算会比较少一些。
另外一个叫monoscopic Rendering,是双眼看到的东西不太一样,即近景不太明显,但是远景比较明显。比如,八米以外位置差别是小于一个象素的,第三个摄像机单独裁减一遍,双影化的都是近景的物体,再跟远景质化一遍的物体合成起来,我们在已经有代码了,在移动端的VR上面看到四分之一的提升,接下来我们打算挪回桌面渲染器。
关注微信公众号:VR陀螺(vrtuoluo),定时推送,VR/AR行业干货分享、爆料揭秘、互动精彩多。关注微信公众号:VR陀螺(vrtuoluo),定时推送,VR/AR行业干货分享、爆料揭秘、互动精彩多。