NGUI元素的遮挡情况是不依赖空间关系,所以在NGUI上添加特效有时候特别蛋疼,特别是美术同学还要依赖空间关系来控制特效效果,那先看看看NGUI的层级是怎么处理的,不过下面的描述都是针对单个相机下的Panel,如果存在多个相机当然还要考虑相机的前后关系。在写之前,还是记录下这篇随笔参考的资源:《NGUI 渲染流程深入研究》) , 一篇不错的介绍,对理解整个流程很有帮助,对层级关系也做了很多描述;作为补充,《NGUI的渲染流程》 对 理解UIPanel、UIWidget、UIDrawCall的关系稍稍有点帮助
Render Queue
也就是渲染队列,默认情况下,Unity会基于对象距离摄像机的远近来排序对象。对象离摄像机越近就会优先绘制在其他更远的对象上面。对于大多数情况这是有效并合适的,但是在一些特殊情况下,你可能想要自己控制对象的绘制顺序。Unity提供给我们一些默认的渲染队列,每一个对应一个唯一的值,来指导Unity绘制对象到屏幕上的顺序。这些内置的渲染队列被称为Background, Geometry, AlphaTest, Transparent, Qverlay。具体描述如下,也就是说数值越小越先绘制。
渲染队列 | 渲染队列描述 | 渲染队列值 |
---|---|---|
Background | 通常被最先渲染 | 1000 |
Geometry | 默认的渲染队列,它被用于绝大多数对象。不透明几何体使用该队。 | 2000 |
AlphaTest | 通道检查的几何体使用该队列。它和Geometry队列不同,对于在所有立体物体绘制后渲染的通道检查的对象,它更有效。 | 2450 |
Transparent | 该渲染队列在Geometry和AlphaTest队列后被渲染。任何通道混合的(也就是说,那些不写入深度缓存的Shaders)对象使用该队列,例如玻璃和粒子效果 | 3000 |
Overlay | 该渲染队列是为覆盖物效果服务的。任何最后被渲染的对象使用该队列,例如镜头光晕。 | 4000 |
UI RenderQueue
对UI而言,一般是浮动在场景的上层,而且可能使用透明UI,所以RenderQueue一般从3000开始,通常情况下,Render Queue会在Shader的SubShader的Tag中明确描述渲染队列,如:
Tags { "Queue"="Transparent" }
如果查看NGUI的shader,应该可以看到这句话。
动态材质
上一篇文章介绍过,NGUI中所有元素最后都会在DrawCall中生成Mesh、MeshRender、Material,然后被绘制出来。NGUI使用Atlas来管理图片数据,也就是说不同层级的组件也会使用相同的Atlas,这就需要每个DrawCall在运行时动态修改材质的RenderQueue,NGUI通过材质参数来处理这个问题。具体可以可以参考Unity Material.renderQueue的定义, 理解这句话:
By default materials use render queue of the shader it uses. You can override the render queue used using this variable. Note that once render queue is set on the material, it stays at that value, even if shader is later changed to be different.
UIDrawCall实际会创建一个叫做mDynamicMat的Material用作后续的材质渲染顺序、贴图、Shader参数设置。
Widget绘制顺序
先看下DrallCall的生成,在UIPanel.FillllDawcall函数中,先对Widget进行排序,然后在对WIdget进行遍历过程中,如果相邻的Widget使用的材质、贴图或者Shader不相同则创建一个新的Drawcall, 也就说DrawCall列表中的顺序和Widget的顺序是一致的(对于存在DrawCall合并的情况,Drawcall中会记录widget上深度的起始和终止数值)。
在同一个Panel中,Widget会按照深度进行排序,而DrawCall的RenderQueue则根据从Panel的RenderQueue起始数值加上在DrawCall列表中的位置,而对单个drawCll而言,生成的顶点则也会根据Widget深度从小到到的顺序进行填充。也即是说深度越小的组件先绘制,会被后面深度大的组件遮挡住。
// Widget 排序策略,深度相同情况下排序规则就会不明确
static public int PanelCompareFunc (UIWidget left, UIWidget right)
{
if (left.mDepth < right.mDepth) return -1;
if (left.mDepth > right.mDepth) return 1;
Material leftMat = left.material;
Material rightMat = right.material;
if (leftMat == rightMat) return 0;
if (leftMat == null) return 1;
if (rightMat == null) return -1;
return (leftMat.GetInstanceID() < rightMat.GetInstanceID()) ? -1 : 1;
}
// 更新Drawcall的绘制顺序
void UpdateDrawCalls ()
{
for (int i = 0; i < drawCalls.Count; ++i)
{
UIDrawCall dc = drawCalls[i];
dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i;
dc.alwaysOnScreen = alwaysOnScreen &&
(mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip);
dc.sortingOrder = mSortingOrder;
dc.sortingLayerName = mSortingLayerName;
dc.clipTexture = mClipTexture;
}
}
Panel绘制顺序
对于不同的Panel而言,NGUI会根据Panel的深度值进行排序,然后依次计算其起始RenderQueue数值。这样的话 深度高的Panel,其内部组件的RenderQueue的数值也会相对较高
/// <summary>
/// Function that can be used to depth-sort panels.
/// </summary>
static public int CompareFunc (UIPanel a, UIPanel b)
{
if (a != b && a != null && b != null)
{
if (a.mDepth < b.mDepth) return -1;
if (a.mDepth > b.mDepth) return 1;
return (a.GetInstanceID() < b.GetInstanceID()) ? -1 : 1;
}
return 0;
}
void LateUpdate ()
{
if (mUpdateFrame != Time.frameCount)
{
mUpdateFrame = Time.frameCount;
// Update each panel in order
for (int i = 0, imax = list.Count; i < imax; ++i)
list[i].UpdateSelf();
int rq = 3000;
// 更新Panel的渲染顺序
for (int i = 0, imax = list.Count; i < imax; ++i)
{
UIPanel p = list[i];
if (p.renderQueue == RenderQueue.Automatic)
{
p.startingRenderQueue = rq;
p.UpdateDrawCalls();
rq += p.drawCalls.Count;
}
else if (p.renderQueue == RenderQueue.StartAt)
{
p.UpdateDrawCalls();
if (p.drawCalls.Count != 0)
rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
}
else // Explicit
{
p.UpdateDrawCalls();
if (p.drawCalls.Count != 0)
rq = Mathf.Max(rq, p.startingRenderQueue + 1);
}
}
}
}
结论
A 一般情况下,UIPanel\Widget的层级使用Depth来控制其前后关系就可以满足需求,但是对于特效和U> I前后遮挡这种情况就比较难处理,不过可以通过三种方式解决:
- 相机深度
- SortingOrder(一直没弄明白这是什么鬼)
- RenderQueue
B. DrawCall的数量和组件的深度的也有关系,同样材质的组件使用连续的深度值就会合并为一个组件,OK ,实际上使用过程中,不合理使用似乎更多点,下图就是一种比较恶劣的使用情况,两张图片,但是深度设置不合理,却有10个DrawCall
NGUI 层级关系控制的更多相关文章
-
Unity NGUI和UGUI与模型、特效的层级关系
目录 1.介绍两大UI插件NGUI和UGUI 2.unity渲染顺序控制方式 3.NGUI的控制 4.UGUI的控制 5.模型深度的控制 6.粒子特效深度控制 7.NGUI与模型和粒子特效穿插层级管理 ...
-
NGUI与特效的层级关系
通过调整特效的 render queue 来解决特效与NGUI界面之间的层级关系问题,用以下脚本解决: using System.Collections.Generic; using UnityEng ...
-
树状结构Java模型、层级关系Java模型、上下级关系Java模型与html页面展示
树状结构Java模型.层级关系Java模型.上下级关系Java模型与html页面展示 一.业务原型:公司的组织结构.传销关系网 二.数据库模型 很简单,创建 id 与 pid 关系即可.(pid:pa ...
-
【吐血分享】SQL Server With As 递归获取层级关系数据
纯洁的一周又开始了,今天看到一则新闻,笑尿了,和袁友们一起娱乐下 最近两月在做基于Saas模式的人力资源管理产品,平常数据库设计我经常会遇到如下需求场景: 以前商城类网站在设计类型表的时候,设计成单表 ...
-
CTE计算层级关系
推广渠道表有ParentID字段,代表上下层级关系.现要统计每个推广员,推广了多少人? --创建表结构,插入测试数据 USE DBA_Monitor GO CREATE TABLE [dbo].[TG ...
-
MFC窗口的父子关系和层级关系
一直对窗口之间的关系有些混乱,遇到需要指定父窗口的函数时常常要考虑很久,究竟父窗口是哪个窗口,遂上网查资料,略有所悟,简记如下: 对话框中的所有控件(比如Button等)都是其子窗口. ...
-
vue层级关系的数据管理
项目背景:为一些有层级关系的数据管理做一套后台管理系统,例如一个小区,里面是有许多楼,楼里有许多层,每一层有许多不同的房······,现在就是要实现对这些数据进行增删改查操作. 1.Tree(树形组件 ...
-
php解析出带层级关系的mpp文件
本来要使用DHX gantt插件自带的API做导入,可是做完后,又发现不稳定,不能访问了 可能是屏蔽掉了 所以又想起可以使用javaBridge,借用java的MPXJ php解析mpp的 上一篇介绍 ...
-
css - Position定位属性与层级关系
今天同事发现一个有意思的问题,关于position的层级关系的,他要不说我也没注意过 测试后果然有趣,有待深入研究: <!DOCTYPE html> <html> <he ...
随机推荐
-
Apache 与 php的环境搭建
Apache和PHP的版本分别为: httpd-2.4.9-win64-VC11.zip php-5.6.9-Win32-VC11-x64.zip 下载地址: php-5.6.9-Win32-VC11 ...
-
Debian 7环境安装TightVNC+Gnome远程桌面环境
昨天下午的时候一个Hostus网友希望在购买的VPS主机中安装桌面环境用来跑软件项目,其实也是我们很多用户习惯的VNC桌面,毕竟在LINUX服务器中也无法去安装WINDOWS系统,尤其是OPENVZ架 ...
-
【bzoj1455】罗马游戏 可并堆
2016-05-31 10:04:41 可并堆的裸题. 左偏树(小根堆为例 性质 1.满足堆的性质,每个节点权值小于左右儿子权值 2.每个节点有dis值,表示子树最浅的叶子深度加1 3.左子树dis ...
-
iframe 动态onload事件处理方式
转自:http://w3help.org/zh-cn/causes/SD9022 标准参考 关于 HTML 4.01 规范中 BODY 标记的 onload 属性说明: http://www.w3.o ...
-
Android中string.xml文件中设置部分字体颜色大小
1.在string.xml文件中: <string name="tips_all"><Data><![CDATA[清理进程:<font colo ...
-
AdHoc发布时出现重复Provisioning Profile的解决方案
当在developer.apple.com更新Provisioning Profile(添加新机器)后,下载到本地,双击载入xcode,运行时没问题.但如果用adhoc发布,可能会发现重复的provi ...
-
XMAL 中x名称控件的Auttribute
1 X:Class 作用告诉XAML编译器将XAML标签的编译结果与后台代码中指定的类合并,只能用于根节点,并且与之同名的类需要有Partial 例如窗口 2 X:ClassModifier 作用告诉 ...
-
codeforces 540D 概率dp
传送门 大概可以这样理解, 一开始有r个石头, p个布, s个剪刀, 每一天有其中的两个相遇, 如果两个是相同的种类, 什么都不会发生, 否则的话有一个会挂掉, 问最后每一种生存的概率. dp[i][ ...
-
NOI第一天感想&小结
嘛...中午总算是到了深圳了--在虹桥机场和飞机上和市队大神们一起讨论各种各样奇(sang)葩(bing)的算(ren)法(lei)还是非常开心的,在此再各种膜拜一下尽管没来比赛的FFT大神@陈中瑞 ...
-
Go基础之--操作Mysql(二)
在上一篇文章中主要整理了Golang连接mysql以及一些基本的操作,并进行了大概介绍,这篇文章对增删查改进行详细的整理 读取数据 在上一篇文章中整理查询数据的时候,使用了Query的方法查询,其实d ...