首页 > UI, 其他 > 【UGUI源码分析】五、Graphic和UI特效

【UGUI源码分析】五、Graphic和UI特效

2018年11月8日
目录
[隐藏]

主要类:GraphicRegistry, GraphicRaycaster, Graphic, VertexHelper
辅助类:BaseMeshEffect, Shadow, Outline, PositionAsUV1
接口:ICanvasElement, IMeshModifier, IMaterialModifier

Graphic是UGUI中的重要组件,在之前总结EventSystem中提到GraphicRaycaster做射线检测,Graphic的派生类(Image、RawImage、Text)是UGUI中唯一的显示元素,以及唯一的可直接交互接受键盘、鼠标、手柄并产生消息的组件。其他组件比如Button、ScrollRect、Toogle、InputField等都需要通过添加一个Graphic组件获得交互消息。

Graphic本身继承自UIBehaviour,也就是说它可以收到上一篇文章中的那些回调函数(是非常有用且重要的)。

 

1. GraphicRegistry

Unity使用一个注册表GraphicRegistry来统计场景内所有的Graphics,以备做射线检测。GraphicRegistry的数据是一个字典

这个注册表本身实现比较简单,包含注册、注销、获取方法。m_Graphics的键是Graphic所属的最近的一个包含Canvas的父节点。

 

2. GraphicRaycaster

GraphicRaycaster派生自BaseRaycaster,实现了Raycast()方法。遍历所有CanvasRegistry中保存的Canvas的Graphic,最终会调用Graphic.Raycast方法,直到找到对应的Graphic,会对这些graphic根据depth做排序,depth最大最深的graphic是射线检测的结果,具体在GraphicRaycaster.Raycast()方法。

GraphicRaycaster处理了不同RenderMode类型的canvas,能够处理overlay, camera space 和world space的canvas。针对不同类型的canvas使用不同的射线检测方法。具体的看代码,这里不展开讨论细节。重点看Graphic类本身。

 

3. Graphic

Graphic是所有可视UI元素(即有材质的,包含image, raw image, text)的基类。

1) 数据成员

Graphic的主要数据包括贴图、材质、颜色、Mesh数据和所属的Canvas以及CanvasRenderer

① 贴图,包括一张公共的白色贴图和此UI元素的图片

② 材质,包括一个公共的默认UI材质和

③ 颜色,注意这个颜色是顶点颜色,而不是shader中某个颜色变量(之前一直以为是有个_Color之类的变量)

④ 网格数据,是两个公共的静态数据,s_Mesh用来设置给canvasRenderer,s_VertexHelper是辅助设置mesh数据的中间结构

⑤ 从属的canvas以及CanvasRenderer

贴图、mesh、材质最终会在UpdateMaterial()和UpdateGeometry()两个方法中设置进CanvasRenderer。

2) Rebuild

Graphic实现了ICanvasElement接口,根据之前Canvas文章所写,也就是说会在willRenderCanvases的时候Rebuild。Graphic的重建只发生在CanvasUpdate.PreRender阶段,涉及网格数据更新和材质更新

UpdateGeometry()和UpdateMaterial()分别是刷新网格和材质的方法。这里有两个脏标记m_VertsDirty和m_MaterialDirty用来标记CanvasUpdate.PreRender阶段是需要刷新网格还是材质。Graphic中有3个方法SetVerticesDirty,SetMaterialDirty和SetAllDirty用来将Graphic注册到CanvasUpdateRegistry的队列里并标记网格或材质数据需要rebuild。

Graphic更新流程

整个更新的流程是

  1. Graphic在合适的时机调用SetXXXDirty()方法,注册进CanvasUpdateRegistry里
  2. 管线在Canvas.willRenderCanvases时调用CanvasUpdateRegistry中注册的Graphic的Rebuild方法
  3. Graphic在Rebuild方法中调用UpdateGeometry()或UpdateMaterial()重建网格或材质,设置到Graphic对应的canvasRenderer里
  4. 管线调用canvasRenderer渲染Graphic

Graphic具体调用SetXXXDirty()的时机有

  1. OnRectTransformDimensionsChange(),即大小改变的时候
  2. OnTransformParentChanged(),即父节点层级改变的时候
  3. OnDidApplyAnimationProperties(),即通过animation clip改变属性值的时候
  4. 设置材质的时候
  5. OnEnable()
  6. OnValidate()
  7. Reset()

需要关注在UpdateGeometry和UpdateMaterial中,会尝试执行自定义修改流程,即同一个GameObject上实现了IMeshModifier或IMaterialModifier接口的组件

这两个接口非常有用,通过实现IMeshModifier或者IMaterialModifier可以修改网格和材质,用来做UI特效

UGUI本身包含了3种常见的UI特效Outline, PositionAsUV1, Shadow通过继承BaseMeshEffect实现。

 

4. UI特效

UI特效是整个UI开发中非常核心的内容,根据美术设计实现相应的UI特效比如流光、泛光、溶解、阴影等等。UI特效是体现游戏品质的一大因素,有UI特效的UI相比死板的静态UI更好。

UGUI包含了3个常见的UI特效,Outline描边、Shadow阴影和PositionAsUV1镂空效果。这三个效果都会派生自BaseMeshEffect基类,基类会做一些将Graphic加到Rebuild队列的工作,并且需要实现IMeshModifier接口中定义的方法

VertexHelper是UGUI定义的网格数据辅助中间结构,之前的版本中直接是Mesh,但是Mesh中UI层面无关数据太多,VertexHelper是Mesh的精简版,等提交canvasRenderer的时候再用VertexHelper填充一个Mesh。VertexHelper中的数据包括坐标、颜色、4套UV、法线、切线和三角形

默认情况下,UV的网格数据只开启了position, color, uv0, indices这4个,如果需要第2套UV或者法线、切线需要在canvas上开启

简单说一下outline,shadow和positionAsUv1这3个效果UGUI的实现。Shadow通过增加三角形并偏移实现,outline是通过4个shadow实现,position就是简单的设置UV1为position。

自定义UI特效可以通过继承BaseMeshEffect或者继承UIBehaviour并实现IMeshModifer和IMaterialModifier接口来实现。

 

5. 自定义和扩展

1) 派生Graphic

Graphic是所有可视UI元素的基类

Base class for all visual UI Component. When creating visual UI components you should inherit from this class.

也是唯一可以做射线检测的UI元素。UGUI共提供了3个派生类Image、RawImage和Text,后面的文章再看。

Graphic通常被重写的虚方法主要是2个

此外要注意在构造函数里设置 useLegacyMeshGeneration = false ,使用VertexHelper而不是Mesh结构。

Unity官方给了一个基础Graphic类绘制方块的例子

可以一起实现的接口有IMeshModifer, IMaterailModifier, ICanvasRaycastFilter, ILayoutElement等

2) 自定义UI特效

通过继承BaseMeshEffect或者UIBehaviour并实现IMeshModifier和IMaterailModifier。需要注意如果需要使用额外的顶点属性,需要在canvas开启Additional Shader Channel。

 

https://docs.unity3d.com/2018.1/Documentation/ScriptReference/UI.Graphic.html

分类: UI, 其他 标签: