在12 月 15 日举办的UNREAL VR DEV DAY活动中,Epic Games的技术总监Nick Whiting详细分享了《Bullet Train》和《Robo Recall》两个项目中的设计技巧、遇到的难题以及思考。

2

在设计游戏中的交互部分时,Nick Whiting介绍了整个test循环,“我们做完一个功能,让Play test的人来做测试,通过他们的反应,看哪些地方有问题。很多时候他们不一定说出来,但是你可以通过观察发现问题并加以改进。”

随后Nick Whiting从枪械瞄准、物理感、后坐力设计、抓取系统、子弹轨迹等多个方面详细的进行了经验的分享。此外Nick Whiting分享了对于VR环境中移动的问题思考和一些列解决方案。

除了进行设计上如何满足用户的预期的分享,Nick Whiting还分享了如何从技术角度更进一步提高画面品质的相关问题,对全效渲染的优缺点进行了分析。Nick Whiting认为,“选用延迟渲染还是全效渲染要根据具体需求来考虑,两者都不是万能的。举例来说,如果要做虚拟的人类或者皮肤的效果可能还是需要用延迟渲染器的一些功能。”

Nick Whiting还提出了两个导致CPU的消耗比较高的问题和解决方案,“一个问题是在BP屋里面的一些数学计算需要优化,还有一个问题是有将近5毫秒的时间是耗费在移动处理上。”在未来,Nick Whiting表示还将实现超级视觉裁剪和棋盘格关注点渲染的功能来进一步节省CPU消耗。

Robo Recall

以下是演讲实录,VRZINC整理有删减:

Nick Whiting:大家好,我在Epic Games负责VR部分,是Epic Games的技术总监。今天主要分享的是我们从去年发布的现在的《Robo Recall》项目中犯过的错误和积累到的经验。

我先讲讲Bullet Train这个项目,这个项目是Oculus当时有原型的时候,希望我们做一个比较正规的VR项目,就像我们做的战争机器,所以有了《Bullet Train》这个项目。

这个项目是一年前的,刚开始只有两个人大概做了四周,这个项目一共也就只有十周时间。当时有一个目的是希望能在Showdown基础上进一步提升画面效果,另一个目的则是我们希望用真实的项目来看一下引擎做VR内容时的效率如何。因为《Bullet Train》当时非常成功,所以Oculus希望我们把它做成一个完整的游戏,这次我们有一整年的时间可以把当时很多没有做好的东西做的更好。

1

观察用户自主体验过程中的反应进行改进

为什么Bullet Train很成功?当时成千上万用户在玩的时候,我们看到了一些关键的地方。其中一点是我们做Bullet Train的时候,我们需要看用户玩,观察他的反应,让用户感受到自己在游戏里面屌爆了。或者看哪里他感觉跟预期不太一样,这可能是我们做的不够好的地方。

这就是整个Play test的循环,我们做完一个功能,让Play test的人来做测试,通过他们的反应,看哪些地方有问题。很多时候他们不一定说出来,但是你可以通过观察发现问题。

在这个过程中我们发现,用户自己去探索和发现规则和交互,这是非常有意思的。就像钓鱼一样,你要晃动钩鱼就会咬上来。在VR环境中,用户如果想要交互某一样东西,你就要满足这样的信息去让用户能够把它交互出来。刚开始的时候,我们火车里面有拉环,用户会很自然地想用手去碰它,去交互。然后发现它好像没有交互,他们就会很不爽。

还有一个就是设计上我们之前犯的错误。为了模拟比较真实的感觉,所以我们在手雷上面做了一个拉环,这个拉环是开了物理模拟的,你能看到晃动的时候它有物理的感觉。于是很多玩家在玩的时候用另外一只手拉拉环,像真实的那样。结果发现不能交互,实际上只要直接把手雷扔出去就会炸掉,显然这是一个很失败的地方。

当时还有一些问题,比如按键是冲突的。好在时间比较充裕,所以我们从顶层把输入模块重新做了一下来满足这些逻辑,用户非常满意这个效果。

枪械瞄准、物理感、后坐力设计

大家知道这个游戏主要都是在用枪玩的,但是很多人可能其实没有真的用过枪,所以用户从电影里看到的用枪方式和自己真的使用枪,其实还是有很大的不同。刚开始我们发现很多用户没有真实的用枪经验,经常学电影里这样瞄,枪都会瞄的偏下。但是那些有过用枪经验的,知道怎么去三点一线瞄的话,那还是很准的。

