Unity_UGUI|通向UGUI源码的入口VertexHelper

为什么要介绍VertexHelper(顶点帮助器)这个类。他在UGUI中起到了至关重要的地位。当然不了解这个类,对于使用UGUI没有任何影响。他只是看懂UGUI源码的一个基础。不看点源码,怎敢说自己精通。

前言

UGUI是图形学渲染和射线检测这两个技术结合的典型例子。图形学渲染来处理UI的显示,射线用来交互。

今天我们主要看看UI的渲染。
首先介绍一点图形学的基础知识:
1、所有的渲染对象都是由网格(Mesh)构成,Mesh的绘制单位是图元(点、线、三角形)。意思也就是说所有的游戏对象都是在绘制一些点、线、三角形的集合。

具体是如何一步一步显示到屏幕上的,可以看之前的一篇博文(实时渲染(第四版)_第2章|图形渲染管线总结):https://www.jianshu.com/p/2d8eeec9d0ef

2、顶点数据中最主要的是位置,颜色,纹理坐标,法线等。也就是说顶点中保存着其位置、颜色、纹理坐标、法线信息等。

3、贴纹理是指,将一张纹理(可以称为图片),根据纹理坐标,贴在模型上面。就好比同一个模型人,穿上了不同的衣服。纹理坐标指的是根据坐标将图片信息覆盖在Mesh表面,就相当于,柚子就贴在手腕处,裤子就贴在腿上。

正文

UGUI提供了我们自己构建顶点、三角形的类,那就是VertexHelper类。通过这个类,我们可以创建顶点,构成三角形,填充到一张mesh上,然后用MeshRenderer渲染到屏幕上,实际上我们可以直接操作Mesh类添加顶点、三角形等操作,这里的vertexHelper只是UGUI与Mesh之间的一座桥梁。

实践

接下来 我们尝试用这种办法在空物体上画出一张image图片。

首先在Unity中添加一个空对象,命名Image,Image对象需要添加MeshFilter组件,用来添加Mesh,还需要添加MeshRenderer组件,用来渲染Mesh,使其能够在屏幕中显示。

创建CreateImage.cs脚本,并挂载在Image上。
在脚本中添加Create函数,并有vertexHelper构造4个顶点(矩形):

        VertexHelper vp = new VertexHelper();
        vp.Clear();
        //这里采用的添加顶点函数,函数参数分别对应了顶点位置,顶点颜色,纹理坐标
        vp.AddVert(new Vector3(0, 0, 0), Color.red, new Vector2(0, 0));
        vp.AddVert(new Vector3(0, 1, 0), Color.green, new Vector2(0, 1));
        vp.AddVert(new Vector3(1, 1, 0), Color.blue, new Vector2(1, 1));
        vp.AddVert(new Vector3(1, 0, 0), Color.cyan, new Vector2(1, 0));

接下来,我们用4个顶点构造出矩形的两个三角形:

        vp.AddTriangle(0, 1, 2);
        vp.AddTriangle(2, 3, 0);

我们知道矩形最少是由两个三角形构成的,当然我们可以构造更多的三角形去显示一个矩形,但是这样不仅显得多余,而且对于计算机来说计算量就会上升。同时我们要注意:

Unity默认是只渲染物体的正面,背面是不渲染的。这里就涉及到构造三角形的顺序。在Unity中以顺时针方向构造三角形,这个三角形就是正面,就被会参与渲染的计算,逆时针就是背面,最终不会显示到屏幕上。

如何看三角形是顺时针还是逆时针呢。从构造三角形的三个顶点顺序(A、B、C),第一个顶点A为基准,然后指向第二个顶点B划线AB,这根线沿着第二个顶点B到第三个顶点C的连线BC扫描,扫描的方向是顺时针即为正面,逆时针即为背面(当然这个规定只是Unity的规定,其他地方要看所用的图形接口是如何规定的)。

接下来,我们填充到一张Mesh上,并将这个Mesh赋值为空物体Image的MeshFilter上。

        meshFilter = this.GetComponent();
        Mesh mesh = new Mesh();
        vp.FillMesh(mesh);
        meshFilter.mesh = mesh;

然后我们运行游戏:


vp1.gif

