找回密码
 立即注册
查看: 950|回复: 19

游戏中的优化指的是什么?

[复制链接]
发表于 2021-1-14 10:24 | 显示全部楼层 |阅读模式
经常听到有人说xx游戏优化特别好 xx游戏优化特别渣 什么是优化 它是怎么实现的
发表于 2021-1-14 10:29 | 显示全部楼层
游戏软件的优化和一般软件是有一些区别。

游戏通常是软实时(soft real-time),就是说运行上有时间限制,但没有硬实时般严格。

先谈固定硬件的游戏平台,如游戏机和街机。在这些平台上,通常会设置固定的帧率目标,例如30 FPS(即每帧33.3毫秒)。游戏开发者希望在这个时间限制下,尽量提升游戏的品质,例如更精细的角色和场境、加入更多效果、提升人工智能水平等。优化的目的除了令游戏顺畅,也是提升游戏品质的必要条件之一。

对于PC或手机平台,因为硬件的性能有很大差异,优化就没有一个具体的目标,而是希望尽可能在大部分平台上都能做得最好(虽然PC游戏有几百FPS的情况,但实质上几乎不能增加流畅性)。

从玩家角度,我认为游戏的性能指标大概有这几方面:
    平均帧率
    流畅性(不要「卡」,专业地说就是少spikes)
    互动延迟(输入后至看到反应的时长)
    等待时间(读盘、写档、网络连接等)
    内存用量游戏体积
    网络流量(主要是移动平台)耗电量(主要是移动平台)

而在开发的角度来说,我认为优化方法可以分为无损和有损的。无损是指不影响品质,纯粹通过技术上的优化去提升整体性能。而有损是指通过简化、近似化去改善性能,例如简化着色器(shader)、要求美术降低某角色的三角形数目、要求关卡设计师减少一些NPC等。

优化前我们要先进行性能剖析(profiling),找出性能问题的核心,然后再看看有什么方法可以尝试。主要可分为算法上的和底层的优化方法。不详细说明,就举个例子吧。

例如,在二维弹幕射击游戏中,需把大量子弹与飞机做碰撞测试(相交测试)。如果有n颗子弹,m个可被击中的目标,蛮力法需要mn次测试。我们可以看情况,使用一些空间分割的算法,把子弹和目标分配到不同的空间范围里,只需对每个范围里的物体做测试。而在底层方面,我们可以考虑使用多线性、SIMD指令,并考虑到缓存一致性等方面去优化。

上述例子主要是在CPU上进行的游戏逻辑方面的优化,而许多游戏中也需要在CPU/GPU上对图形方面进行优化。在PC/手机平台上,因为瓶颈不固定,游戏开发者通常会尽力优化每一个部分。

----------
@孟德尔和 @Thinkraft提到了Quake的平方根倒数,我引用一篇以前写的文章,测试SSE指令和Quake的实现:

在1999年,id software公司发布了《雷神之锤III竞技场(Quake III Arena)》巨作,此第一身射击游戏有别于前作,以多人连綫游戏为主轴,得到空前的成功。

在2002、2003年间,网上出现一段关于该游戏中的源代码讨论,那段代码是这样的:

float Q_rsqrt( float number )  
{  
    long i;  
    float x2, y;  
    const float threehalfs = 1.5F;  
   
    x2 = number * 0.5F;  
    y = number;  
    i = *(long*)&y;                // evil floating point bit level hacking  
    i = 0x5f3759df - (i >> 1);            // what the fuck?  
    y = *(float*) &i;  
    y = y * (threehalfs - (x2 * y * y));  // 1st iteration  
//  y = y * (threehalfs - (x2 * y * y));  // 2nd iteration, this can be removed  
   
    return y;  
}

它是用于计算一个单精度浮点数的平方根倒数(reciprocal square root, 即1/sqrt(x))。平方根倒数在游戏中经常用到,例如把矢量归一化(normalize)时,就要计算n = v / sqrt(v  v)。

此段代码使用了牛顿法(Newton’s method)去提升精确度,但令人渍渍称奇的是它计算初始估值的这一句:
i = 0x5f3759df - ( i >> 1 );   

它利用了IEEE754浮点数的二进制表示来计算第一个近似值。此方法是谁发明的,魔术数字(magic number) 0x5f3759df 从何而来,暂时也没有确切的证据。但现在已找到比这更优的魔术数字[1]。

然而,本文想带出的是,虽然此方法如此神奇,在现今的机器上通常不是最理想的。在PC上,自1999年Intel推出的Pentium III,就已经加入了SSE指令集,当中的rsqrtss指令就是能够计算一个单精度浮点数的平方根倒数。此外,rsqrtps则能同时计算四个单精度浮点数的平方根倒数。

测试

我们可以写一个程序简单测试一下:
(略……)

结果及分析

使用VS2008 (缺省release配置),在i7 920 2.67Ghz上的結果:
   dummy      363.8ms  error= 83.70051795%  
standard     1997.4ms  error=  0.00000871%  
   quake      586.1ms  error=  0.17520049%  
quake2nd      970.1ms  error=  0.00046543%  
  
dummy_ss      109.4ms  error= 83.70051795%  
vsqrt_ss     1160.3ms  error=  0.00000871%  
rsqrt_ss      108.3ms  error=  0.03087627%  
rt2nd_ss      180.6ms  error=  0.00002188%  
  
