语言选择: 简体中文简体中文 line EnglishEnglish

行业资讯

Shader学习(3)性能优化的概念

文中多有引用,如有侵权请指出。

学习笔记之三:性能优化

一些名词的概念介绍

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) 格式:压缩格式并不是指外部的图片格式,而是引擎内部的压缩方法



图片引用自cnblogs.com/zsb517/p/62

在移动端,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入门精要》

平台注册入口