可以看到有一个紫色的方块从无到有。可能有小伙伴就有疑问了,创建的顶点不是紫色的啊,这是因为MeshRender渲染时候无材质的默认颜色。在来看看官方的解释:


vertexcolor.png

意思就是大部分的shder都不会显示顶点颜色,用一个可以显示顶点颜色的shader比如, partice shader去观察顶点颜色。
这时候随便用partice下的shader创建一张材质,赋给meshrender,再运行一遍就可以看到顶点颜色了。


mat.png

顶点效果就出来了:


vp2.gif

4个顶点的颜色是已知的,中间的颜色是插值得到的。具体原理还是在上文链接中有详细介绍。

当然我们也可以用Material中的颜色或者一张图片,给mesh贴上纹理,就相当于给Mesh穿上纯色或者有图案的衣服。全部代码如下:

    private MeshFilter meshFilter;
    private MeshRenderer render;
    public Texture tex;

    void Start()
    {        
        meshFilter = this.GetComponent();
        render= this.GetComponent();
        CreateAImage();
    }

    void CreateAImage()
    {
        VertexHelper vp = new VertexHelper();
        vp.Clear();
        //这里采用的添加顶点函数,函数参数分别对应了顶点位置,顶点颜色,纹理坐标
        vp.AddVert(new Vector3(0, 0, 0), Color.red, new Vector2(0, 0));
        vp.AddVert(new Vector3(0, 1, 0), Color.green, new Vector2(0, 1));
        vp.AddVert(new Vector3(1, 1, 0), Color.blue, new Vector2(1, 1));
        vp.AddVert(new Vector3(1, 0, 0), Color.cyan, new Vector2(1, 0));

        vp.AddTriangle(0, 1, 2);
        vp.AddTriangle(2, 3, 0);

        Mesh mesh = new Mesh();
        vp.FillMesh(mesh);
        meshFilter.mesh = mesh;

        //设置颜色或者纹理(这里的设置会覆盖Mesh的颜色)
        //想象你穿衣服是不是就把你的肤色盖着了
        //render.material.color = Color.red;
        render.material.mainTexture = tex;
    }

最终效果:


vp3.gif

举一反三:

想象一下圆,他同样是有三角形来构成的,我们可以用10个三角形构成一个圆,也可以用1000个三角形构成。下面我们看看三角形数量有什么差别。
直接上主要代码:

void CreateCircle()
    {
        VertexHelper toFill = new VertexHelper();
        toFill.Clear();
        //首先添加圆心
        toFill.AddVert(new Vector3(0, 0, 0), Color.white, new Vector2(0.5f, 0.5f));
        //计算单位三角形的角度
        float theta = 2 * Mathf.PI / triCount;

        for (int i = 0; i < triCount; i++)
        {
            //玩的特殊的,顶点颜色都不一样
            Color color = Color.Lerp(Color.blue, Color.red,  (float)i / (triCount-1));
            //计算每个顶点的位置
            float X = Mathf.Sin(2 * Mathf.PI-i * theta);
            float Y= Mathf.Cos(2 * Mathf.PI-i * theta);
            //radius为半径
            toFill.AddVert(new Vector3(X*radius, Y*radius, 0), color, new Vector2(X, Y));
        }
        //添加三角形
        for (int i = 1; i < triCount; i++)
        {
            toFill.AddTriangle(0, i, i + 1);
        }
        toFill.AddTriangle(0, triCount, 1);
        Mesh mesh = new Mesh();
        toFill.FillMesh(mesh);
        meshFilter.mesh = mesh;
    }

看看效果:


10.png
1000.jpg

上面分别是10面和1000面的效果。
实际上36个三角形已经可以构造出很圆的圆形了。大量的三角形渲染会增加GPU负担。这也是在游戏开发中,美术为什么要限制模型的顶点与三角形数量的原因。
我们还可以搞点不一样的。想想下面是如何实现的。


vp5.gif

小结

知识点:了解VertexHelper的用法。VertexHelper有助于我们理解UGUI源码。而且我们熟悉了VertexHelper的用法后,甚至可以随心所欲的制作出独特的UI。

你可能感兴趣的:(Unity_UGUI|通向UGUI源码的入口VertexHelper)