NGUI框架

NGUI有三大基础机制支撑整个NGUI的显示和交互,这三大机制分别是:渲染机制事件、消息机制、间隔动画

渲染机制事件

  1. 基础介绍
    NGUI的UIWidget、UIDrawCall、UIGeometry和UIPanel等基础脚本
    • UIWidget是UI的基础组件(UILabel,UISprite)的基类,含有组件的基本信息(width,Height,color,AnchorPoint等)
    • UIGeometry 是UIWidget的几何数据,记录了顶点坐标,贴图的UVS和颜色等信息
      • 存储顶点、UV、Color、相对父节点的位移数据
      • 向Buffer写数据
    • UIDrawCall是将多个UIWeiget的UIGeometry组合起来一起回执
      • drawcall是啥?其实就是对底层的图形程序(比如:OpenGL ES)接口的调用,以在屏幕上画出东西,所以,是谁去调用这些接口呢?GPU,Unity每次在准备数据并通知GPU渲染的过程称为一次Draw Call,一般情况下,渲染一次拥有一个网格并携带一种材质的物体便会使用一次Draw Call,对于渲染场景中的这些物体,在每一次DrawCall中除了在通知GPU的渲染上非常耗时之外,切换材质与shader也是非常耗时的操作。这个值可以在Game视图窗口的status面板查看。
      • 有一次我们发现NGUI的UIPanel.LateUpdate函数的CPU开销非常大。仔细研究之后,发现是合并了太多的DrawCall所致,尤其是将运行时会运动变化的UI控件和静止不变的UI控件的DrawCall合在了一起。当一个UI控件(UIWidget)的位置、大小或颜色等属性发生变化时,UIPanel就需要重建这个控件所用的DrawCall,某些情况下还要重建Panel上的所有DrawCall。有时重建一个DrawCall会消耗不少CPU开销,它需要重新计算这个DrawCall上所有控件的顶点信息,包括顶点位置、UV和颜色等。如果很多控件都集中在同一个DrawCall上,那么只要一个控件有一点点变化,这个DrawCall上的所有控件的顶点就都要重新遍历一边;而我们的UI又大量采用了九宫格拉伸,使控件的顶点数量变得更多,因此重建一个DrawCall的开销就更大。
          因此我们将UI控件分组,将一段时间内会发生变化的控件——比如怪物头顶的血条和伤害跳字放在同一个Panel上,并且这个Panel上只有这些控件,其余基本不变化的控件就放在别的Panel上。这样两类控件就被隔开到不同的DrawCall不同的Panel中,当一个控件发生变化而导致DrawCall重建时,就不需要遍历那些没有变化的控件。因为在美术设计上,一段时间内在变化的控件总是少数,所以优化效果十分明显,节省的CPU占用率能达到25%。
      • 减小DrawCall的思路:对DrawCall的优化,主要是为了尽量解放CPU在调用图形接口的开销上,所以针对drawcall我们的思路就是每个物体尽量减少渲染次数,多个物体最好一起渲染,所以这个思路有一下几个解决方案:
        • 使用drawcal batching,也就是描述调用批处理,unity在运行时可以将一个物体进行合并,从而用一个描绘来渲染他们
        • 通过把纹理打包成图集来尽量减少材质的使用
        • 尽量少的使用反光,阴影之类的
    • UIPanel 用于管理UIWeiget、UIDrawCall等,实现界面的渲染剪裁、更新
      • 对所有widget进行排序、更新、生成widget的几何数据
      • 负责管理DrawCall、Widget
      • 根据深度值进行渲染顺序的排序
      • 有Clipping功能(ScrollView)
      • SetDerty()影响所有的子节点,在下一次update时所有的DrawCalls和Widget(Rect)重新计算alpha值
      • 在LateUpdate中更新所有的子Panels和Widgets还有DrawCalls
      • 在FillDrawCall中遍历Widgets将材质、纹理、着色器相同的并且连续Widget中的Geometroy数据填充到一个DrawCall上并将DrawCall与Widget关联,将不可见的,没有顶点数据的Widget的DrawCall设置为null。
    • UIRoot UI界面的根目录,用于分辨率适配和事件广播
      • 屏幕自适应
      • 所有UIRect的root

