NGUI 层级关系控制
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 ...
随机推荐
- python Function
Python 2.7.10 (default, Oct 14 2015, 16:09:02) [GCC 5.2.1 20151010] on linux2 Type "copyright&q ...
- ubuntu下MySQL中文乱码(新版本Mysql修改方法)
前几天在开发的时候出现了中文查询阿里云服务器上的mysql的时候,查询出来的值为空,找了好久终于发现原因是ubuntu下的mysql无法识别中文,这就涉及到要调整编码格式啦!!!! 然后就在网上查了许 ...
- jstl catch if choose标签
catch标签: catch标签用来处理异常 属性: * var :用来出现异常保存到的变量. 代码: <c:catch var="e"> <% int i = ...
- objccn-相机工作原理
感觉这个世界上最幸福的事情就是工作和兴趣结合到一起了.这一阵子总是在听再看有关摄影的种种,今天在objccn上又看到这个,哈哈~ 轻轻一按,相机就把光子转化成了比特,于是一张照片就保存到了手机里. 一 ...
- MyBatis的初始化方式
1. 加载配置文件 public static void main(String[] args) throws IOException { //mybatis的配置文件 String resource ...
- NSString 初始化方法的内存比较
NSString *str1 = @"hello"; NSString *str2 = @"hello"; NSString *str3 = [NSString ...
- iOS开发UI篇—核心动画(关键帧动画)
转自:http://www.cnblogs.com/wendingding/p/3801330.html iOS开发UI篇—核心动画(关键帧动画) 一.简单介绍 是CApropertyAnimatio ...
- LockSupport
LockSupport是高级线程同步类的基础,用来block和释放线程.这里要区别notify和wait的点在于这里可以先unpark,再park.(有点类似于unpark等于-1,park等于+1. ...
- EXT.NET 使用总结(1)
前言 从系统改版到现在,将近半年的时间,原本陌生的Ext.NET的UI框架,也慢慢的熟悉了.总的来说,这个UI框架还是很优秀的,但是也没有100%完美的产品(老系统使用easy ui其实也挺好的).趁 ...
- OneThink开发框架
OneThink是一个开源的内容管理框架,基于最新的ThinkPHP3.2版本开发,提供更方便.更安全的WEB应用开发体验,采用了全新的架构设计和命名空间机制,融合了模块化.驱动化和插件化的设计理念于 ...