dummy_ps       26.8ms  error= 83.70051795%  
vsqrt_ps      288.4ms  error=  0.00000871%  
rsqrt_ps       27.0ms  error=  0.03087627%  
rt2nd_ps       53.4ms  error=  0.00002188%
standard用了标准库的sqrt()函数,编译器使用传统FPU的运算计算开方和倒数。

quake和quake2nd的确比standard快,但quake的相對误差峰值约是千分之2,误差较大。quake2nd则用接近一倍的运算时间来改善精确度,相對误差峰值降至约百万分之5。

divsqrt_ss使用了SSE运算,准确程度与standard相同,而耗时仅比quake2nd慢一点点。实际上,如果在编译器开启/arch:SSE,standard也会使用SSE运算,产生的代码和divsqrt_ss相约,性能也差不多。

重点来了,rsqrt_ss的耗时只有quake的18%,而相對误差峰值也更好,约万分之3。仔细一看,发现它的耗时与dummy_ss相若。换句话说,因为使用了流水綫的潜伏时间,其数据吞吐量和至dummy_ss相若。

那么,再比较使用多一次牛顿迭代的版本。rsqrt2nd_ss的耗时也只有quake2nd的18%。而相對误差值也更好,去到千万分之2的水平。

最后,若真正运用了SIMD的并行运算能力,使用ps后缀的指令又会如何?在此测试中,可以看到性能比ss版本的提升了3至4倍。而rsqrt_ps也因流水綫达至dummy_ps的吞吐量。rsqrt_ps比quake版本快20倍以上,比standard版本快70倍以上。

总结

虽然quake里的平方根倒数算法是令人津津乐道的话题,但从应用来说,它并不一定是最好的选择。
……

参考

[1] Lomont, Chris. "Fast inverse square root." Technical Report, 2003.http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf
 楼主| 发表于 2021-1-14 10:37 | 显示全部楼层
更新完成。
@Milo Yip  milo老师说了整个优化的大框架,那我来补充一点实践方面的知识好了,聊一下天涯明月刀OL的优化,下文把这个游戏简称天刀。这是一个大型mmorpg,pc平台,客户端程序员数量在25人以上,其中引擎程序员大约在10人不到。
天刀是我从业以来优化最久,投入最大的项目,没有之一。以前的AAA游戏,我们通常会有一个两个senior的程序员,进行数个月的优化,而天刀的优化,断断续续做了接近3年,长期来看平均有两个以上的senior程序员投入,整个引擎和游戏方方面面都做了好几轮优化。
优化的流程始于profiling,我们用过各种各样的工具,cpu性能方面包括比较大路一点的vtune,自制profiling工具,已经数个小众一点的基于sampler的cpu监测工具。为了监测各种卡顿,windows performance toolkit是最常用的利器,虽然相对难学点,但这是最好的查找卡顿的工具了,是windows平台上性能优化必须要掌握的工具。gpu性能方面gpa,perfhud用的比较多,中后期gpuview也很常用。至于为什么要用这么多不同的工具,主要是每个工具各有擅长,往往能看见其他工具不容易发现的盲区。

来几个有趣的优化例子,看看天刀这里的优化幅度:
1,milo老师的tag math+visibility组件,理念在2015年已经不算先进,但令人惊讶的是组件的效率。参考的dice公司同样的技术,运行在ps3的spu,这样的计算密集型特性,经过milo的优化,运行在普通cpu上,毫无压力,在i3的入门级cpu上,依然只消耗低于2ms的cpu时间。这个技术甚至颠覆了传统场景管理技术。天刀这个大场景远视距的游戏,玩过的朋友可能知道,场景复杂度和可视距离,都是国内少见的,即使和国外游戏相比,也只有逊色于just cause,farcry等不多的游戏,但是天刀里面的场景管理,没有用4叉树或者8叉树,直接扔进底层visibility组件。。。当然visibility组件里面还是有一些简单的类似管理,把这一层管理放到底层之后,场景管理和移动物体变得无比方便,对引擎层完全透明了。visibilty组件如此高效,以致阴影、树木、反射,全部可以由它来裁剪,简洁优雅。
在天刀早期做完大地形后,粗粗用visibility裁剪一下,帧数直接翻倍。后期主城场景密密麻麻,用到了其中的遮挡裁剪,看不见的就不画,又没有gpu的oclussion culling的延迟。

2,植被系统的优化。严格来说这不算优化,是一个特性。天刀植被用了speedtree,相当出色的中间件,基本一个美术就能把整个游戏需要的树全部建模出来了。于是我们就在考虑是不是可以在场景里面种满树,因为这个中间件也有类似的demo。但是结果并不令人满意,原生的技术在效率和质量上都不 够好。
开发同事在speedtree的基础上做了很多尝试和优化,效果被制作人几次拍死,最后终于达到了满意的质量,也就有了大家看见的漫山遍野得植被。远处树木本质上使用speedtree的billboard,但是在normal生成、树木根部和地形的融合等多方面做了很多尝试,对于树木建模,是多一些polygon,好降低fillrate(因为pre z可以裁剪掉后面的像素),还是用大一点的面,可以减少polygon,也做了细致的美术微调,找到了平衡。前后整个特性应该做了超过半年,初始效果做出来以后,在场景序列化、裁剪等方面又要做深度整合,而不能简单充用原先speedtree的整合方式。在远处使用billboard的树木,同事很创新的想出密度倍增的技巧,一下子就出现了震撼的全景植被效果。
天刀的植被目前来说,效果和效率应该是是顶尖的。我们在2014年给unreal引擎创始人tim sweeney展示的时候,他也表示这是他见过的最好的植被表现,能得到偶像君的肯定,团队也非常受鼓舞。更多细节我们今年下半年会有一个gdcc session,同事应该会介绍更多。
这个工作有一点值得注意,真正好的优化,是程序、美术等多团队共同努力的结果。在效果和效率上很多团队说起优化,就是程序定个指标,扔给美术去做,程序就不管了。这样做下去,很容易出现美术用力缩贴图减模型,效果一塌糊涂,帧数倒是没提高多少。真正好的优化,必须是多方一起坐下来,共同分析问题,一起解决,即使是纯美术的改动,也需要程序帮助定位问题,这样才更有针对性,才能把优化带来的质量损失降到最低。

