如果游戏的渲染瓶颈来自于GPU
首要任务就是找出造成GPU瓶颈的因素所在,通常GPU的性能受到像素分辨率的影响,特别是在移动客户端的游戏,但是内存带宽和顶点计算的影响也需要注意。这些因素的影响都需要实时的测试和定位。
像素分辨率
像素分辨率是指GPU每秒可以渲染的像素个数,如果游戏受到像素分辨率的影响,则意味着游戏每帧描绘的像素点个数超过了GPU可以处理的极限。
检测游戏是否收到像素分辨率的影响可以通过以下方式:
. 分析游戏,注意GPU的运行时间;
. 在unity的Player Settings中设置降低分辨率
. 这时候运行分析游戏,如果游戏的性能得到提升,则有可能是像素分辨率造成性能问题。
下面有一些方法来解决像素分辨率造成的问题:
. shader中的片元着色器主要用来告诉GPU如何绘制每个片元的像素,所以如果片元着色器的执行效率不高,则会造成游戏性能的降低。复杂的片元着色器代码通常是造成分辨率问题的原因。
— 如果我们采用内置的shader,在视觉特效上最好采用最简单和最优化的shader。例如,the mobile shaders that ship with unity就是高度优化的shader,我们可以通过使用他们来测试是否对游戏的性能有影响同时并不影响游戏的表现。这些shaders是专为手机平台而设计,但是在其他平台上也可以使用。特别在并不影响游戏的表现效果的情况下,使用这些shader有极大的优势。
— 如果游戏中的物体使用Standard Shader,那么需要知道在unity中,这些shader的编译依赖于当前的材质设置。只有当前被使用的特性才会被编译。那么可以通过移除地图细节等特征来极大的提高片元着色器的性能。此外,如果在游戏中进行这样的操作测试,需要测试该操作是否会影响游戏的整体表现品质。
— 如果游戏采用定制的shader,则我们需要尽可能的优化这类shader。shader的优化是极其复杂的,这儿和这儿的Shader optimization部分都给出了一些优化建议。
. Overdraw是指相同的像素被多次渲染,如果某些Objects在其他objects之上,则会将起多次渲染造成像素问题。要理解overdraw,则需要了解unity中的渲染顺序设置。每个物体的渲染顺序是由其上的shader决定的,特别是shader中的render queue。Unity极其依赖渲染顺序的设置,详见此处。此外,在物体渲染之前,不同的render queue中物体会进行不同的排序。例如,在Unity中,如果render queue设置为Geometry,则其排序为从前到后渲染。如果render queue设置为Transparent,则其渲染排序为从后到前,从后到前的渲染顺序会造成渲染的极大化。overdraw是一个复杂的问题,没有一个合适的方法来解决这个问题,但是减少unity不能自动排序的重叠的物体的数量是一种好的途径。解决这类问题最好在unity的scene视图下,此处可以设置Draw Mode模式下的场景视图,从而查找如何减少这类物体。通常造成overdraw的原因是透明材质,极费的特效,和多重叠加的UI,所以对于这些的优化都需要测试优化效果。This article on the unity learn site主要讲解UI的优化,但是对于减少overdraw也有一定的建议。
.游戏中的图像特效会极大的造成像素问题,特别是有多个图像特效。如果游戏受到像素的影响同时又采用了图像特效,则最好对图像特效进行优化,比如用优化后的爆炸特效来替代优化前的爆炸特效。特别是在同一个相机上有多个图像特效,这会造成多个shader pass,这种情况下最好将多个图像特效合并在一个shader pass中。如果这样设置都不能解决问题,则最好考虑是否不使能图像特效,特别是在低端机上。
存储带宽
存储带宽是指GPU在其特定的内存上的读写速率,如果游戏受到储存带宽的限制,则意味着游戏在操作GPU快速处理大贴图。可以通过以下方法来确定是否是存储带宽的问题:
. 运行游戏,分析GPU的时间;
. 在unity 的Quality Settings中减少当前平台和目标对象的贴图质量;
. 再次运行游戏,检测游戏性能是否有提升,如果有,则意味着可能是内存带宽造成游戏的性能问题。
如果是游戏的内存带宽造成游戏的性能问题,则需要减少贴图的内存占用来提高游戏的性能。当然不同的游戏解决方法不同,但是有一些通用的方法可以采用:
. 贴图压缩 贴图压缩可以极大的减少贴图在磁盘和内存中的占用率。如果游戏的内存是我们的限制因素,则压缩贴图可以提高游戏的性能。在贴图的压缩中有不同的格式,每种格式都有特定的设置。所以需要不断的测试和实验来找到适合游戏的格式,这儿有如何在unity中设置贴图的格式的一些介绍。
. 多级贴图(Mipmaps)是unity中对于较远的objects的一种技术,如果场景中包含较多的较远的objects,我们可以运用Mipmaps技术来解决存储带宽的问题。这儿介绍了如何在场景中查看多级地图的使用效果,这儿对于贴图的mipmaps有更为详尽的介绍。
顶点计算
顶点计算是指GPU必须对每个网格上的顶点进行的计算操作,顶点计算主要受到两个因素的影响:需要计算的顶点数量,每个顶点需要进行的操作。
如果GPU的性能问题不是来自内存带宽或者像素分辨率,则有可能就是顶点计算造成,此时减少需要渲染的顶点数量可以提高游戏性能。
在减少顶点数量和顶点的操作计算上有一些方法可以提供:
. 首先需要剔除不必要的复杂网格,对于不在视图中的物体,不需要过多的细节网格。对于复杂的包含较多顶点的网格也可以进行简化来避免GPU的浪费。最好的解决办法就是创建面数较低的模型来替代高模。
. 我们可以采用法线贴图的方法来使得贴图有一种更复杂的几何度,尽管这会造成一定的GPU复杂度,但是这对于游戏的性能的提升有较大的帮助。这儿有一些对法线贴图的介绍。
.如果游戏中的模型网格没有使用法线贴图,则可以在导入设置的时候剔除切线顶点来减少顶点数量。
.LOD(level of detail)技术可以用来减少较远网格的复杂度,通过减少需要渲染的顶点数量同时不影响游戏的表现效果。LOD Group对于LOD技术有详尽的介绍。
. shader中的顶点着色器主要用来处理顶点计算,如果游戏受到顶点计算的限制,则减少顶点计算的复杂度可以提高游戏的性能。
— 如果我们采用内置的shader,则最好采用最优化的shader来进行游戏的特效设置。参见上文的分辨率设置。
— 如果游戏采用特制的shader,则最好对其进行优化,参见上文的分辨率设置。
总结
通过全文,我们学习了unity中的渲染原理,怎么解决和定位渲染的问题,提供了一些解决的办法和途径。通过运用分析工具,我们可以定位造成游戏性能的问题,通过优化可以让游戏更加顺畅的运行。
后续我会继续翻译一些Unity中的优化方法,比如内存管理机制的问题。