主要原因是手握的对应位置和实际持枪的位置有一些差别,我们思考有什么方法可以解决这个问题?一开始我们尝试的是Oculus Toybox里面用的方法,希望虚拟环境中手的模型和真实世界保持完全一致。这个方法很简单,但还是有一些问题,因为手握模型的感觉和握枪的感觉是不太一样的。于是我们没有保持手对应的关系完全一致,而是让枪直接跟模型的位置对应起来。由于因为模型的关系,需要做一些细微的调整。

4

怎么样的对齐方式是最好的?是让控制的模型完全吻合还是让后面手柄的方向完全一致?其实这个我们也还没有定论,最后的结果就是在两者之间,模型和手柄都是差不多可以对上。结果我们在做游戏测试的时候,大部分用户有些手偏高有些手偏低,就比较合适,这样反而是比较好的结果。

我们接下来要做的工作是刚开始教学的时候会让用户先去打靶,如果用户始终瞄的有一些偏高,我们会帮他往下修正一点,接下来的设计我们都会帮用户微微修正一点。

枪有三个主要部分。第一个是物理感,握着枪是有重量感的,开枪的时候是有后坐力的。第二,枪具有运动感,在开枪的过程中会有一些反馈,你可以闻到硝烟的味道。还有一个就是用枪可以玩各种杂耍,大家看过这种动作电影。

刚开始我们就直接使用了引擎自带的模拟功能,就是把枪作为一个Physics,这是很容易设计的,只要打开就可以了,你握着手枪的时候就设置完了。至于模拟后坐力其实也很简单,直接加了一个物理的Impulses,可以模拟真实情况下受到冲击的感觉。一个很奇怪的点,我们认为加了后坐力这其实是非常棒的感觉,不知道为什么大部分其他VR设计游戏都没有。

直接把枪设置成物理对象的好处是会有与其他枪和物体碰撞的声音。但这样有一个比较严重的问题就是枪可能会卡在某些地方,比如枪模型较大的时候,会卡在桌角之类的地方不停抖动,或者有时候会突然再弹回来,这一点需要注意。

大多数人认为,VR里面所有东西都是低延迟,你挪到哪里就跟到哪里。但对于枪来说,这其实是有一些问题的,因为枪有重量感,如果你能很快地移动,拿个十斤的东西这样甩甩看,是不太可能的。所以我们反而加了一些延迟,让枪更有重量感。我们故意做了一些延迟,会把前期帧的速度累计起来,慢慢移过来。虽然我们没办法让你实际握的东西变重,但是我们可以给你这样的感受,好像这个东西的重量感有一些变化。

还有一个非常重要的就是后坐力感,后坐力不能用物理来加。我们最后来模拟后坐力的一个节点图,最关键的是左上角的Timelife功能。为什么用它而不是用线性的?因为产生后坐力手往上抬时你会想压下来,所以一开始会比较快后面会比较慢,而不是线性的过程。这就是用Timelife来模拟后坐力的时候控制枪的变化,游戏里面加上Recoll以后的效果,在全速的时候可以看到每枪开完后坐力往上之后很快就回来了。《Robo Recall》中恢复时间就比较慢,可以很明确地看到在连续开枪的时候它是慢慢往上走的。

我们把所有这些功能都放到枪的分类里面,这样所有的枪都有同样的功能,只不过我们针对不同枪都一些参数的微调,比如手枪的回复速度比较快,因为轻比较小,AK这种枪就比较慢,双手持枪后坐力的影响和回复都会比较小一点。

抓取系统的设计

接下来要谈的是抓取系统,我们大概花了足足六个月来做好这个东西。刚开始我们实现是跟OculusToybox实现差不多的,当你去抓取的时候会有一个球体,这个球体的大小跟你的手掌展开差不多大,当你按抓取键的时候,我们判断这个球体跟物体有没有发生接触。

然而我们发现一些在用这种方式的时候出现的问题,用户经常会很远距离就去尝试抓一个他肯定抓不到的东西,或者对于深度不是那么准确,明明还没碰到,他就以为碰到,所以就按抓取键了。

