- 最后登录
- 2019-12-25
- 注册时间
- 2012-8-24
- 阅读权限
- 90
- 积分
- 71088
- 纳金币
- 52336
- 精华
- 343
|
最近在整理一些知识点,感觉自己不总结下,实践下好多东西好难彻底搞明白。所以,小菜也开始学着写点东西,都是比较入门的东西,由于小菜技术有限难免会有一些错误,请大家指出,好让小菜及早发现。在开始前,小菜先声明下,以下内容是小菜通过查找网络上与Draw Call相关的教程后,小菜自己整理和总结的内容,有自己原创的看法也有网络其它小伙伴的看法。
好吧,进正题了。首先,我要总结的是有关Ngui draw call的相关入门知识。也许,我们经常会说Draw Call,但究竟什么是Draw Call呢?其实,我在之前也是对这个概念一知半解,那好我们先来普及下常识,其实Unity生成一帧的画面的过程是这样的,引擎会先做简单的可见性测试以确定需要渲染什么物体,然后会把这些物体的一些信息数据准备好(例如:物体的顶点,包括本地位置、法线、UV等,还有变换,相关光源,纹理,渲染方式),然后通知GPU而GPU根据这些数据在屏幕上画出N个三角形,最后就构成了我们眼前的图像。好啦,重点来了,引擎这个渲染物体前的数据准备并且通知GPU的过程就叫做Draw Call。
OK,通过简单的介绍我们大概知道了,Draw Call是什么东西了,其实又不用太了解内面的原理,因为引擎都帮我们完成了,我们更关心的是有关Draw Call的[color=rgb(85, 85, 85) !important]问题和相关解决方案。这里,我想到中学时写议论文的万能公式,没错就是提前问题,分析问题,解决问题三步曲。其实,对于说明一个问题,这三步曲还是挺好用的。好吧,我们就按这三步曲来一步一步分析。
首先,提前问题。说到Draw Call,我们也许最关心的是Draw Call为什么会变得过于大呢?是什么原因造成的呢,我们又应该如何解决呢?要知道,如果一个项目的界面Draw Call过大,会让GPU压力山大的,从而导致差游戏流畅性差,这对于 一个游戏来说是致命的。好,有问题是好事,不断地发现问题,解决问题,我们的技术才会提高。
然后,就到了分析问题了。这Draw Call的问题其实就是,Why Draw Call会变得越来越大?如何减小?Draw Call 为什么会变大?这问题,我们先看定义:Draw Call是引擎渲染前的一个数
据准备和通知GPU的过程.也许大家都会想到了些东西,是不是我们想办法减小这个数据的准备和通知的过程就可以减小Draw Call了呢?换句话说,就是我们应该想办法合并Draw Call,其实就是要站在引擎的角度来看,我如何才能做最小的事,来完成渲染任务呢?举个例子吧,好比如,我们接到了一个任务,这任务包括三个小任务,假如你现在在楼上,请分别是把楼上的灯关了,把楼下的门关了,把楼上的门关了。按正常人的思维,这三个小任务的执行顺序是,先在楼上的灯关了,顺手把楼上的门关上,最后来到楼下关门,这是最有效率的,只需要下一次楼。那假如,我们冒傻了偏要浪费点时间会怎么做呢,可能会先把楼上的灯关了,再到楼下关门,最后又跑上楼上关楼上的门,这需要一次下楼,一次上楼。Ok,这两种情况的效率,大家应该好清楚了。好了,重点又来了,其实Draw Call也一样,说到底就是我们如何安排这个渲染的顺序和渲染的内容.
最后,就是最关键的一步了,解决问题。经我们分析后,也许大家都大概知道怎么做了,没错就是分两个方向,一个是控制好渲染顺序和第二个就是安排好渲染内容。站在引擎的角度,多想想如何才能偷下懒(话说不爱偷懒的程序猿,都不是好的程序猿)。Ok,针对这个原则,我们可以提前几个常用的几个优化方向:
1、图集打包的优化。由于每个材质/纹理的渲染一定是会产生DrawCall的,所以我们只能通过打包图集来进行优化,这可能在不同项目会有不同的结果,我们可以从功能角度进行划分,例如UI可以划分为公共部分,以及每个具体的界面,功能上,显示上密切相关的图片打包到一起.我们要实现的效果是怎样的呢?就是方便我们安排UI时可以做到以下两点:1》可以让同一个图集的元素尽量放在同一个UIPanel下。(经测试可知,它消耗的drawcall是以每个Panel为独立计算单位进行计算的,就算是同一个图集的同一个图片,放在两个不同的Panel也会产生两个Draw Call)2》如果一个UIPanel下面使用了多个图集(不同的动态字体也算不同的图集),那就应该让使用同一个图集的元素连续,尽量避免图集交叉。
2、渲染顺序优化。[color=rgb(85, 85, 85) !important]U3D渲染是有顺序的,而NGUI的渲染顺序是可以由我们控制的,控制好了NGUI的渲染顺序,就等于控制了U3D的渲染顺序,从而控制DrawCall数量。[color=rgb(85, 85, 85) !important]unity3d默认会按照控制的Depth进行渲染,从后往前渲染,当使用相同的材质的控件会合并为一个DrawCall,相反如果和前一个材质不相同就会重新产生一个DrawCall.说白了,就是我们应该渲染完一个图集的元素,再渲染另外一个图集的元素,不要让不同图集的元素出现穿插渲染。在项目中我们可以这样处理,为同一个图集的元素设置一个深度值区间,我们在制造UI时严格按照这个区间来摆放对应图集的元素。
为了加深理解,我们举个例子吧。同一个UIPanel下有4个UIWidget,w1,w2,w3,w4。其中 W1和W2引用altals1。其中 W3和W4引用altals2。如果它们的depth顺序为 w1 : 1,w2 :2,w3 : 3,w4 : 4。那么整个渲染需要2个drawcall,因为渲染顺序为 w1,w2,w3,w4。而w1和w2公用一个altals,所以可以合并成一个drawcall,同理w3和w4可以合并成一个drawcall。而如果它们的depth顺序为: w1 : 1,w2 :3,w3 : 2,w4 : 4。那么整个渲染需要4个drawcall,因为渲染顺序为 w1,w3,w2,w4。因为w1和w3不是公用一个altals,所以只能分开渲染。同理w3和w2,w2和w4也只能分开渲染。
OK,这次总结就以此结束了,感觉这都是好基础的理解,希望大家可以提前更加深入,更加全面的总结和建解,小菜就此拜谢了~!
|
|