最近在做一个关于vr游戏的项目,作为一个刚刚毕业并且刚刚进入这一行业的新手,有太多太多的东西需要学了。经过这个三个月的时间,在整个团队的合作下,算是基本完成了游戏吧,平台是三星的gear vr,现有在三星官方商店上架,其实游戏现在还并不很完善,很多bug可能还没修复,用户体验也没有做好,但是由于种种原因还是上架了,好评率不高。不过这次也让我学到了挺多的东西的,在这里就稍微记录一下,作为一个新手的经验,也希望以后还能对照着去做以后的游戏。

这次要讲的是关于性能优化这一块,因为之前准备在oculus上上架,但是oculus上架有个硬性要求就是在note4 note5 s6 s7等手机上的运行准率必须接近60,而我们的游戏一开始并没有,因此就做这一块的记录。做vr的都知道,其实vr并不同于普通游戏,我觉得最最不同的一点就是vr的渲染是普通游戏的两倍,因为有两个镜片,因此在性能优化上必须下很大的功夫,很遗憾我们只花了不到一个月的时间做这一方面,所以其实效果不是特别好,只能算基本满足能玩的要求,但对于眩晕这个问题还是没有得到特别好的缓解。

这里必须说到unity自带的一个工具位置位于Windows->profiler,这个工具主要可以看到当你的游戏在运行的时候,什么物品或者哪个脚本占用了特别大的时间,导致你的游戏变得很慢,由于我做的是渲染方面的优化,所以主要也就是看看CPU ,GPU和Render三个选项里面的内容,然后根据反馈结果去做事情。

我个人觉得,优化的最主要的目的应该就是减少Draw Call的调用量,overdraw指的就当我们把一个图形的所有信息包括位置,法线,颜色等传递给电脑,然后调用一系列API,并把它们放置到gpu可以访问的指定位置,之后调用了_glDraw命令,一个命令就是一次Draw call,例如,一个场景里有水有树,我们渲染水的时候使用的是一个material以及一个shader,但渲染树的时候就需要一个完全不同的material和shader,那么就需要CPU重新准备顶点数据、重新设置shader,而这种工作实际是非常耗时的。因为,减少Draw Call 就成了重中之重的步骤。下面是我们游戏做的一些事情。

1,在搭建模型方面,一开始为了求逼真,因此在建模上都力求完美(然而我们组没有专业的,都是程序猿转行建模),所以做的并不怎么好看但是面数特别多,而面数多就会导致渲染次数变多,这样很耗性能,因此在制作的中期我们就意识到这个缺点,所以就开始大幅度的改模型,基本每个模型都会砍一般的面,但是在手机内的效果看起来也并不是特别差,然而会有一些地方可能看起来并不是特别逼真,因此就用了法线贴图去更进一步优化表面。再到后期,由于场景内物品多了,虽然单个模型的面数少了,但仍然不能减低draw call 的调用数,因此我们又做了一次模型修改,这一次,就是合并材质球,基本上,我们把每个场景里面所有静态的物品都合并了,这件事其实unity好像有有自带的合并贴图的工具,但我们没用到,还是让建模人员把材质球合并,并且把场景内的外壳也合并了,经过这个方式,我们的draw call调用量又再次减半了。