3,卡顿优化,shader cache收集系统
天刀一测二测得到了较好的性能方面反馈,一方面的确优化的还可以,另一方面由于我们花了非常多的精力在防卡顿上面,导致游戏里面的卡顿相对较少,有玩家反映帧数只有20左右,但也能顺利玩下来。由此可见,片面追求高帧数意义不大,去掉性能上的spike,会给玩家更好的体验。
卡顿原因多种多样,单独就可以是一个很大的话题。我分几个单独案例来说。
一个情况是shader cache,天刀使用了uber shader的机制,根据场景和人物材质不同,可以组合出多种多样的shader,开发早期会在构建版本的时候穷举所有参数组合把shader全部编译出来,存在版本里面。很快这个方式就没法用了,shader参数组合爆炸了,于是就用动态生成机制,根据参数组合去取shader,如果之前没有编译过就同步编译,然后把编译后的shader保存到cache文件,以后要用就可以直接load。之所以这里没有在后台用别的线程编译,主要原因还是不希望编译的过程中模型不显示造成显示上的瑕疵。但是这样做的话,如果遇到缺失shader,就会有几百ms的卡顿了。
开发过程中这个同步编译当然无妨,但是见玩家的时候可不能这样,事实上三测一开始就因为bug,cache没处理好导致卡顿乱七八糟,被玩家喷死了。我们需要做的就是给玩家的版本里面需要把所有的shader组合都编译出来。
07年做xbox360游戏的时候也遇到过一样的问题,当时的团队有足够的测试资源,我们的方案是把所有用到过的shader参数存在文本文件,每天测试人员会把所有的参数发给我,我运行一个脚本去掉重复,整合所有的shader参数,然后第二天构建版本的时候就可以用收集的参数来预先生成所有的shader了。
但这次天刀项目组规模比较大,用类似的方法收集比较累。
我写了个简单的小server,测试版本都会上传所有的shader参数组合到这个小server,这个server会定期合并参数,输出后就可以上传到版本里面,下一个版本就可以构建这些shader了。
通过这个方法,我们在整个团队不受到干扰的情况下,收集了所有的shader参数组合。同时如果一个shader太久没有被用掉,也会被server去掉,这样如果因为更新程序导致shader改变,那些废旧的shader会在一段时间以后被慢慢淘汰,避免了shader的无止境增加。

4,卡顿优化,跨进程卡顿
有一阵子上线以后玩家表示卡得很,但只要删除cross组件(腾讯内部的一个通用组件),就会流畅很多。听到这个迷信的说法,大家都不以为然,自己测试一下,发现也没有重现。
可是过了一阵子,发现坊间这个传说越传越广,进一步测试,发现在主程或者群战的时候,的确有可能会有很多没发现的卡顿,这些都是我们开发版里面不能重现的。
开发同学用Windows performance toolkit查了很久,结论非常令人崩溃。
起源是Cross组件使用了内部的另一个登录组件,这个组件也被很多其他腾讯产品使用。每一帧cross更新的时候,这个登录组件都会去读一个系统的锁。如果在游戏内存占用量非常高的时候,这个系统锁的变量有可能被page out,于是引起了一个page fault,所以系统就会卡顿一下。我们内部的电脑都是SSD,所以page in也一般不是很慢,理论上也不应该卡啊。继续追查,发现出问题的机器上往往装了微云,微云经常读写硬盘,在多台电脑件同步数据。如果正好page in发生在读写数据的时候,就会卡了。换句话说,我们内部观察到的现象,是腾讯的微云读写一个文件,正好和游戏中那个系统级锁的page in过程重叠了,所以会卡。外部玩家如果用了其他腾讯服务,或者硬盘比较慢,也可能引起一样的问题。
解决方案就比较简单,把这块东西的update全扔到另一个线程就好了。

就先讲四个案例吧。可以看见在这几个案例里面,查找问题、解决思路都各不相同,但共同特点都是在程序端做了非常多细致的工作,也有一些非常有创意的解决方法。在我看来,优化绝不仅仅是设一个budget,对美术资源的大小、polygon数量等等设好限制,然后push他们去减贴图简化模型。程序作为性能的主导者,有非常大的主动性,如果能有很多更有创意的实现方式,可以大大简化美术的工作,也把性能和效果推到更极限。
发表于 2021-1-14 10:40 | 显示全部楼层
只答前半部分「什么是优化」。

我个人的看法:广义上, 优化是「为了达成相同目标,寻求并采用消耗更少资源的办法」的过程,或其结果。

不知道题主小时候读没读过高斯那个很流行的传说,老师让计算1+2+3+...+99+100,比起全部一个个相加,他发现1+100=2+99=3+98=...=50+51=101,然后直接101*50得出了答案5050。利用等差数列的求和公式使计算更加简便快捷,这就是一种算法优化。

