游戏性能优化的五个方向

或者换个标题也行:3D实时程序性能优化的五个方向。一般来说,这五个可以认为是性能优化的顺序,越靠前意味着单位时间投入的产出越大。大多数时候来说,优化都会牺牲一些质量,优化本质上就是取舍,本质上就是说,提升的性能值不值得牺牲一点画面。切记:我们只是在做游戏,并且还是在性能可怜的移动端上,而不是电影。游戏里最多30毫秒就要渲染一帧,而电影你可以用一个服务器集群花几小时渲染一帧。其实用牺牲画面来换性能的提升从游戏诞生时就一直广泛存在,例如控制面数、压缩纹理等等。关键是程序员和美术同学之间要建立一种良性的互相制约的关系:程序员不要为了优化性能把画面搞得惨不忍睹;美术不应该看到一丁点的画面损失就大呼小叫。流畅性和优秀的画面对玩家体验来说同等重要。

一、引擎使用层面

主要包含两方面内容。

1、引擎内置功能的使用是不是合理。例如,项目里场景很小,却打开了长距离的级联阴影,肯定不合适。

2、资源格式是不是合适。例如,纹理没有用压缩格式,纹理的压缩格式选的不好(现在3D游戏有个趋势,都尽量使用ASTC),面数太多或者没有做LOD,等等。这些问题人工去查费时耗力,现在有些工具可以自动排查,例如官方的UPR。

二、渲染管线

作为通用商用引擎,引擎内置的渲染管线会兼顾所有的项目类型,所以设计时必须考虑灵活性。但是灵活性往往会牺牲不少性能。而实际上每个项目的情况不一样,可以根据自身情况设置一些前置条件,这样就能扔掉不需要的“灵活性”,换取性能的提升。一般对于目前大型3D游戏来说,对画面的要求越来越高,性能瓶颈在GPU上。所以,如果针对项目对渲染管线进行深度定制,会获得非常足的性能油水。

所以项目开发中,不管使用Unity还是UE,首先需要根据项目情况优化渲染管线。对于Unity来说,建议务必使用SRP管线,因为整个管线可以深度定制。比如说内置的后期处理,从软件设计的角度来说,很灵活,但是会极大牺牲性能,例如去消NaN的操作是一个单独的pass,可以将这个整合进其它的pass,因为移动端上切换RT很浪费性能。UE因为开源,也可以深度定制渲染管线,周围朋友用UE做手游的都会定制开发,只是人力成本相对于Unity来说高很多。

三、算法

改进或者重写内置的算法。

作为通用商用引擎,引擎内置的算法只会考虑大多数需求,但每个项目的情况不一样,如果针对项目进行深度定制,性能无疑会优化的更好。

再说,不一定通用商用引擎的算法就一定是最好的,很多3A工作室内部的技术积累不一定比Unity和UE弱,他们放出的论文还是很值得参考的。例如EA的寒霜引擎,还有顽皮狗工作室,等等。

网上经常有人说,我把Unity的场景管理、SSAO、阴影等算法重新实现后,效果和性能更好了,就是这个原因。吐下槽,Unity的优势是工具链和框架,而不是具体的算法。

对于Unity来说,非常丰富的插件极大方便了游戏开发。但是以这么多年的经验来看,插件质量参差不齐,都需要进一步优化,目前还没看到例外。

突然想起2013年刚接手一个基于OGRE开发的自研引擎时发生的一个小故事,美术打开景深这个效果,编辑器的帧率跌了一半。后来发现,由于引擎开发团队整体经验严重不足,景深直接使用了一个开源的插件。一般来说,景深这个效果只需要一个后期处理就行,在当时的硬件上最多消耗1-3毫秒。但是这个插件用的方案是,将场景多渲染了一遍。真让人哭笑不得。

四、语言的最佳实践

开发语言的使用不当,也是性能问题的重灾区。还是举两个例子。

Unity的项目开发语言是C#,里面需要注意的点非常多(其实是正确的废话,哪个语言没有最佳性能实践呢?)。网上资料很多,最多的可能就是跟mono和垃圾自动回收机制相关的了。另外,这种编译时生成中间代码,运行时编译成机器码的语言,性能比C++这种直接编译成机器码的语言要低,所以Unity官方支持了Burst compiler这个功能,据说性能有点接近C++。当然,也有人说性能还不行(对于一个C++拥趸来说,我愿意相信)。如果某个算法实在太过“热点”,可以使用native plugin这个方案。例如插件使用C++写,利用DOD(面向数据编程)增加缓冲区命中。

这里夹带点私货,一直很不喜欢Unity这种不敢硬扛技术,总靠现成工具、算法、模块来绕的做法。为了方便跨平台开发,采用了C#。但是为了性能又支持了il2cpp,将C#编译结果生成C++代码,利用现有编译器编译成机器码。UE直接魔改了C++,支持了反射和垃圾回收机制。快速原型验证用蓝图,高性能开发用魔改的C++。技术实力雄厚,才能优雅到让对手难忘项背。

至于shader,也有很多语言层面的优化点。例如浮点数尽量使用低精度的。以前使用过cocos2d-x开发项目,引擎使用的着色语言是glsl,浮点数竟然有三种:lowp、mediump和highp,分别对应1、2、4个字节;Unity下对应的类型是fixed、half和float(CGPROGRAM和ENDCG之间的代码支持fixed;但HLSLPROGRAM和ENDHLSL之间不支持fixed)。使用不同精度,对性能的影响极大,尤其是低端手机。一般来说,颜色、归一化向量等都尽量用fixed或者half,位置和纹理坐标用float。当然这只是粗略的说法,写shader时心里应该一直有根弦:变量的值域有多大,精度低点对画面的影响多大。还有UNITY_BRANCH、UNITY_UNROLL等用法,也都会有明显的性能差别,网上资料很多,不赘述。

并且相同的代码,在不同的硬件上也有明显的性能差异。举个刚遇到过的一个例子,某个算法的纹理采样数量变多后,在Iphone 8 plus上的帧率还没有太大变化,但是到了华为Mate 30 pro这种高端机上,帧率却低的要死。猜测是mali的纹理缓存太小导致的,还没有去查资料验证,如果有朋友是内部员工,可以分享一下。

五、设备分级

如果优化到底了,最低目标硬件上还是不能流畅运行,那就要做减法了。可以将最低目标硬件以上的所有机型按照性能分级,一般会分3-5级,每个级别上都将算法进行一定的简化。常见的简化有:纹理分辨率、采样类型(例如是否开启各向异性采样)、渲染分辨率、阴影质量、水面反射质量,等等。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值