现实生活中大家不会去考量我要拿那个东西,第一步伸出去,第二步抓过来,基本上是一次性的动作。人的感受很敏感,借助各种综合的因素来判断你是不是能抓到它,所以我们尝试加了一些感知的反馈系统。其实人类的感知系统是很敏感的,一旦有一些反馈,就能比较清楚地知道发生了什么情况。例如你能抓到某项东西的时候,我们给你一些微小的振动,通过振动反馈,能很清楚地知道接下来是否能抓到这个东西。再举个例子,我们手慢慢接近还没有碰到的时候,就开始有微小的振动,随着你越来越接近,它的振动感越来越强劲,这样就能很好地判断你的手是不是离它越来越近。

此外我们通过后处理材质把用户当前能抓到的东西表现出来,当你发现哪个东西变成黄颜色,你可以接下来按抓取键就会把它抓过来,即使这东西不是你想要的,经过大脑的反馈以后,你也可以抓过来扔掉,再去抓你想要的东西。接下来我们会尝试让你的手变的更长,可以抓到更远的东西。因为比如说Oculus的Touch,你弯下腰的时候它很可能会被遮蔽掉,你就捡不到东西,我们延长这个东西以后,你就很容易捡到东西。

而Oculus Toybox的方法是这样,永远是在你能抓到的东西,一旦它掉到地面上,就会把这个东西销毁掉。

对于我们来说,我们希望有更好的体验,比如地上有一把枪,我们不希望你永远从空中抓枪,我们希望地上有一把枪,你可以把枪捡起来。接下来的问题是,扩展距离要设置多远?

根据我们的测试2米是比较好的,如果斜在前面,这个位置大概刚好1.4、1.5米左右。还有一个问题是朝向标准,距离远了以后很难知道具体要抓的是哪样东西?所以接下来我们尝试的方案是通过从眼睛到手生成的方向来计算,就是你延伸出去的那个位置。但是又有一个问题,如果我的手从侧面拿东西,手从侧面来看是偏的,这样又是拿不到的。最终我们的解决方案就是把刚刚算出来的两个朝向取了一个平均值,目前来说这个方案已经相当好了,但我们还是以后希望能有更高级的方案,比如说能有眼球追踪,我知道你注视着什么,我就知道你现在关注的是哪样东西,然后把它抓起来。这样就解决了可以抓取一定距离内东西的问题。

我们在设计《Robo Recall》的时候有一个很重要的设计,用户可以抓住机器人。然而机器人被抓了以后就在那边像死掉了一样,没有任何反抗的感觉。因此我们在里面加了物理动画的功能,一边受到物理控制,一边还是在尝试播放动画,两者可以混合。

Bullet Train

子弹轨迹的设计

接下来我们看一看如何让用户观察到子弹?因为子弹很快,用户根本观察不到子弹。所以我们做了这样的设计改动,原本子弹从发射开始就一直是以全速往前飞的,我们在它刚开始离开枪管的时候把速度降四分之一,最后再把速度提到本来的1.25倍,整个子弹飞行过程速度是差不多的,但是可以让用户注意到子弹离开枪管的时候,跟随子弹的轨迹去打向目标。

刚开始大家可能枪打了,子弹往哪里飞出去都感受不到,所以有些人在抱怨,因此做了这个改动以后,虽然大家也没有发现这个变化,但感受就明显好了很多。

我们需要潜在的帮助用户,用户当然不希望觉得你帮助他作弊了,但我们其实还是要辅助一下。例如在《Bullet Train》中最后会有Boss需要使用导弹攻击,玩家只要抓住导弹,用导弹瞄准Boss,然后松手就可以。我们的解决办法是把它做成像真的在扔一个导弹一样,于是我们就干脆把用户扔导弹时手位置的轨迹记录下来一部分,然后平均计算出他出手的位置,因为导弹朝向可能不太对我们故意做了一些抖动,让它看上去像是被玩家扔出以后慢慢朝向前面。

玩家每失败一次(导弹没有扔中),我们会微微调一个系数他们自动瞄准一些。所以最后玩家失败几次后总能扔中。但如果我们一开始就打开辅助系统,用户其实会不爽,因为他明明觉得自己完全没瞄准怎么就扔中了。这个修正是前半段有0.5秒左右的时间按照用户扔出去的方向前进,随后再慢慢修正。给玩家的感觉就像扔的准确度越来越高了,其实他们一直没扔准过。

3

VR环境中移动的思考

接下来我们谈下如何在虚拟环境中移动的问题。在Oculus的Tracking系统中一旦转身模型可能被你的身体遮蔽掉,无法对准。因此我们起初想尽量避免让用户转来转去。既然玩家在游戏里面看到的是这种分离的手和头,不是一个完整的人,那为什么就不能传送?

