19.NGUI进阶-DrawCall
19.1 知识点
DrawCall的概念
- 字面理解DrawCall就是绘制呼叫的意思,表示CPU(中央处理器)通知GPU(图形处理器-显卡)。
- DrawCall概念:CPU准备好渲染数据(顶点,纹理,法线,Shader等等)后,告知GPU开始渲染(将命令放入命令缓冲区)的命令。
- 简单来说,一次DrawCall就是CPU准备好渲染数据通知GPU渲染的这个过程。
- 如果游戏中DrawCall数量较高会影响CPU的效率,最直接的感受就是游戏会卡顿。
- 举例说明:以拷贝文件来进行类比。如果我们创建10000个小文件,每个文件大小为1kb,然后把这些文件拷贝到另一个文件夹中,你会发现,即使这些文件加起来不超过10MB,但是拷贝花费的时间是很长的。如果我们单独创建1个10MB的文件拷贝到另一个文件夹,基本可以瞬间拷贝完毕。因为每一个文件赋值动作都需要很多额外的操作,比如分配内存,创建数据等等,这些操作就会带来一些额外的性能开销,进行10000个这样的操作额外开销会非常大。简单理解,文件越多额外开销就越大。
- 渲染过程和上面的例子很类似,每次DrawCall,CPU都需要准备很多数据发送给GPU,那么如果DrawCall越多那么额外开销就越大。其实GPU的渲染效率是很强大的,往往影响渲染效率的都是因为CPU提交命令的速度。如果DrawCall太多CPU就会把大量时间花在提交DrawCall上,造成CPU过载,游戏卡顿。
如何降低DrawCall数量
- 在UI层面上,主要是小图合成大图
- 小图合成大图,即多个小DrawCall变为一次大DrawCall。比如当前要绘制的六张图毫无关系,那么会DrawCall六次,有六次开销。假如把当前六张图打成一张图集,那就只会DrawCall一次,减少了开销。
制作UI时降低DrawCall的技巧
通过NGUI Panel上提供的DrawCall查看工具
- 创建三个同一图集下的Sprite选择小图,点击Panel下ShowDrawCall按钮,可以在弹出来的弹窗看到DrawCall的次数只有1,图集下子物体有3,因为这三个Sprite都在一个图集。
- 如果创建三个Texture直接关联图片(即使是相同图集下的图片),再点击ShowDrawCall按钮,可以看到有三次DrawCall了,因为Texture是直接设置图片没有关联图集,所以就有三次。
注意不同图集之间的层级关系
- 如果更改Sprite012的层级分别为123,再修改Sprite1的图集不和Sprite0和Sprite2不一样,这样DrawCall会有三次。因为即使0和2属于同一个图集,但是他们在1和3层级,2层级插入了一个不同图集的Sprite1,会导致DrawCall增加。
- 这时如果把Sprite1的层级调整成4,那么DrawCall会降为2。可以理解为同属同一个图集的Sprite0和Sprite2的层级13之间没有夹杂其他要渲染的对象,可以一起渲染。
- 注意相同图集下的Sprite的层级层级之间最好不要夹杂其他图集的Sprite,注意可以有效降低DrawCall。
注意Label的层级关系
- 注意Label其实最后也会打成一个动态的图集。假如把他放在相同图集的Sprite的层级中间,也会打断相同图集的Sprite的合并渲染增加DrawCall。可以设置Label的层级更高一些避免打断相同图集的合并DrawCall。
可以用内存降低DrawCall次数
- 比如一个游戏正常来说,有通用图集、开始场景图集和游戏场景图集。
- 这个时候假如开始场景或游戏场景使用到通用场景图集,至少就会产生两次DrawCall。
- 这个时候可以把通用图集里的资源分别放到开始场景图集和游戏场景图集。
- 这样虽然重复了资源,浪费了内存,但是可以减少DrawCall次数。
- 实际开发中要根据实际情况确认更注重内存还是DrawCall。
19.2 知识点代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson19_NGUI进阶_DrawCall : MonoBehaviour
{
void Start()
{
#region 知识点一 DrawCall的概念
//字面理解DrawCall 就是 绘制呼叫的意思 表示 CPU(中央处理器)通知GPU(图形处理器-显卡)
//DrawCall 概念
//就是CPU(处理器)准备好渲染数据(顶点,纹理,法线,Shader等等)后
//告知GPU(图形处理器-显卡)开始渲染(将命令放入命令缓冲区)的命令
//简单来说:一次DrawCall就是 CPU准备好渲染数据通知 GPU渲染的这个过程
//如果游戏中DrawCall数量较高会影响CPU的效率
//最直接的感受就是游戏会卡顿
//举例说明 以拷贝文件来进行类比
//假设我们创建10000个小文件,每个文件大小为1kb,然后把这些文件拷贝到另一个文件夹中
//你会发现,即使这些文件加起来不超过10MB,但是拷贝花费的时间是很长的
//如果我们单独创建1个10MB的文件拷贝到另一个文件夹,基本可以瞬间拷贝完毕
//为什么会这样呢?
//因为每一个文件赋值动作都需要很多额外的操作,比如分配内存,创建数据等等
//这些操作就会带来一些额外的性能开销 进行10000个这样的操作 额外开销会非常大
//简单理解 文件越多额外开销就越大
//渲染过程和上面的例子很类似,每次DrawCall,CPU都需要准备很多数据发送给GPU
//那么如果DrawCall越多那么额外开销就越大,其实GPU的渲染效率是很强大的,往往影响渲染效率的
//都是因为CPU提交命令的速度
//如果DrawCall 太多CPU就会把大量时间花在提交DrawCall上 造成CPU过载,游戏卡顿
#endregion
#region 知识点二 如何降低DrawCall数量
//在UI层面上
//小图合大图——>即多个小DrawCall变一次大DrawCall
#endregion
#region 知识点三 制作UI时降低DrawCall的技巧
//1.通过NGUI Panel上提供的DrawCall查看工具
//2.注意不同图集之间的层级关系
//3.注意Label的层级关系
#endregion
#region 知识点四 可以用内存降低DrawCall次数
//比如一个游戏正常来说,有通用图集、开始场景图集和游戏场景图集。
//这个时候假如开始场景或游戏场景使用到通用场景图集,至少就会产生两次DrawCall。
//这个时候可以把通用图集里的资源分别放到开始场景图集和游戏场景图集。
//这样虽然重复了资源,浪费了内存,但是可以减少DrawCall次数。
//实际开发中要根据实际情况确认更注重内存还是DrawCall
#endregion
}
}
19.3 练习题
在EventListener和EventTrigger特殊事件监听相关的练习题基础上,请用现在所学知识,制作一个这样的功能,调整之前的面板,让面板的DrawCall尽量小
调整面板上各控件的层级,要注意label的影响。
使用合并材质: 如果可能的话,将面板上使用的图片材质合并成一个材质,以减少DrawCall。这可以通过将多个图片合并到一张贴图上,并在NGUI的 Atlas 中进行配置。
合并Label: 如果面板上有多个Label,可以尝试将它们的字体合并到一个字体图集中,以减少DrawCall。这同样可以在NGUI的 Atlas 中完成。
Sprite Atlas: 使用NGUI的 Sprite Atlas 功能将多个 Sprite 图片打包成一个贴图,以减少DrawCall。
UI Panel优化: 对于NGUI中的UI Panel,可以考虑合并它们,尽量减少不必要的UI Panel。将多个UI元素放在同一个Panel下,以减少DrawCall。
动态加载优化: 如果面板中有动态加载的元素,可以考虑使用对象池技术,以减少动态加载时产生的额外开销。
通过这些优化措施,可以有效地减少面板的DrawCall,提升游戏的性能表现。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com