2,在场景的优化上,我们主要运用了烘焙技术,在unity,虽然实时光照可以带来特别好的体验效果,但是,跟电脑端的不一样,手机端由于cpu并不是十分强大,因此实时光太多会导致渲染次数大大增加,最终会反映在画面抖动十分厉害,并且卡顿眩晕感很强,因此,在我们的游戏中,只有一个实时光照,其他的光作为烘焙光照,在这里就必须说到一个光照探针(lightprobe),这个东西的作用就是用于静态烘焙中,对非静态物体产生一个模拟光照。而这个光照并不是动态的,而是静态的,从游戏运行时就渲染,在游戏过程中并不会重复渲染,这样做的好处就是只有在游戏开始时就只做一次然后就没有再次对那些被标记过的物品进行渲染,这一部分并不是我负责的所以只了解下,大致的做法就是在适当的位置添加光照探针,然后把每个静态的物品的static打钩(这里必须注定到的是如果场景有用到自动寻路或者是其他的东西则需要把对应的选项钩去掉),然后选择windows->lighting里面有个scene里面的build就可以,这里需要注意的有两点,一点是在windows->lighting中默认的话有两个东西是勾选的 一个是precomputed realtime gi和baked gi,这里我们需要把第一个的钩去掉因为这个是关于实时光的,第二个就是有的时候可能在渲染完成后的场景中物品表面会有乱乱的,这是因为UV的原因(具体的也不太清楚),这时需要找到物品的模型在他的Generate Lightmap UV勾选就可以了。此外就是pixel light的数量,我们的游戏里面是1,这个的设置方式是在edit里面的project setting 里面的quality里,这里面有很多东西都可以操作,包括防锯齿的一些,还有阴影效果的,还有其他一些。

3,在代码方面,尽量少在update用gameobject.find这个函数,好像这个函数是遍历式的寻找物品,这样会降低性能,我们采用的方法是在定义的时候定义一个公有的gameobject或者可见的私有gameobject,然后在面板中把对应物品拉到相应位置,这个方法好像也并不是最好,听一个大神说最好的方式应该是在一开的时候就定义了并且find好,之后就不在做查询的操作,这样的代码也不会特别乱。然后就是少用update函数,至于为什么我也不是特别清楚,我们花在代码上的时间并不是特别多。

4,使用遮挡剔除技术,这个技术也是unity自带的十分强大的一款技术,这一技术主要是讲我们的场景分成许多个小块,然后将摄像机看得到的地方的物品显示出来,看不到的就不显示,这个地方其实也不是特别难操作,也是要选择static里面的Occludee static,然后在点开Windows->OcclusionCulling里面设置bake的大小,然后点击bake就可以了

其实,还有一门技术就是LOD技术,但是由于我们的游戏场景并不是特别大,所以就没有用到这一技术,这一技术的做法是需要在建立模型的时候建两个模型,一个面数多,较为逼真的,一个面数少,较为粗糙的,在场景中,当摄像机里物品远的时候就使用面数少的模型,近的时候就使用面数多的模型,这也可以优化游戏的性能,但是如果场景太小也没有什么作用,因此就没用了。

其他的一些小的优化:

1,在场景中,尽量不要用到mesh collider,因为这个很影响性能;

2,由于手机加载场景很慢,因此在游戏设计中的第一个场景最好选用比较简单的,让玩家可以一开始就进入一个可视的场景而不是一直黑屏等待您的主场景;

,由于在手机端,摄像机的移动会造成较大的眩晕感,因此,最好就是摄像机移动的慢点,并且摄像机只朝着一个方向线性运动不要加速运动并且移动的时间不要太长(这是在一篇文章上看到的,我们的游戏并没有用到);

4,unity自带的Mecanim动画系统也要尽量少用,最好一个镜头里不要同时出现多个带有animator的物品,这个亲测也会影响手机端的体验。

然后想说一点就是,另一个性能优化的方向就是关于shader的,然后这个太难。。。我们现在还不会,所以做出的效果也不是特别好,这里我要推荐另一款同款的游戏叫绝命缉凶,英文名叫dead secret,这款游戏真的做的特别好,这里有他们游戏的一些关于性能方面是如何处理的,分享给大家学习一下。

最后在推荐一个网站是作为初学者(也就是我这种菜鸟),不知道某个函数是干嘛用的时查询的网站,初学的多学些函数感觉也没有什么坏处。

希望我这篇文章能在这里抛砖引玉,也希望大神们能帮我指出我的错误和不足,或者是给我点建议,因为其实到现在为止,虽然游戏基本完成了,某些场景的帧率也能基本保持在60,但还是需要花很大功夫在这一方面。大家帮忙指点指点。