一、CPU与GPU
1、CPU与GPU的区别
橙黄色:控制单元 橙红色:存储单元 绿色:计算单元
CPU:结构组成复杂、控制逻辑丰富,计算量小,适合复杂运算
GPU:结构组成简单,核心数量多,计算量大,适合简单运算
CPU:以i7-10700为例,有8核心16线程
GPU:以RTX2060为例,有1920个Cu核心,每个CU核心包含了64个流处理器,即1920*64=122880个流处理器计算核心
CPU相对于GPU就像老教授和小学生,拿i7-10700和RTX2060举个例子,出一套小学数学试卷,老教授刚做一道题,两千多名学生一人一题早就交卷子了。如果套高数卷子,老教授做完学生们一道也不会做。
2、CPU渲染与GPU渲染
2.1、CPU渲染
由于CPU的内核较少,资源的可用性也有限,所以渲染速度通常比GPU慢
CPU渲染更注重精度和渲染细节,能够渲染出更准确和细致的光影效果。同时还可以通过更高的内存带宽来处理复杂的算法,掌握更高的渲染技能
2.2、GPU渲染
每个核心处理一个像素,渲染速度要比CPU快很多
通常可以更快速地呈现动态光影效果,例如全局光照和环境光遮蔽。但在精确度上,由于GPU渲染使用了一些近似计算方法,因此在某些情况下,细节可能会略有差别
二、渲染流水线
Draw Call就是在应用阶段产生的,本文侧重介绍应用阶段,其他阶段有兴趣的可以参阅:
https://blog.csdn.net/u012722551/article/details/104276327?spm=1001.2014.3001.5502
三、应用阶段都负责了些什么?
应用阶段由CPU负责,准备好场景数据、剔除掉不可见的物体、设置耗每个模型的渲染状态,设置好后传给GPU
3.1、数据加载到显存中
将渲染所需数据从硬盘加载到内存中,网格纹理等数据又被加载到显存中(一般加载到显存后内存中的数据就会被移除)
3.2、设置渲染状态
这些状态定义了场景中的网格是怎么被渲染的。例如,使用哪个顶点着色器, 片原着色器,光源属性,材质等。
3.3、调用Draw Call
Draw Call 就是一个命令,它的发起方是Cpu,接收方是Gpu。这个命令仅仅会指向一个需要被渲染的图元列表,而不会包含任何材质信息。
三、为什么Draw Call多了会影响帧率
在每次调用Draw Call之前,CPU需要向GPU发送很多内容,包括数据﹑状态和命令。在这一阶段,CPU需要完成很多工作,例如检查渲染状态等。而一旦CPU完成了这些准备工作,GPU就可以开始本次的渲染。GPU的渲染能力是很强,渲染200个还是2000个三角网格通常没有什么区别,因此渲染速度往往快于CPU提交命令的速度。如果Draw Call的数量太多,CPU就会把大量时间花费在提交Draw Call 上,造成CPU的过载
命令缓冲区中的虚线方框表示GPU已经完成的命令。此时,命令缓冲区没有可以执行的命令了,GPU处于空闲状态,而CPU还没有准备好下一个渲染命令
四、优化方向
1. 合并网格
相同材质的模型合并成一个网格
2. 合并材质
能用相同材质的尽量用相同材质
3. 静态合批
静态合批前提是使用相同的材质、运行时不能移动、旋转、复制
静态批处理会导致内存和存储开销
4. 动态合批
Cocos、Laya这些WebGL的引擎没有该功能
动态合批是专门为优化场景中共享同一材质的动态GameObject的渲染设计的。目标是以最小的代价合并小型网格模型,减少Drawcall
动态合批是前提是使用相同材质,Unity自动处理的
动态批处理会产生一些 CPU 开销
5. GPU Instancing
GPU Instancing 没有动态合批那样对网格数量的限制,也没有静态网格那样需要这么大的内存,它很好的弥补了这两者的缺陷
美术如何使用GPU Instancing?
方法1. 针对重复的物体(网格、材质一样),可以在DCC软件上导出一个,再在引擎上copy实例化出来多个,在引擎的场景上摆好位置
方法2. 针对于方法一,不熟悉引擎,或者不习惯引擎里的操作,不想在引擎上摆,想在DCC软件上摆,怎么办呢?
美术可以在DCC软件上只建出一个重复的物体,再通过实例化的方式实例化出来,在DCC软件上摆好位置,切记摆好后不要重置轴或者修改某个模型。导到引擎里后,把这些重复性的模型的网格全部改成其中一个即可。
这个方法的原理就是在DCC软件上记录好每个Instancing的模型的位置信息,再在引擎上使用