那么把上面斜体部分代入到游戏这个话题中,不难理解优化是怎么一回事了:

通过特别的软件编程技巧……
实现相同的画面表现效果、流畅度,对硬件机能的需求更低、更平民化
或者
在相同机能的平台上,实现更好的画面表现效果、流畅度

如今玩家们口头说的优化,一般是针对移植作品,也就是至少有两个平台对比。人们会将游戏在原平台的画面表现和平台机能作为基线,去衡量移植版,有时也会以同平台的不同游戏作对比进一步论证。总之,一个游戏在一个平台上的优化好坏,大体可以用「表现效果/环境需求」的比值来衡量,或者说白了就是画面好不好看、跑起来卡不卡。

@孟德尔 提到的卡马克平方根倒数算法是一个细节优化的例子,就是采用了特殊处理而非标准库函数来提升运行速度,无数个这样的细节堆砌起来,造成的效果可能甚至不是不太卡和有点卡的区别,而是有的玩和没的玩的区别——那个时候你甚至想不到「优化」这个词。卡马克之所以神,就是因为他屡次化不可能为可能。他在PC机上先后实现了卷轴游戏、带贴图的伪3DFPS、真3DFPS、真实光源……这每一个进步背后都隐藏着优化,只是那个时代ID的光芒掩盖了一切,其领先业界的幅度之大让大家只能看到质变而已,可以说,在20世纪时,玩家们还没意识到优化一说。

——————————

下面不说怎么实现优化(可以参见 @Milo Yip 的回答),而是谈谈大家是怎么意识到需要优化的,题主为何产生这样的问题——其实那些嘴上说着优化好优化渣的人未必比题主更懂。

回过头来,我们什么时候开始感到「优化」的概念呢?我想,应该是PS2时代。

PS和SS时代,主机阵营相当分明,即使跨平台游戏的表现有差异,多半也被归功于SS的扩展卡。同期主机游戏和PC游戏的互相移植相当有限,也就是一些大作,例如PC版FF8、PC版MGS、SS版仙剑之类。
进入PS2时代后,微软参战,加之卡社、科社为代表的公司进一步婊化,游戏跨平台化变得越来越流行。由于电视游戏主机的硬件相对固定,为了最大限度发挥机能,提高3D画面表现,开发过程中需要针对主机特性进行大量特殊处理,也就是所谓优化。而移植时限于成本,往往无法做到这么彻底,因此即使硬件性能相当,原平台版的表现通常还是会比移植版要强一些,这个差距可能体现在分辨率、抗锯齿、贴图精度、多边形数量、运行帧率等各个方面。

到了PS3/X360时代,PC移植兴旺后,「优化不足」的问题更加明显,抱怨也更多,其实主要是国内玩家对移植版抱有不应有的期待,原因大概有以下几点:

    主机的特点是更新周期长,性能至少要照顾未来5年内的需求,硬件上必须采用推出当时中高端PC的配置;而价格上,为了迅速推广抢占市场,都是赔着本卖的——反正主要利润模式是软件抽税。一来一去,也就是说次世代主机推出的一两年之内,性能上是比同等价位的PC强不少的。买一台3000块的主机可以爽最新的游戏,但3000块的PC也就是欢乐斗地主水平。
    PC显示器分辨率碾压同时代电视,主机的设计输出分辨率其实是低于流行的PC游戏的。例如PS2的标准分辨率是480i(640*480),当时主流的17寸彩显怎么也是1024*768的。PS3的大部分游戏都是720p输出,每秒30帧;而两年之后的08年,1080p显示器已成主流。同一款游戏若需要达到1080p点对点每秒60帧的PC玩家习惯需求,分辨率上就扛了2.25倍的像素数量,帧率又翻了一倍,相当于需要的性能是主机版的4.5倍,这还没算抗锯齿的消耗。平民机玩移植游戏卡顿也是正常的。
    由于PC并没有主机难以扩展升级性能的问题,厂商在将主机游戏移植到PC时也不会太介意硬件需求——反正你现在跑不起来过两年新显卡出来了内存便宜了就能跑起来了嘛。所以很多移植游戏的推荐配置都是变态级的。比如以「优化差」臭名昭著的GTA4,不光吃显卡吃的厉害(1G以下显存基本无法游戏),对CPU的要求也极其苛刻。
    (*本条慎读)PC玩家和主机玩家的群体重合度并不高,想想和主机原版发售日期比起来,PC移植往往晚几个月,有爱的早通关全成就了。其实等PC移植版的人有相当一部分是没钱买主机专等盗版的lamer(这逻辑很奇怪吧?明明差不多性能的PC买一台主机加十几个正版游戏都够了),素质也比较有限。你可以想象一下抠脚猥琐男们,盼盼盼,盼来个传说中的大作终于出了windows版,挂上迅雷拖两天装上一跑卡得像幻灯,上网发帖嗷嗷简直是本能啊~

补一下,还是拿被骂优化烂最凶的GTA4说,这游戏大陆根本买不到合法正版。你上amazon、steam去买下载版,没有美国信用卡账单地址人家根本都不让你支付的。所以,吐槽归吐槽,但有几人真有资格抱怨优化问题?
发表于 2021-1-14 10:48 | 显示全部楼层
说起游戏的优化,在游戏开发中经常分为这几步:
    首先要确定游戏中经常会出现哪些问题 - Profile
    然后确定在哪些方向进行性能优化 - Analyze
    最后再尽可能将问题逐个解决 - Solve
