(六)Graphic与MaskableGraphic详解

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类重点方法的详细分析。

posted @ 2020-04-06 10:37  81192  阅读(836)  评论(0编辑  收藏  举报