在《Bullet Train》场景设计中,所有的交互体验其实都发生在中间位置,用户其实是可以游走整个场景中,然而我们会自动把朝向对着事件发生的中间。除了这种定点传送以外,我们还有一个瞬间传送。当出现一个敌人的时候,玩家可以瞬间传送到敌人的面前。

然而这种设计还是有很多的限制,《Bullet Train》因为是这样一种竞技场形式,我可以让用户永远朝向中间。但是像《Robo Recall》这样一个城市场景中,我们希望玩家可以自由地到处走。《Robo Recall》的场景其实相当复杂,高低不平甚至还有小的拐角玩家都可以去,所以我们希望能有一些其他系统来帮忙。

于是我们加了一个功能叫做带方向的传送。用户可以控制传送的方向,传送到的位置我们不是用直线的,而是用一个曲线,这样可以限制传送的距离,也能更好地传到你要的位置,包括比较高的位置等。因为直线传送距离较远的情况下,玩家稍微抖动一点点就会偏离的很厉害。

其中还有一些小细节,例如传送的目标点会出现角色的形象,就是玩家的头盔和两只手。这个头盔和两只手的朝向能够显示当前位置和定位正确的位置有多少偏差。虽然这个比之前《Bullet Train》的方案灵活很多,但还是有一些问题,因为玩家转动还是可能会出现刚才遮挡的问题。所以我们现在设计了一些屏幕上辅助的箭头,引导用户转向正面的朝向。然而用户还是会有一些混乱,因为真实世界不会传送的,玩家突然到那个位置,会搞不清楚从那里来的。所以我们还是会沿用一些《Bullet Train》中的设计,比如传送过来的道路上会有一条轨迹,让玩家看到自己是从哪里过来的。

全效渲染的优缺点分析

刚才我们说了一些设计上如何满足用户的预期,接下来我们看看如何从技术角度更进一步提高画面品质?这个比较老的技术,我们就很快过一下,就是Instanced Stereo Rendering在CPU上的功能。传统是先画左眼再画右眼,用了Instanced Stereo Rendering是左右眼一起画的。Hidden Area指我们在周边,最后你没有用的那些地方。先在你的裁减面画出来,接下来的操作、计算都不会发生。Visible是反向的,可见区域画出来之后,这样在做后处理的时候,实际的处理就变成了这个区域,象素处理就会变少,会进一步提高效率。这两个技术结合起来我们在《Bullet Train》的Demo中节省了相当多的GPU时间,在Oculus上面节省了0.25-0.35。我们希望能在《Robo Recall》中使用相同的场景表现不同的环境效果,这样一个城市有夜景也有白天的场景,我们尽可能用静态的光照来做场景的光照环境,效率会非常高。

全效渲染器是怎么回事?在《Bullet Train》的时候我们用的还是一个延迟渲染器,通过GBuffer可以进行很多设计。例如《Bullet Train》中我们关掉Scene,通过扰动做出了反射效果。还有火车刚开始的场景,本来一开始我们用75个动态光非常浪费,后来通过访问到GBuffer,只用了一个动态光就做成了现在效果。

在我们做《Bullet Train》的时候,Oculus也做了一个基于UE4的全效渲染器,我们也参考了他们的全效渲染器做了自己的版本。比较一下我们自己的全效渲染器和原生渲染器,最大的区别是抗锯齿部分。原生渲染器我们只能用TTA,在这种本来分辨率不是很高的VR环境下会显得更加模糊、不太清晰。然而这种情况下你可以访问整个GBuffer从总功能性角度来讲是最完善的,所有的引擎渲染功能都可以用得到。

用全效渲染器可以选择用TAA还是用MSAA,我们因为有很多直线条,所以MSAA会带来很多的帮助。全效渲染器损失了屏幕空间的效果,但总体来看是更快一点,能够适配更低一些的硬件。

Oculus能够实现完全独立的Render分支,我们的做法是在延迟渲染器上加了一个全项的path,你可以把全效的path关掉,同时开启延迟和选项,好处是通过全效渲染器中可以用一些延迟渲染的内容。

还有一些是接下来会支持的,其中最重要的一个是动态投影。在一块Nvidia970GTX上全效渲染器只有9.5,with135% Oversampling,其中0.7毫秒的时间主要节省在GBuffer的带宽包括各个地方的拷贝之类的。后面还会有提升,因为你可以单独开关某一个物体的选项。