消息机制

  • 基础介绍
      UICamera:真正做的事情是发送NGUI事件给所有被当前camera渲染的object,camera是UICamera脚本所在的那个。 其实这个脚本做的事情和UI无关。事实上如果你想让游戏里面的object接收OnPress、OnClick、OnDrag等这类事件,你需要把UICamera挂在你的主相机上。游戏场景里面可以有多个UICamera。大多数游戏一个挂在渲染widget的相机上,一个挂在渲染游戏的相机上。UICamera发送以下事件给collider,用他们到自己的脚本里面,只要实现相应的函数即可:
    Ø OnHover (isOver) 发送时机为鼠标悬停(只触发一次)或者离开collider。
    Ø OnPress (isDown) 发送时机为鼠标在collider上按下。
    Ø OnSelect (selected)发送时机为鼠标点击和松开的时候都在同一个object上。
    Ø OnClick ()发送时机和OnSelect一样,但是要求鼠标没有移动特别多。UICamera.currentTouchID表示按下的鼠标哪个键。
    Ø OnDoubleClick ()发送时机为当在四分之一秒内click两次的时候。UICamera.currentTouchID表示按下的鼠标哪个键。
    Ø OnDragStart ()发送时机为OnDrag()事件之前。
    Ø OnDrag (delta) 发送时机为一个object被拖拽。
    Ø OnDragOver(draggedObject)发送时机为其他的object拖拽到他的上面。
    Ø OnDragOut (draggedObject)发送时机为其他的object拖拽出他的上面。
    Ø OnDragEnd ()发送时机为drag事件结束。发送给被拖拽的object。
    Ø OnInput (text)发送时机为输入的时候(在点击选择了一个collider之后)。
    Ø OnTooltip (show) 发送时机为鼠标悬停在一个collider上一段时间没有移动。
    Ø OnScroll (float delta)发送时机为鼠标滚轮滚动。
    Ø OnKey (KeyCode key)发送时机为键盘或者输入控制器被使用的时候。

事件接受函数如下:

void OnPress (bool isPressed)
{
if (isPressed)
Debug.Log("I was pressed on!");
else
Debug.Log("I was unpressed");
}

- 监听和分发
  在Update()中,依次处理 触摸/点击,文本输入,键盘/摇杆输入,Tip。
  其中最主要的就是 触摸/点击 事件的处理了,下面以触摸事件处理ProcessTouches()来分析。
  第一步:从Input节点中,获取触摸/点击的信息为Touch类。
  第二步:根据Touch类的信息,分析出可能事件。
  第三步:通过物理的射线检测即(Physics.RaycastAll)找出来对应UI使用的Collider,并把Collider所在的Gameobject作为触发事件的对象。
  第四步:把消息事件转化成按照实现相应的函数调用。
  第五步:在控件所对应的脚本中实现对应的函数,便可以收到来自于UICamara的调用,并做相应的处理(如:UIButton)
  第六部:把静态的Current变量设置为当前的控件脚本,把使用SentMessage或EventDelegate.Excute再次分发出去。如:UIToggle.OnChange

间隔动画Tween

间隔动画:对对象的某一个变量,使这个变量在一定时间段内,每一帧按照预先指定曲线变化,从而形成一段动画。如:屏幕颜色的渐变、屏幕抖动、对象的运动等等。

  • UITweener

是实现NGUI中间隔动画的基础。间隔动画的基类,所有间隔组建都继承该类,用于执行update()。所有的继承了都需要从Begin开始。继承类中主要函数是OnUpdate,用于处理每帧的更新处理。在Begin开启后,当前脚本状态会被设为true,在运行结束之后,又会设置为false。

  • UIPlayTween

:这个脚本管理一组Tween脚本的Play,提供了不同的Tirgger,然后在不同的事件函数中触发Play(true)


参考知识:

