1、GPU作用:负责整个渲染流水线。它会从处理CPU传递过来的模型数据开始,进行Vertex Shader、Fragment Shader等一系列工作,最后输出屏幕上的每个像素。因此它的性能瓶颈包括顶点、像素、显存等因素有关。
2、顶点优化
1)优化几何体
unity-game视图-stats页签可观察三角形数目和顶点数目。
方案:尽可能减少模型中三角形的数目,一些对于模型没有影响、或是肉眼非常难察觉到区别的顶点都要尽可能去掉。
方案:尽可能重用顶点。在很多三维建模软件中,都有相应的优化选项,可以自动优化网格结构
方案:unity与三维软件在计算顶点上的区别,前者站在GPU角度,后者站在人的角度;有时在GPU看来一个顶点要分开处理,因为顶点的每一个属性和顶点之间必须是一对一的关系,即空间位置上重叠的一个顶点可能会有不同的属性,主要考虑两个方面:UV splits和Smoothing splits。UV splits的产生,是因为建模时,一个顶点的UV坐标有多个;例如在不同面上,同一个顶点的UV坐标可能发生改变。Smoothing splits的产生也是类似的,不同的是,这次一个顶点可能会对应多个法线信息或切线信息。解决方案是对于两个面交接的一个边,采用Smooth Edge不用Hard Edge,以避免冗余的纹理信息。
2)使用LOD(Level of detail)技术
LOD技术有点类似于Mipmap技术,不同的是,LOD是对模型建立了一个模型金字塔,根据摄像机距离对象的远近,选择使用不同精度的模型。它的好处是可以在适当的时候大量减少需要绘制的顶点数目。它的缺点同样是需要占用更多的内存,而且如果没有调整好距离的话,可能会造成模拟的突变
在Unity中,可以通过LOD Group来实现LOD技术。菜单Component-Rendering-LODGroup
3)使用遮挡剔除(Occlusion culling)技术遮挡剔除是用来消除躲在其他物件后面看不到的物件,这代表资源不会浪费在计算那些看不到的顶点上,进而提升性能。
3、像素优化
1)像素个数=屏幕分辨率*帧率FPS,同时受overdraw影响
2)分辨率的放缩:很多国内山寨机有过大的屏幕分辨率+糟糕的GPU,这就是画面与性能之间的权衡关系了。有时我们要针对特定机器进行分辨率的放缩,在Unity中设置屏幕分辨率可以直接调用Screen.SetResolution()。
3)像素优化的重点在于减少overdraw,overdraw指的就是一个像素被绘制了多次。
Unity还提供了查看overdraw的视图,在Scene视图的Render Mode->Overdraw。当然这里的视图只是提供了查看物体遮挡的层数关系,并不是真正的最终屏幕绘制的overdraw。也就是说,可以理解为它显示的是如果没有使用任何深度检验时的overdraw。这种视图是通过把所有对象都渲染成一个透明的轮廓,通过查看透明颜色的累计程度,来判断物体的遮挡。
4)overdraw方案:控制绘制顺序。在PC上,资源无限,为了得到最准确的渲染结果,绘制顺序可能是从后往前绘制不透明物体,然后再绘制透明物体进行混合。但在移动平台上,这种会造成大量overdraw的方式显然是不适合的,我们应该尽量从前往后绘制。从前往后绘制之所以可以减少overdraw,都是因为深度检验的功劳。在Unity中,那些Shader中被设置为“Geometry” 队列的对象总是从前往后绘制的,而其他固定队列(如“Transparent”“Overla”等)的物体,则都是从后往前绘制的。这意味这,我们可以尽量把物体的队列设置为“Geometry” 。例如,对于天空盒子来说,它几乎覆盖了所有的像素,而且我们知道它永远会在所有物体的后面,因此它的队列可以设置为“Geometry+1”,这样就可以保证不会因为它而造成overdraws。
5)overdraw方案:时刻警惕透明物体。而对于透明对象,由于它本身的特性(可以看之前关于Alpha Test和Alpha Blending的一篇文章)决定如果要得到正确的渲染效果,就必须从后往前渲染(这里不讨论使用深度的方法),而且抛弃了深度检验。这意味着,透明物体几乎一定会造成overdraws。如果我们不注意这一点,在一些机器上可能会造成严重的性能下面。例如,对于GUI对象来说,它们大多被设置成了半透明,如果屏幕中GUI占据的比例太多,而主摄像机又没有进行调整而是投影整个屏幕,那么GUI就会造成屏幕的大量overdraws。
6)overdraw方案:减少实时光照。实时光照对于移动平台是个非常昂贵的操作,例如,一个场景里如果包含了三个逐像素的点光源,而且使用了逐像素的shader,那么很有可能将Draw Calls提高了三倍,同时也会增加overdraws。这是因为,对于逐像素的光源来说,被这些光源照亮的物体要被再渲染一次。更糟糕的是,无论是静态批处理还是动态批处理(其实文档中只提到了对动态批处理的影响,但不知道为什么实验结果对静态批处理也没有用),对于这种逐像素的pass都无法进行批处理,也就是说,它们会中断批处理。
7)使用Lightmaps
它主要用于场景中整体的光照效果。这种技术主要是提前把场景中的光照信息存储在一张光照纹理中,然后在运行时刻只需要根据纹理采样得到光照信息即可。
8)使用God Rays
场景中很多小型光源效果都是靠这种方法模拟的。它们一般并不是真的光源产生的,很多情况是通过透明纹理进行模拟。