游戏开发中一定是先做工具,进行Profile,再进行优化,所以,说优化就不得不再扯一下Profile

常见的工具有一些是引擎和IDE自带的,比如Unity自带的Profiler,就包含了CPU,GPU,Memory等等各式各样的性能分析工具,其他的比如GPA,Xcode Instrument和Visual Studio,Intel自带的内存管理工具在必要的时候也使需要去学习和使用的。

另外一些工具,就需要根据游戏的需求去编写了,比如一键关闭所有特效,一键更改分辨率等等,一键设置场上NPC数量,简单的游戏如啪啪三国是做成快捷键开启Profile功能的,更为复杂的游戏如神秘海域则是通过游戏内控制台来进行更为细致的Profie。

接着,我们再来说说游戏优化中主要的四个考虑方向:
1、CPU
引发的问题:
    由于短时间内的计算量太大,导致画面流畅性降低,俗称跳帧
    发热严重,耗电量高
常见的优化手段:
    将计算分到多个逻辑帧中进行计算,避免短时间内的性能超过负荷,俗称“分帧”(time-slice)。将可以缓存的数据尽可能的缓存起来,避免重复计算和重复分配内存,常见的示例为“内存池”。使用合理的算法和数据结构,比如:冒泡排序和直接插入排序在整体数组比较有序的情况下效率大大好于快速排序。把快排替换成是优化程序排序效率的一个常见的思路。
2、GPU
引发的问题:
    发热严重,耗电量高FPS降低
常见的优化手段:
    优化美术资源,比如合理规划图集,约定好模型的最大三角形面数,制定合理的粒子效果规范。这个可以说是游戏优化中最重要的一个,因此,技术美术在游戏开发中作用巨大。简化或者优化着色器(shader)使用Batching,尽量减少DrawCall使用平台推荐的压缩格式,比如安卓平台的ETC1和IOS平台的PVRTC
3、IO和网络
引发的问题:
    网络延迟甚至掉线加载资源导致的跳帧加载时间过长
常见的优化手段:
    使用独立的线程进行加载,有些引擎如Unity中还能利用协程减少网络包里面的冗余数据合并小包,减少请求数据的次数分帧对回包进行处理限制一定时间内的发包频率
4、内存
引发的问题:
    闪退和卡死,比如安卓的Low Memory Killer会在低内存情况下杀掉内存占用过大的程序。
常见的优化手段
    动态加载和卸载资源,比如在游戏内的时候,我们可以把游戏外的一些UI图集卸载掉。降低资源质量或屏幕分辨率,这是有损优化,一般作为最后的手段

其实这四个方面的优化总是相互制衡的,你把一个方面的优化做好了,另一个方面的问题又会出现了,比如,我们如果使用动态加载和卸载资源,这就虽然减少了内存占用量,会在IO上造成加载时间延长的问题。

所以,我们在做游戏优化的时候,不能太追求完美,刚刚好就是真的好(Good Enough Is Fine)。最终使得以上这四个方面能达到均衡即可,切忌在某一方面优化过头,又引发其他方面的问题,此消彼长的情况下,有时反而不如不做优化。
发表于 2021-1-14 10:56 | 显示全部楼层
  高票答案已经解答得非常专业了,这里就从玩家的角度出发,举几个普通人就能观察的到的游戏优化手段吧。
  不渲染大地图远处/遮挡的事物
  现在开放世界式的游戏越来越多,连在线性叙事游戏耕耘多年的日本厂商,都开始尝试制作开放世界游戏,例如最终幻想15就硬生生把前几关做成了开放世界。开放世界游戏中,大地图是必不可少的元素,但大地图就意味着模型数量暴增,如何将大地图流畅地呈现到玩家面前?于是就得在视野外的模型做手脚了。


大地图对硬件负荷很大,要流畅的画面,远景和遮挡事物会被缩掉
  尽管开放世界的地图很大、视野开阔,但玩家总有看不见的地方,或者看得不太清晰的地方,例如背后,例如被遮挡住的建筑,例如远处等等。于是,游戏就会不渲染或者只用低画质来渲染这些模型,待到玩家移动到这些地方的时候,才使用高画质来进行渲染。
  玩家在很多游戏中,其实都可以观察到这些现象:放眼望去远处明明是没有草的,跑过去后草突然就从身前冒了出来;某座山刚刚看到的时候就像一个圆滑的土堆,但向它靠近的话不一会儿就变成了棱角分明的石头。这些现象被部分玩家称作“炸山”,带有大地图的游戏想要流畅运行,这种优化技巧基本是必不可少的。为什么《绝地求生:大逃杀》会卡?为了竞技的公平性,这游戏不能大幅减少远处的草木、房子渲染,所以需要渲染的地图大、事物多,对配置的要求自然也就水涨船高了。
  利用崩落场景删地图
  除了开放世界式游戏,线性叙事的游戏地图也比之前进化了不少。地图不仅更大,而且更加精细,像顽皮狗最新出品的《神秘海域4》,一些场景已经接近照片级,令人难分真假。一般来说,如此精细的画面是很耗资源的,但偏偏这游戏是PS4独占,PS4的机能远不及现在的顶级PC,而《神秘海域4》还非常流畅,这是怎么做到的呢?