1.什么是UV?

对于三维模型,有两个最重要的坐标系统,一是顶点的位置(X,Y,Z)坐标,另一个就是UV坐标。什么是UV?简单的说,就是贴图影射到模型表面的依据。 完整的说,其实应该是UVW(因为XYZ已经用过了,所以另选三个字母表示)。U和V分别是图片在显示器水平、垂直方向上的坐标,取值一般都是0~1,也 就是(水平方向的第U个像素/图片宽度,垂直方向的第V个像素/图片高度)。那W呢?贴图是二维的,何来三个坐标?嗯嗯,W的方向垂直于显示器表面,一般 用于程序贴图或者某些3D贴图技术(记住,确实有三维贴图这种概念!),对于游戏而言不常用到,所以一般我们就简称UV了。

所有的图象文件都是二维的一个平面。水平方向是U,垂直方向是V,通过这个平面的,二维的UV坐标系。我们可以定位图象上的任意一个象素。但是一个问题是如何把这个二维的平面贴到三维的NURBS表面和多边形表面呢? 对于NURBS表面。由于他本身具有UV参数,尽管这个UV值是用来定位表面上的点的参数,但由于它也是二维的,所以很容易通过换算把表面上的点和平面图象上的象素对应起来。所以把图象贴带NURBS是很直接的一件事。但是对于多变形模型来讲,贴图就变成一件麻烦的事了。所以多边形为了贴图就额外引进了一个UV坐标,以便把多边形的顶点和图象文件上的象素对应起来,这样才能在多边形表面上定位纹理贴图。所以说多边形的顶点除了具有三维的空间坐标外。还具有二维的UV坐标。

UV” 这里是指u,v纹理贴图坐标的简称(它和空间模型的X, Y, Z轴是类似的). 它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. 在点与点之间的间隙位置由软件进行图像光滑插值处理. 这就是所谓的UV贴图.

那为什么用UV坐标而不是标准的投影坐标呢? 通常给物体纹理贴图最标准的方法就是以planar(平面),cylindrical(圆柱), spherical(球形),cubic(方盒)坐标方式投影贴图.

Planar projection(平面投影方式)是将图像沿x,y或z轴直接投影到物体. 这种方法使用于纸张, 布告, 书的封面等 - 也就是表面平整的物体.平面投影的缺点是如果表面不平整, 或者物体边缘弯曲, 就会产生如图A的不理想接缝和变形. 避免这种情况需要创建带有alpha通道的图像, 来掩盖临近的平面投影接缝, 而这会是非常烦琐的工作. 所以不要对有较大厚度的物体和不平整的表面运用平面投影方式. 对于立方体可以在x, y方向分别进行平面投影, 但是要注意边缘接缝的融合. 或者采用无缝连续的纹理, 并使用cubic投影方式. 多数软件有图片自动缩放功能, 使图像与表面吻合. 显然, 如果你的图像与表面形状不同, 自动缩放就会改变图像的比例以吻合表面. 这通常会产生不理想的效果, 所以制作贴图前先测量你的物体尺寸.
链接:http://www.cnblogs.com/jenry/p/4083415.html

2、纹理,贴图,材质的区别?

材质 Material包含贴图 Map,贴图包含纹理 Texture。

纹理是最基本的数据输入单位,游戏领域基本上都用的是位图。此外还有程序化生成的纹理 Procedural Texture。

贴图的英语 Map 其实包含了另一层含义就是“映射”。其功能就是把纹理通过 UV 坐标映射到3D 物体表面。贴图包含了除了纹理以外其他很多信息,比方说 UV 坐标、贴图输入输出控制等等。

材质是一个数据集,主要功能就是给渲染器提供数据和光照算法。贴图就是其中数据的一部分,根据用途不同,贴图也会被分成不同的类型,比方说 Diffuse Map,Specular Map,Normal Map 和 Gloss Map 等等。另外一个重要部分就是光照模型 Shader ,用以实现不同的渲染效果。
链接:https://www.zhihu.com/question/25745472

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值