1.前言
此篇将对UGUI系统中图像显示的核心Graphic类进行详细分析
2.重点方法分析
基本流程已经在CanvasUpdate一文中的2.1和2.2节分析过了。即每帧在进行Canvas渲染前通过CanvasRenderer更新mesh和材质等信息,渲染时根据这些信息进行相应渲染。所以UI渲染的基本模块是Canvas。本文对一些核心方法进行详解。
2.1 GraphicRegistry
此类有别与GraphicUpdateRegistry,一个只是纯粹用来存储本Canvas下Graphic对象。另一个则是用来更新Canvas,设置Canvas的渲染问题。GraphicReigstry目前只在射线检测中(GraphicRaycaster)使用,即用来获取特定Canvas下的Graphic列表。
2.2 标记Graphic重建
标记Graphic重建是通过SetMaterialDirty和SetMeshDirty来标记的。两者均是与Graphic渲染相关的。Layout布局重建相关的则是SetLayoutDirty来标记的。
2.2 材质Material
材质分为三个默认材质、材质和渲染材质。优先使用渲染材质,如果没有mask组件则渲染材质和材质相同,最后是默认材质。如果没有指定材质,则使用默认材质。
默认材质:defaultGraphicMaterial是最备选方案,备胎材质。
材质:material是指定的材质,一般情况下使用的是此材质。
渲染材质:materialForRendering一般情况下此材质与material相同,如果存在Mask或者继承IMaterialModifier的组件,则会进行材质修改以达到遮罩的效果。
2.3 重构Rebuild
Rebuild是Graphic的核心,即通过Rebuild来实现材质、网格等的修改,其流程如下:
1)剔除,如果CanvasRenderer.cull,则直接退出。
2)如果标记几何(mesh)更新,则进行网格更新(DoMeshGeneration),通过OnPopulateMesh来更新mesh,这也是自定义网格时经常用到的。可以自定义组件继承Graphic,然后重写OnPopulateMesh来自定义网格形状,结合VertexHelper可进行UIMesh的各种样式定制,比如游戏角色的属性图、饼状图、柱状图以及各种函数曲线。
3)如果标记材质更新,则更新Material以及贴图等信息。
2.3.1几种OnPopulateMesh
1)Graphic默认方法
protected virtual void OnPopulateMesh(VertexHelper vh)
{
var r = GetPixelAdjustedRect();
var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
Color32 color32 = color;
vh.Clear();
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0f, 0f));
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0f, 1f));
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(1f, 1f));
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(1f, 0f));
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}
2)RawImage重写mesh方法
protected override void OnPopulateMesh(VertexHelper vh)
{
Texture tex = mainTexture;
vh.Clear();
if (tex != null)
{
var r = GetPixelAdjustedRect();
var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
var scaleX = tex.width * tex.texelSize.x;
var scaleY = tex.height * tex.texelSize.y;
{
var color32 = color;
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(m_UVRect.xMin * scaleX, m_UVRect.yMin * scaleY));
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(m_UVRect.xMin * scaleX, m_UVRect.yMax * scaleY));
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(m_UVRect.xMax * scaleX, m_UVRect.yMax * scaleY));
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(m_UVRect.xMax * scaleX, m_UVRect.yMin * scaleY));
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}
}
}
3)Image方法
image由于涉及到许多不同的表现形式,所以比较复杂,此处就不贴代码了。
2.4 遮罩效果
UGUI可以通过遮罩只显示部分图像(遮罩详细流程参考此文2.3节),这之中分为Mask和RectMask2D,前者使用像素级别的检测,原理是根据GPU模板检测实现的,后者只能实现Rect遮罩,通过CanvasRenderer实现,所以Mask能达到更多的效果,但是性能消耗更高。如果想了解Mask的原理,可参考(一)、(二)、(三)个文献。
2.4.1 Mask
Mask的实现流程比较简单,只要Graphic继承IMaskable, IMaterialModifier两个接口即可(Mask以及MaskableGraphic)。IMaterialModifier的作用是通过修改该材质来达到模板检测剔除的功能。而IMaskable则是上层逻辑接口。即当Mask生效时,会通知所有的的子游戏物体的IMaskable组件RecalculateMasking,来实现所有子游戏物体的遮罩功能。
2.4.2 RectMask2D
Rect遮罩则比较麻烦,需要Graphic继承实现IClippable接口。当RectMask2D生效时,会通知所有的子游戏物体的IClippable组件进行RecalculateClipping,然后通过SetClipRect设置EnableRectClipping,通过Cull方法进行操作。
3.结语
以上为Graphic类重点方法的详细分析。