《神秘海域4》的画面令人很难相信是在PS4这样的机能下实现的
  这游戏的一大优化手段,就在于不断利用崩落场景删地图。例如,当玩家爬山爬了一段后,背后会发生悬崖崩落之类的情节,紧张刺激的同时,随着崩落,旧的地图也被删掉了,游戏自然也不再需要渲染太大的场景,硬件压力大大减少。
《神海4》的游戏流程伴随着很多场景崩落,崩落的同时删掉了无用地图,减轻硬件负担
  其实这种手段在顽皮狗出品的游戏中很常见,例如《The Last of Us》当中,也经常走一段路,后面的建筑就崩塌掉,玩家没法再走回头路。这种和关卡设计紧密结合的优化手段,还是非常行之有效的。不过这种优化方式仅适用于线性游戏,开放世界式的游戏很难使用。
  采用动态分辨率
  更高的分辨率带来了更细腻的画面,同时也带来了更大的运算压力。现在越来越多的游戏把分辨率做到了4K乃至8K,这对于机器来说,可就很难吃得消了。但玩家偏偏又喜欢享受高分辨率带来的快感,怎么办?动态分辨率应运而生。
  顾名思义,动态分辨率就是会变动的分辨率,当游戏遇到复杂场景、特效而压力山大的时候,就会自动降低分辨率,以牺牲分辨率为代价,换取流畅度。动态分辨率的使用是有技巧的,你总不能让玩家跑一会儿人突然变成了马赛克,再走两步突然又高清得连毛都看得一清二楚。通常来说,只有在动态、特效复杂等场面下,玩家不太留神建模的时候,动态分辨率才会发挥作用,带给玩家更流畅的游戏体验。
像放无双这种特效比较多的场景,某些游戏机就会动态降低分辨率,PSV的玩家应该深有体会
  实际上,在PC中动态分辨率这手段使用得并不算频繁,在游戏机平台上倒比较常见。在PC上游戏卡了厂商可以赖你配置不够高;但在游戏机上游戏都变成幻灯片,这游戏“渣优化”的帽子可就脱不掉了。同时,游戏机一般也不能设置游戏渲染的分辨率,游戏用什么分辨率,全凭厂商的策略,于是动态分辨率就成为了常见的优化手段。
  利用过场时间读图
  现在的游戏体积越来越多,读图的时间也越来越长,如何让玩家减少读图的等待,也很考验游戏优化的功力。现在最常见的手段,或许就是在过场时读图,等过场播完了,游戏也就已经载入完毕,玩家并不会觉得等读图等了很久。
《女神异闻录5》带有大量非常炫酷的过场动画,其实过场时就已经在读图,很巧妙的设计
  什么是游戏的过场?例如游戏过程中播放的CG、战斗结算动画等等,就是典型的过场。现在很多游戏都是用了电影式叙事,打一段游戏播一段片,在播片时读图,的确可以提升游戏体验。
  总结
  上文提到的只是一些玩家留心就可以观察得到的优化手段,希望游戏厂商都能够更加注重玩家的实际体验,在用“显卡杀手”来奠定画质领头羊地位的同时,也不要忘记并非所有玩家都会配备四路泰坦,多做优化,为最广大的玩家提供流畅而精美的画质,才能赢得真正的好口碑。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-1-14 10:57 | 显示全部楼层
程序方面:
内存优化
渲染效率优化(包含综合帧率)
机型适配优化
CPU利用率优化
网络流量优化
资源大小优化
耗电量优化
I/O效率优化
美术方面:
配合渲染(面数,材质球,特效制作效率...)
配合适配 (UI的适配性,字体的适配....)
配合内存及CPU(贴图的UV排布,材质大小及通道复用)
策划方面:
不产生新开发需求的各个模块调优
发表于 2021-1-14 11:01 | 显示全部楼层
优化简单说就是尽量减少性能消耗的方法。
本人不懂游戏底层的优化,那是程序员的事情,代码水平高,用更少的计算节省了更多性能,那也是优化。
我说一些游戏引擎里常见的优化功能,都是大家耳熟能详的。
不管是底层的还是表层的优化,除了性能本身还有可提升的情况,另一种情况则是牺牲一部分效果来节省性能。引擎经过长时间摸索,逐渐发展出一套优化的思路:与玩家近距离交互的重要内容采取较精细的计算,离玩家较远的次要内容采取较粗略的计算(牺牲一些效果),暂时不需要的内容则临时让它消失。
以下大部分优化功能都是这个思路。
LOD
在游戏中,很多模型会在远离玩家视点后逐渐进行简化(替换成精度更低的LOD模型),以减少性能的消耗。比如一个游戏角色,一般会有3个LOD替身,一个比一个长得“简陋”,最后一个LOD就像一个方块人。有些游戏没处理好切换LOD的时机,会让玩家看到远处房子变盒子的情况。但LOD也是无法彻底避免的(比如远处的树必须替换成纸片,不然机器根本拖不起),只是尽量处理得巧妙一些,减少生硬感。


延迟光照
现在的游戏已经是实时光照,游戏的实时阴影就成了耗能大户,于是阴影也有了优化的方法:离玩家较远的阴影不会更新计算(不必每帧都去计算它们),只有离玩家较近区域的阴影才实时更新。但大量采用这种东西,有时会让玩家看到一些奇怪的现象,比如远处的一个东西在动,但它的影子似乎还在原地(它的阴影没有及时更新)。另外,反正你也看不清远处的细节,所以计算方式也进行了简化,将3D空间的精确算法换成基于屏幕深度的“偷懒”算法,这两种东西就类似真3D电影(用两台摄像机去拍)和2D后期转3D的电影(只用一台摄像机拍,然后后期制作深度信息变成3D,细节较差)。引擎里还有一些东西也用了延迟技术,比如灯光、反射等这些,它们进行了类似的“偷懒”处理,可以节省很多性能。


