文中多有引用,如有侵权请指出。
学习笔记之三:性能优化
一些名词的概念介绍
1. OpenGL和DirectX
OpenGL和DirectX是图像编程接口,用于渲染二维或者三维图像,架起上层应用程序和底层GPU的沟通桥梁。
我们的应用程序运行在CPU上,应用程序调用图形接口将渲染数据储存在显存中,然后图形接口发出渲染命令,这些命令传递给显卡驱动,被显卡驱动翻译成GPU可以理解的机器语言,进行图形绘制。
2. 着色语言HLSL、GLSL、Cg
着色语言专门用来编写着色器,常见类型有DirectX的HLSL(UE4使用的就是HLSL,而Unity使用的也是HLSL的一个变种。)、OpenGL的GLSL以及NVIDIA的Cg(HLSL语言和Cg的语法几乎一模一样,所以选择Cg基本上等于选择HLSL)。
3. Draw Call
(1)Draw Call就是CPU调用图形绘制API,以命令GPU进行渲染的操作,每调用一次为一次draw call。
(2)图形绘制API的调用需要很多准备工作:检查渲染状态、提交渲染数据、提交渲染状态,相对比较耗时。DrawCall是在CPU上运行的,当DrawCall过多时,就会出现CPU过载但GPU闲置的状态。
Unity界面中可以查看当前的DrawCall
4. 固定渲染管线
(1)固定函数的流水线(Fixed-Function Pipeline),通常指古董级的GPU上实现的渲染流水线。开发者对它只能进行一些配置操作,而并不能对其进行更多编程操作。就像是只留下了几个开关的电路板。
(2)基本已经没什么设备会用,知道就好了。
5.帧率(FPS):表示一秒钟内渲染的图片(帧)数量,是反应游戏渲染速度最为直观的数据。主要受到CPU和GPU的耗时影响。
6.面数(Triangle Count),在游戏中需要渲染的模型面数,一般来说考虑的只是同屏面数,面数越多,渲染速度越慢。
7.贴图,是指在三维模型上面映射的纹理,一般保存为各种格式的正方形图片。
二、对渲染进行性能优化
1. 内存和帧率
由于硬件的影响,应用程序不可能无限开辟内存,所以内存是应用程序效率的主要数据之一。内存太高可能导致应用程序崩溃,会导致内存碎片化,影响下一次使用内存的寻址时间,还会导致垃圾清理消耗太多时间。
帧率和内存是游戏性能分别在时间和空间上的两个数据表现。而这两个数据表现是由一系列其他因素导致的。
为了知道哪些因素导致了性能的消耗,可以使用性能优化工具来查看。比如RenderDoc,IntelGPA,Unity Proflie等。
2. 优化顶点数据
(1) 不对不需要的数据进行导出,比如没有用到2UV就不输入2UV,没有用到法线就去掉法线,没有顶点色信息就去掉顶点色等等。
(2) 顶点数据压缩,可以提高数据从CPU传入GPU的速度。
(3) 坐标数据,使用更节省的数据类型,减少每个顶点数据占用的字节数。
3. 优化Draw Call
(1) 减少渲染的物体。有些在远处,被遮挡,看不清的位置的物体,可以通过逻辑去除该物体的渲染。
(2) 合批Draw Call。引擎一般都提供了合并Draw Call的功能,如动态合批,静态合批,代码合批。这些合批的基本条件是使用相同的材质。
① 如何尽可能使用相同的材质。场景中的相似物体可以使用同样的参数,同一个shader,对于使用不同贴图的模型,在必要时可以修改UV,并且对贴图进行合并。
② 动态合批:引擎会在应用阶段收集满足合批的模型,将这些模型收集在一个大mesh,通过这个大mesh进行一次API提交,从而减少大量零散小物体的绘制。
③ 静态合批:动态合批是在运行时进行的,而静态合批是读取在运行前已经合批好的数据。
④ 代码合批:有些引擎会提供一些接口,用逻辑来判断在不同状态下是否对模型进行合批。
4. 优化面数
(1) 一般在项目中会确定模型制作时的面数要求,在前期就规定好同屏面数的限制,而一些没有经验的项目往往就要花费数倍的时间和金钱去进行返工。
(2) 面数LOD:现在引擎一般都会提供LOD功能,根据摄像机距离的不同来使用不同的LOD Level 的模型。
5. 优化Shader
(1) Shader复杂度:一般来说,Shader的指令个数可以粗略表示Shader的复杂度。要降低复杂度,要少用复杂计算的函数,反三角函数以及循环指令的消耗都特别大,要尽量少用。、
(2) Shader组合:Shader组合时指Shader为了满足多种功能或者表现,在Shader中通过添加宏代码块来开关对应的功能和效果表现。一般引擎会通过组合的方式来生成不同的Shader版本。这样Shader就会比较灵活,在一个Shader上包含了多种效果,管理方便。但是要控制Shader生成的内存大小。
(3) Shader LOD:给不同性能的设备提供高中低配置的Shader版本。
(4) 在CPU性能不错的情况下,能在CPU计算的就不在顶点着色器计算,能在顶点着色器计算的就不在片元着色器计算。
(5) 使用适合的数据精度。
(6) 曲面细分shader,曲面细分对性能的消耗巨大。当需要用到这些Shader时,要尽可能减少曲面细分的范围,因为这种功能一般都会比普通Shader更加消耗GPU性能。
(7) 几何Shader:利用几何Shader生成大量物体来渲染比起在应用层提交大量DrawCall会更加节省性能,在一些情况下,如渲染草丛、碎石时会很有用。
6. 优化贴图
(1) 格式:压缩格式并不是指外部的图片格式,而是引擎内部的压缩方法
图片引用自https://www.cnblogs.com/zsb517/p/6297739.html
在移动端,ASTC是首选的纹理压缩格式。
(3)尺寸:很容易理解,图片越大,消耗越大。最好是根据实际的运行平台来确定适合的贴图大小。
(4)采样滤波(Filter):现在常见的滤波方式中性能消耗:Anisotropic=>Trilinear=>Bilinear=>Linear=>Point ,而更高的消耗也意味着更高的精度,更好的效果。
(5)Mipmap:当摄像机离图片距离更远时,引擎会自动采用更低精度的Mipmap,可以有效减少渲染消耗。
(6)合并多个单通道贴图,可以降低内存消耗。
7. Overdraw
(1) 使用透明渲染时会出现。为了绘制透明物体背后的物体,所以不能裁剪掉背后的物体,而多个透明物体互相叠加时,性能消耗更为恐怖。
(2) 所以要减少透明物体,限制透明物体的重叠。
8. 分辨率:分辨率越高对于GPU的性能要求越高,对于分辨率高但是GPU比较差的机型进行降低渲染分辨率可以提高帧率。
9. 剔除
(1) 主要有:视锥体剔除、遮挡剔除、背面剔除、深度剔除。
(2) 一般游戏引擎都有相应的算法来实现以上功能,可以进行配置或者自己编写算法来实现更多的功能。
10. 抗锯齿(Anti-aliasing)
抗锯齿主要有两种算法:super sampling(超级采样)和Multi Sampling(多采样),超级采样的消耗较大,而效果也更好。
以上是对性能优化的一些简单介绍,实际应用中还有很多更复杂的细节需要去解决。在了解这些知识之后可以有目标的去排查问题。
参考图书《Unity Shader入门精要》
电 话:400-123-4567
传 真:+86-123-4567
手 机:13800000000
邮 箱:admin@eyoucms.com
地 址:广东省广州市天河区88号