还有一个好处是用全效渲染器的时候渲染分辨率的调整的范围可以更大。因为TTA比较大,你不能将延迟选项设的太小,但是全效你可以用MSAA,可以设置得比较低一些。其实这两个渲染器都有各自的优势,不是说哪个全效可以帮助你解决所有的问题。举例来说,如果要做虚拟的人类或者皮肤的效果可能还是需要用延迟渲染器的一些功能。

还是有一些地方我们需要特别的注意和改进,MSAA大家知道对于轮扩的效果还是不不错的,但是对于这种亚象素级的没有什么办法。《Robo Recall》有很整齐的城市,很远看过去如果亚象素级的就会产生比较明显的效果。一个很简单的解决方案是刚好我们这些建设是比较规则的形状,简单的方法就是把它换成一个没有什么细节,直接贴图。还有一个问题MSAA没法解决,特别明显的闪烁的效果,TAA可以很好的缓释这个效果,但是MSAA不行。

刚才说的是一些渲染的东西,接下来我们看看CPU的性能调整。第一大功能是我们的把蓝图转成C++后端的功能,《Robo Recall》将会成为第一个正式使用并发布这一个功能的项目。在《Robo Recall》中其实有大量的主要Game Play都是用蓝图来写,在这个项目里面大部分情况下我们省了0.25毫秒左右。有一个比较大的改进是不太会有那种卡顿的现象,本来用蓝图的时候有一些特别的地方会卡个四五十毫秒的样子。虽然这相当的有帮助,但是我们还是要做很老套的优化。

这里有个小插曲,Oculus一开始和我们说之后跑demo的机器CPU主频是3.2级的,我们在设备上测发现完全没有问题。结果到前一天晚上他们说真实的机器主频只有2.7级。

两个导致CPU的消耗比较高的问题

后来我们发现有两大块导致CPU的消耗比较高。其中一个问题是在BP屋里面的一些数学计算,关于枪械各种各样的计算,有大量的数据计算是在蓝图里面。我们开始觉得我们用到蓝图转到C++应该没有什么消耗,直到我们看到生成的代码。例如一个App,其实很简单的功能,但是在蓝图转向C++以后,跑在类似虚拟机的环境下其实加了很多指令。于是我们把一些底层特别重要的一些函数以及数学库里面的函数做了一些优化,这是一个相当大的性能改进。

还有一个问题,有将近5毫秒的时间是耗费在移动处理上。例如一个机器人在运动的时候,因为他自己发生了位置的变化,所以他会更新自己的Scene Component,所有的级都要计算,并且有时候还要去判断有些区域碰撞之类的情况,消耗都非常大。

刚才提到,《Robo Recall》有交互可以抓机器人的各个部位,所以我们专门做了一个Component,而且Scene Component上面会挂一些碰撞和其他的Component。两组机器人,头、躯干、双手、双脚,加起来有五十个Scene Component,是相当多的。其实大部分时候用户并不会跟那么多机器人都发生交互,更新那么多非视觉的Component是很浪费的。

所以我们将用户周围人触手可及的区域进行划分,如果敌人跑到这个区域我们才会把所有的Scene Component放到root上,进行更新,而其他的Component都不需要更新。这样的改进最终节省了4毫秒。我们还发现有一些枪在做中间版本的时候加了很多不必要的Component,从二十几个最后减到五六个。

未来要实现超级视觉裁剪和棋盘格关注点渲染

我们再看看在发布前还有什么还没有做打算做的?其中一个叫超级视觉裁减。我们现在的视觉裁减会在每只眼睛各做一遍,其实还是有一些额外消耗的,我们打算做一个比较大的把两只眼睛看到的东西都算进去计算一遍,我们预期可以省一毫秒左右。

还有一个就是我们成为棋盘格的关注点渲染。就是其实中间注视的地方渲染可能比较高,其实这不是渲染分率,它的分辨率是不变的。只不过我们周围用一些棋盘格的形式,然后实际的象素计算会比较少一些。还有一个叫monoscopic,双眼看到的东西不太一样,近景可能不太明显,但是远景比较明显。八米以外位置差距小于一个象素,单独裁减一遍,双影化的都是近景的物体,再跟远景只化一遍的物体合成起来。我们现在已经有代码了,在移动VR上面看到四分之一的提升,接下来我们想在PC渲染器上实现。