视距裁剪
这个功能是给前两个功能“补刀”,前两者是根据一定距离进行简化或“偷懒”,这个功能则在对象离玩家非常远后,干脆删除掉这些内容。为了避免被玩家注意到远处的对象突然消失,通常会使用一些障眼法:比如很远的地方一般会有雾效,用浓雾来掩盖对象的失踪。另外,视距裁剪可以裁剪整个场景,也可以裁剪特定的过于消耗性能的对象,玩家应该经常注意到,只在玩家近处出现的草丛,这东西虽小但消耗巨大,如果不控制其数量,将一望无际的草原同时显示出来,它们将耗完你所有机能。当然也有缓解草丛消失的方法,设计者会在地形的染色层上绘制一个和草丛相近的颜色,可以过渡一下颜色的差异(如果草丛是在绿色的地面上消失,玩家就不会感觉那么唐突)。


遮挡渲染
这个功能和视距裁剪目的相同,都是让不需要的东西消失。它可以裁剪掉玩家看不见的对象(即使离玩家很近)。比如玩家在屋门外,屋里的对象就没有必要被渲染出来。一些关卡设计为了优化性能,故意设计一些弯曲的巷道来阻挡玩家的视线,以分割多个游戏区域。


基于距离的其它优化技术
除了上述的,还有网格细分程度、阴影质量、纹理分辨率、抗锯齿、AO等,它们都会根据距离进行简化或者被删除。典型的有地形(现在的引擎几乎都有地形系统),近处的地形网格相对精细(并使用一个高精度的纹理层),远处的逐渐粗糙(并切换成一个低精度的染色层)。在一个有跳伞元素的游戏中你很容易感受前面说的内容:在高空降落过程中俯视地面,地面会从粗糙(并且颜色单调)逐渐变得精细,有的地方凭空变出一个盒子,盒子又变成房子,有的地方变出纸片……。另一个是大家经常会感觉到地面前方有个奇怪的分割线,其实也是系统在根据不同距离进行纹理和抗锯齿的降级处理。另外,一定距离后,阴影、环境遮蔽这些渲染细节都会消失。


反射与折射的优化
现在的游戏已经开始大胆的使用反射和折射,比如水面的倒影和水底的折射、玻璃或镜子上的反射、光滑地面上的倒影,玩过3dsmax的都知道这些是最消耗性能的东西。对于这些东西,游戏引擎采用了很多优化方法。首先,视觉要求高的对象采用真反射,要求低的就使用假反射。比如玩家通常对水面的审美要求很高,所以游戏的水面一般会用真反射(也就是大家经常听说的光线跟踪算法),能同时模拟较为真实的反射和折射。镜子效果通常也是真反射,而其它的大多对象都可以使用假反射(也就是环境球,这东西也发展出一套抠门的灯光技术,叫做基于图像的光照),比如地面的倒影,细心的玩家有时会注意到反射与实体对不上的情况,这就是假反射,它是提前将场景渲染成一个球形图,用来代替反射对象(有时在水面上用这种方法也能得到理想效果)。其次,反射的时候,只反射主要的对象,比如水面的倒影,你仔细看,它并没有老老实实的反映所有实景,一般它只反映树木、岸边的大石头这些大件的主要对象,而花花草草这些小细节就被省略了,而且倒影是没有阴影、粒子、抗锯齿这些细节的,同时控制了其更新的帧数,这些都节省了很多性能。


代理
代理你可以简单理解为替身。比如一棵树的阴影代理,如果老老实实计算所有重叠树叶的阴影,这对设计者来说就是巨大的浪费,你可以额外做一个交叉的纸片,用它的阴影来代替原来的阴影(在特定的投影角度下,两者的结果差不多)。另一种是物理代理,如果一个网格对象过于复杂(顶点越多),物理计算的消耗也会越大,所以通常游戏中的每个交互对象都有一个很简单的网格替身,用来代替自己去做物理计算(碰撞、接受打击等)。比如一个茶壶(面数1000),它的物理代通常就是一个简单的立方体(或者面数再多一些)。物理代理有时过于简陋也会带来一些奇怪的现象,比如你朝着栅栏的间隙开枪,却发现弹孔留在了间隙中间,仿佛有一道隐形的墙,这就是设计者把物理代理做成了一个整体。


池(Pool)
这个功能对现在的沙盒游戏比较重要,游戏场景通常特别大,所以无法一次性加载整个关卡的所有数据,只能在需要的时候才加载相关数据,不需要的时候还要去卸载它们。但在加载和卸载数据的时候也要占用很多内存,极易出现堵车(导致卡顿)的情况。总之,就有了这么一个缓冲的方法:在近段时间内需要反复出现的东西,提前预加载(悄悄的准备好),存放到一个叫池的地方,当需要它的时候立即就能取出来,以避免卡顿。所以它经常用来存放近段时间内需要重复刷新的敌人。


实例化
实例化是减少大量重复对象的消耗的一种机制,是所有软件都应该有的基本功能,这本没什么好说的,只是在设计上,游戏里需要大量重复的道具都要故意设计成一种通用的状态,以便大量重复或进行随机组合。比如大量重复的配景树,必须做成较规则、对称,也就是每个角度看上去都差不多、没有明显个性的那种。


