`

NGUI所见即所得之UIWidget , UIGeometry & UIDrawCall

阅读更多

NGUI所见即所得之UIWidget , UIGeometry & UIDrawCall

 

       UIWidget是所有UI组件的抽象基类,作为基类当然定义了必须的成员变量和函数,接触过MFC或其他UI组件开发,想必都知道有一堆参数设置,尤其是Visual Studio的可视化界面,简直太丰富了,UIWidget要当UI组件的爹就必须得具备这些,下面就一一介绍:

 

Pivot

       Pivot,这个枚举,其实定义了GameObject中心坐标在整个组件的位置,这个跟UIStretch很类似,只不过UIStretch说的是组件相对于屏幕的位置。

public enum Pivot
	{
		TopLeft,
		Top,
		TopRight,
		Left,
		Center,
		Right,
		BottomLeft,
		Bottom,
		BottomRight,
	}

        Pivot可以提供开发者更多的定位模式,可以方便实现组件对齐,如对个UILabel组件的文本居中对齐。当然这样,在计算组件的四个角的顶点坐标(localCorners)就得考虑Pivot。

 

localCorners,worldCorners & innerWorldCorners

        这三个变量都是四个角的顶点坐标,只是localCorners是计算局部的(相对gameObject的中心而言)坐标,worldCorners只是将localCorners作为世界坐标空间的坐标,innerWorlCorners则考虑了边框Border。

	public virtual Vector3[] localCorners
	{
		get
		{
			Vector2 offset = pivotOffset;

			float x0 = -offset.x * mWidth;
			float y0 = -offset.y * mHeight;
			float x1 = x0 + mWidth;
			float y1 = y0 + mHeight;

			mCorners[0] = new Vector3(x0, y0, 0f);
			mCorners[1] = new Vector3(x0, y1, 0f);
			mCorners[2] = new Vector3(x1, y1, 0f);
			mCorners[3] = new Vector3(x1, y0, 0f);

			return mCorners;
		}
	}

 上面代码中的pivotOffset的计算就考虑了Pivot:

static public Vector2 GetPivotOffset (UIWidget.Pivot pv)
	{
		Vector2 v = Vector2.zero;

		if (pv == UIWidget.Pivot.Top || pv == UIWidget.Pivot.Center || pv == UIWidget.Pivot.Bottom) v.x = 0.5f;
		else if (pv == UIWidget.Pivot.TopRight || pv == UIWidget.Pivot.Right || pv == UIWidget.Pivot.BottomRight) v.x = 1f;
		else v.x = 0f;

		if (pv == UIWidget.Pivot.Left || pv == UIWidget.Pivot.Center || pv == UIWidget.Pivot.Right) v.y = 0.5f;
		else if (pv == UIWidget.Pivot.TopLeft || pv == UIWidget.Pivot.Top || pv == UIWidget.Pivot.TopRight) v.y = 1f;
		else v.y = 0f;

		return v;
	}

         发现pivotOffset是一个由0,0.5,1组成的二维向量,所以前面计算localCorners的原理就可想而知了。

         当然还有诸如width(minWidth),height(minHeight),depth(raycastDepth),alpha(finalAlpha),看了代码就自然一目了然了。rayCastDepth和finalAlpha都考虑了UIPanel的因素,所以有时表层看着没问题,可能就要去看下底层的实现。

 

两大基石:UIDrawCall和UIGeometry

       根据我有限的3D知识(其实没有学过),隐约觉得3D呈现出来的东西都是由顶点(vertice)构成的Mesh通过纹理贴图构成的材质渲染出来的。

        但是NGUI所有组件都没有看到Mesh Render,只有transform信息和脚本,查看UIWidget:

         /// <summary>
	/// Internal usage -- draw call that's drawing the widget.
	/// </summary>

	public UIDrawCall drawCall { get; set; }

	// Widget's generated geometry
	UIGeometry mGeom = new UIGeometry();

 这就是UIDrawCall和UIGeometry神一般的存在。

 

UIGeometry

         UIGeometry其实是UI组件的数据仓库,存储UI组件的Vertices,UVs和Colors,以及相对UIPanel的顶点Vertices,法向量和切线:

	/// <summary>
	/// Widget's vertices (before they get transformed).
	/// </summary>

	public BetterList<Vector3> verts = new BetterList<Vector3>();

	/// <summary>
	/// Widget's texture coordinates for the geometry's vertices.
	/// </summary>

	public BetterList<Vector2> uvs = new BetterList<Vector2>();

	/// <summary>
	/// Array of colors for the geometry's vertices.
	/// </summary>

	public BetterList<Color32> cols = new BetterList<Color32>();

	// Relative-to-panel vertices, normal, and tangent
	BetterList<Vector3> mRtpVerts = new BetterList<Vector3>();
	Vector3 mRtpNormal;
	Vector4 mRtpTan;

 UIGeometry为此提供了三个函数,也可以说是为渲染绘制做的三个步骤:

Step 1:   Clear()    情况存储的信息

Step 2:   ApplyTransform()    将verts转化为相对UIPanel的顶点坐标mRtpVerts

Step 3:   WriteToBuffers()     将数据仓库缓存的数据添加到UIPanel的缓存数据队列中去。

 

          UIWidget分别用UpdateGeometry和WriteToBuffers对UIGeometry的ApplyTransform和WriteToBuffers进行封装调用,ApplyTransform是根据UIPanel的坐标调整Vertices的坐标,WriteToBuffers将UIGeometry的Vertices,UVs和Colors添加进UIPanel的Vertices,UVs和Colors的BetterList中。

          这里还有一个细节就是:UIGeometry中的Vertices,UVs和Colors的BetterList的buffer什么时候得到,因为这些都是UIWidget或其子类的信息,所以在UIWidget的子类UILabel,UISprite和UITexture中OnFill函数生成UIGeometry的BetterList的buffer。

 

 

 

UIDrawCall

       如果是UIGeometry为了渲染绘制准备数据,那么UIDrawCall其实是定义了渲染绘制需要的基本组件。这里拿煮菜做个比喻帮助理解:UIGeometry好比为煮菜准备食材,UIDrawCall好比是煮菜的工具(锅,炉子等),UIPanel就是大厨了决定着什么时候该煮菜,UIWidget(UILabel,UISprite和UITexture)是这道菜怎么样的最终呈现。会不会很好理解呢?

          下面就直接看下Set函数:

if (mFilter == null) mFilter = gameObject.AddComponent<MeshFilter>();
if (mRen == null) mRen = gameObject.GetComponent<MeshRenderer>();

         在Set函数中就给gameObjdect添加了MeshFilter和MeshRenderer组件,当然还做了其他辅助的工作。

         此外,在UpdateMaterials惊奇的发现了UIPanel clipView的AlphaClip和SoftClip的实现,其实就是更换了Material的Shader,这也体现了Shader强大,不得不学呀,DSQiu在后面也会对Unity的Shader编程做一个整理。

 

回放细节,回笼锻造

          看了上面就会觉得写得的确是所见即所得——D.S.Qiu好像都没有看到什么要害,都说学武功就要学习上次心法,一点皮毛总是会惹来耻笑。

          还是回到UIWidget这个脚本中的两个函数:WriteToBuffers,OnFill,UpdateGeometry。

          WriteToBuffers和OnFill这两个函数都是将Vertices,UVs和Colors等add进参数的List中去,查看WriteToBuffers的调用出发现其参数是UIPanel的Vertices,UVs和Colors,而OnFill的参数是UIGeometry的Vertices,UVs和Colors。

          WriteToBuffers只是对UIGeometry的封装调用,也就是说将UIGeometry的Vertices,UVs和Colors等信息add进UIPanel的对应List中。

          在看UIGeometry的脚本,一直有一个疑问:UIGeometry的Vertices,UVs和Colors的List没有看到add方法的执行,只有在WriteToBuffers被add。直到看到了OnFill才恍然大悟,虽然UIWidget的OnFill是虚函数,没有具体实现,看了下UISprite重写的OnFill函数,就是把Vertices,UVs和Colors 添加到UIGeometry的Vertices,UVs和Colors中。

          转了一大圈,发现最后所有UI组件的Vertices,UVs和Colors都汇集到UIPanel的Vertices,UVs和Colors去了,然后UIPanel指定给UIDrawCall渲染就行了,具体细节还要等攻克UIPanel就明白了。

 

 

其他细节

       到这里差不多把本文的内容都掏干净了,剩下的就是看下UIWidget的一些实现细节,MakePixelPerfect():对gameObject的localPosition和locaScale进行微调和纠正。

SetDirty():调用UIPanel的SetDirty()对组件的变更进行重建(rebuilt)。

CreatPanel():这个函数可以得知,所有UI组件一定是放在UIPanel的子节点上的,从前面的分析也可以知道:因为是UIPanel对统一对组件进行渲染绘制的,所以如果没有UIPanel有点“皮之不存,毛将附焉”的意思。

这也越发激发D.S.Qiu 去啃UIPanel这个主心骨。

 

小结:

       总算对UIWidget,UIGeomerty 和UIDrawCall有了一个清晰的认识,这三个组件可以说是NGUI的背后无名英雄(平时使用都不会接触者三个脚本),功能很强大但很简单,真的很佩服NGUI的设计思路。

       但我也有点小微词:UIWidget都被定义成长方形的,要是能提供自定义UI的接口(如我想画一个圆形UI),那将会更强大;底层缓存了很多数据,这个是内存和开发者的代码逻辑也是要考虑到的。

       最后附上①画的NGUI框架图:


       如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。

        转载请在文首注明出处:http://dsqiu.iteye.com/blog/1965340

 

更多精彩请关注D.S.Qiu的博客和微博(ID:静水逐风) 

 

参考:

dujimachehttp://www.unitymanual.com/forum.php?mod=viewthread&tid=5579&highlight=NGUI%E6%A1%86%E6%9E%B6

        

 

 

 

 

 

 

 

 

 

 

 

 

  

 

          

 

 

  • 大小: 157.7 KB
2
0
分享到:
评论
2 楼 DSQiu 2013-12-13  
kevinmw 写道
请问下D.S.Qiu
你分析的ngui版本是多少,我在UIWidget没有找到localCorners这些值,用的2.6.4的版本

3.0.x
1 楼 kevinmw 2013-12-13  
请问下D.S.Qiu
你分析的ngui版本是多少,我在UIWidget没有找到localCorners这些值,用的2.6.4的版本

相关推荐

    NGUI插件3.11.2版本

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI_3.11.3.unitypackage

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI3.11.4

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI 2019_3_0.unitypackage.zip

    开发者可以在Unity编辑器中直接设计和调整UI元素,实现所见即所得的效果。这种设计方式极大地提高了开发效率,使得UI设计和游戏逻辑的开发可以同步进行,减少了开发者在不同工具间切换的时间成本。 二、本地化与...

    NGUI Next-Gen UI 2020.1.5

    - 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持 2020.1.5 - NEW: You can now specify per-symbol ...

    CustomGUI.unitypackage

    使用unity原生GUI封装,来达到UGUI,NGUI所见即所得的效果和部分功能,目的是由此来了解高级UI的原理。

    NGUI Tutorial Create a Button & Download

    在本教程中,我们将深入探讨如何...NGUI的强大之处在于其高度的可定制性和灵活性,无论是对于初学者还是有经验的开发者来说都是一个值得学习的工具。在未来的游戏开发过程中,掌握NGUI将有助于提升UI设计的质量和效率。

    NGUI插件大全

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。 基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。 全面支持iOS/Android和Flash。 灵活的事件系统。 可以让...

    NGUI3.6.4 最新版本NGUI ngui

    《NGUI 3.6.4:打造高效Unity3D移动界面的利器》 NGUI,全称为Next-Gen UI,是Unity3D游戏引擎中的一款广泛应用的界面系统插件,尤其在移动游戏开发领域备受青睐。其3.6.4版本作为官方发布的最新版,不仅集成了之前...

    最新版本的NGUI插件NGUI Next-Gen UI 覆盖unity多个版本

    NGUI Next-Gen UI是一款功能强大、灵活性高的UI插件,是当前最新版本的NGUI插件。它可以覆盖Unity的多个版本,包括Unity 5、Unity 2017和Unity 2018等。与其他UI插件相比,NGUI Next-Gen UI具有高效的性能和优秀的...

    NGUI 3.5.9

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。  基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。  全面支持iOS/Android和Flash。  灵活的事件系统。...

    NGUI3.7.3unitypackage

    NGUI3.7.3unitypackage 是 NGUI 的一个特定版本,即3.7.3版的资源包。这个版本包含了对 NGUI 系统的更新和改进,旨在提升性能、优化用户体验以及增加新的功能。 NGUI 的核心特性包括: 1. **Widget 系统**:NGUI ...

    NGUI 2020.1.5.unitypackage

    NGUI 是一款非常强大的 UI 系统和事件通知框架。...- 编辑器集成,所见即所得 - 本地化、数据绑定、委托、事件 - 支持所有平台 - 制作进行 1 次绘制调用的 UI - 随附完整的 C# 源代码 - 已广泛优化 - 专门团队支持

    NGUI3.5.9 Unity3d UI开发神器

    在场景视图中看到的就是在游戏视图中得到的(所见即所得)。  基于组件的、模块化的特性:要让你的界面控件做什么,只需为其附加相应的行为,而不需要编码。  全面支持iOS/Android和Flash。  灵活的事件系统。...

    NGUI 3.11 离线 Document 文档

    1. **NGUI基本概念**:NGUI的基本构成包括UIPanel、UIWidget、UILabel、UIButton等基本元素。这些元素是构建UI的基础,理解它们的功能和交互方式是使用NGUI的第一步。 2. **UIPanel**:这是NGUI中的一种核心组件,...

    NGUI图文混排demo

    NGUI图文混排的实现是其核心特性之一,它允许开发者在界面上灵活地组合文字和图像,创造出各种复杂的布局效果。下面将详细探讨NGUI图文混排的相关知识点。 1. **NGUI概述**: NGUI(Natural GUI)是由Tasharen ...

    NGUI v3.12.1 2018 最新版NGUI

    《NGUI v3.12.1:2018年Unity UI系统深度解析》 NGUI,全称为Next-Gen UI,是一款专为Unity引擎设计的用户界面系统。在2018年,它发布了v3.12.1的最新版本,此更新旨在优化用户体验,提升性能,并增加新功能。作为...

    NGUI3.11.2

    NGUI 是一个针对 Unity 游戏引擎的用户界面(UI)系统,专为游戏开发者设计,提供了一套高效、易用且功能丰富的UI组件。在3.11.2版本中,NGUI 进一步提升了性能和用户体验,遵循了“Keep It Simple, Stupid”(KISS...

    Unity插件 NGUI各种版本合集

    本包中共有六个版本的NGUI,大家可以自己选择版本。 NGUI Next-Gen UI 3.6.0.unitypackage NGUI Next-Gen UI 3.12.1(u5.6.5).unitypackage NGUI Next-Gen UI 2019.3.0.unitypackage NGUI Next-Gen UI v2018.3.0....

    ngui 3.7.0

    《NGUI 3.7.0:Unity开发插件的深度解析与应用指南》 NGUI,全称为Next-Gen User Interface,是一款专为Unity3D游戏引擎设计的UI开发插件,它提供了丰富的界面元素和强大的交互功能,极大地简化了开发者在创建用户...

Global site tag (gtag.js) - Google Analytics