上述功能几乎都是现在引擎通用的东西,还有一些设计层面上的优化,说两个典型的:


气泡式关卡
即使是大型沙盒(开放式)关卡,也会一定程度采用气泡式设计,即关卡分布在不同地方,每个关卡完不可以再回头。比如你做完一个任务,结尾通常要找个理由把任务地点给毁了(把地儿给炸了),总之不能再回去,这样该任务点的数据就可以被清除,以节省资源。


隔离区域
将关卡场景设计成多个隔离的区域,当玩家在一个区域时,可以不用加载其它的区域的数据。比如你在一个建筑群中活动,另一个建筑群就不会加载,而在两个区域过渡的地方,通常会设计一条狭长的通道,利用玩家在这条通道走路的时间,悄悄预加载下一个区域(类似于人工读条)。
气泡式关卡和隔离区域是两个相辅相成的东西,是关卡设计里经常要考虑的东西。


另外,其实在策划阶段就会考虑优化,做事前要先算账是通用的道理。每个游戏在最初期会有一个性能预算,用来统计你游戏里需要多少东西以及它们会消耗多少性能,比如静态对象、角色、场景道具、植被(大头)等,它们应该使用多少面数、纹理尺寸、LOD的标准等。你的目标用户是什么配置,你的模型、纹理细节应该做哪种精度他们的破机器才能拖,你不只要先算账,还要实际进行测试,前期是游戏公司自己测(现在的游戏引擎几乎都集成了一个很重要的性能剖析系统,用来剖析游戏运行时消耗的内存、显存、调用对象次数等等信息),后期还要请外部的玩家来测,优化和解决BUG有时是一种工作。


说了这么多,这也是为什么通常是沙盒游戏的优化差,你很少听说小关卡游戏的优化差,小关卡没太多性能负担,也就没这么多事情。有些游戏的优化做不好,是因为做优化比较耗人工和时间,比如前面说的LOD,这意味着一个模型,通常要额外做2或3个不同精度的LOD模型(如果是一个游戏角色,除了模型,你还有绑定骨架的工作,事情就得成倍增加),而优化是玩家体验后才能感觉到的东西,如果厂商急功近利就会选择先偷工期,卖出去了再来补。也有大环境的原因,现在是沙盒游戏的开荒时期,开放式地图的经验比较少,很多大公司做游戏第1代时也出现了优化差的情况,之后才慢慢开始好转。还有一种就是缺乏完整的制作经验,没有在策划阶段做好性能预算,只想着用高精度、表面的东西去博眼球,最后屁大个关卡也卡,新生代独立游戏人经常出现这种情况,因为现在这一批做(3D)游戏的人,几乎都是从新一代3A级游戏引擎(比如虚幻3、4)进门,新技术减轻了游戏制作的难度,使很多初学者喜欢滥用一些耗能的技术,比如实时光照、曲面细分、光线跟踪、全局光、毛发、布料,这些东西都是耗能大户,稍微超标即卡。
发表于 2021-1-14 11:07 | 显示全部楼层
既然说游戏优化,那么聊聊某些容易被人忽视的因素吧。

程序角度的优化:

1、项目开发周期的分析及预估(版本计划)
第一个提是因为所有的优化方案都是基于整个项目基础上的,所有的突发情况都应该是可以被预估的。所有的冗余都是由于计划不完整造成的。
2、模块整合优化
项目肯定有重要功能以及辅助功能,将几个重要功能整合作为核心功能优先处理是相当有必要的。如账号登录以及商城充值。
3、各个功能模块功能点的梳理以及后续拓展的分析
如果模块优化是粗放式的,那么这个就属于细节了。分析各个模块的功能点有利于程序逻辑的实现以及项目的预估,并且使后续功能的拓展变得更加方便。

用户方面的优化:

1、用户行为分析需求整合——分析后提交给程序以安排时间设置埋点。
2、后台配置优化整合——添加各种查询功能,并设置权限。为策划、运营、QA、客服提供支持。
3、基于用户体验的交互设计优化——主要利用策划的主观感性设计、以及用户行为分析等客观手段作为参考。

美术源源方面的优化:

1、美术资源的有效利用——尽量不使用整张图片、重复利用小块拼接方式拼图、使用程序实现动态特效等等。手机游戏怎样压缩美术资源?
2、美术资源的有效管理——保证每个版本的资源都是明确不冗余的、不同版本的资源是可区分的、查询修改是方便的。

QA方面的优化:

1、测试流程的规范化管理。——能够随时掌握项目当前的所有功能点的测试内容、测试方法、测试通过标准。
2、用户体验的分析报告。——有利于策划在新版本开发时的功能模块优化。

还有很多其他方面的优化、比如用户可见的(节奏感、流畅度、动态特效表现)以及不可见的(游戏底层、数据库存储过程、表结构的优化、机器人AI优化)等等。

虽然回复经常没有人点赞,但是我还是会坚持每一条认真回复,只要能给予各位以些许启发就满足了。
发表于 2021-1-14 11:11 | 显示全部楼层
优化在计算机中覆盖的面太广了,这种没有具体指向的问题,只会引来越来越多的民科答案。

顺便,题主听到的这些话肯定都是门外汉说出来的。

ps,图形方面的优化期待 @Milo Yip 前辈的答案。
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-26 07:36 , Processed in 0.097458 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表