UGUI六芒星

发表于2016-06-28
评论0 4k浏览

   游戏中为了展现角色属性,突出职业特点,经常用到“六芒星”,玩家可以根据六芒星的形状,更好的分析当前角色的属性和特点,如图:

   最近正在研究UGUI,为了理解UGUI组织顶点渲染的机制,就用UGUI实现了一套“六芒星”。

   在Canvas节点下,所有显示的UI控件都有一个CanvasRenderer组件,这个组件就是用来组织UI控件顶点的。CanvasRenderer有设置Mesh的接口,通过角色的属性,构建出六芒星mesh,并传递给CanvasRenderer,使其符合UGUI渲染机制(深度,Order等)统一渲染。

   Unity提供渲染网格接口类就是Mesh,通过Mesh我们可以设置顶点属性(位置,uv,颜色等),以及Mesh的顶点索引数组,就可以构建一个完整的Mesh对象了。为了使其在Canvas中正常显示,我们实例化一个Shader作为Material对象,赋值到CanvasRenderer组件对象中,即可完成渲染。

   我们以六芒星为例,六芒星将平面360度平均划分为6份,每份60度,即可确定每个属性的方向,再根据属性的值(相当于向量的模),就可以得到对应的“属性向量”,将6个属性向量的终点连在一起,就可以渲染出整体的六芒星。

  为了便于扩展六芒星为“五芒星”,“七芒星”等,我们允许设置以下几个属性:

  startDirection:第一个属性的方向,通过这个方向值以及每个属性之间的角度,可以得到其他属性的方向。

  attributes:属性数组,数组的长度表示了“N芒星”。

  fullStrength:满属性值,通过属性值/满属性值,可以得到这个属性的比例,用于构建六芒星UI控件。

1
2
3
4
5
6
// 起始方向
    public Vector3 startDirection = new Vector3(0, 1, 0);
    // 星属性
    public int[] attributes = null;
    // 最大值
    public float fullStrength = 100f;

  通过将360度平均划分为N份,以及向量旋转公式,可以得到每个属性的方向向量,算法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 获取每个属性点的方向向量
        int starsCount = this.attributes.Length;
        List directionList = new List(starsCount);
        float deltaAngle = this.circle / starsCount;
        for (int i = 0; i < attributes.Length; ++i)
        {
            float angle = i * deltaAngle;
            float rad = Mathf.Deg2Rad * angle;
            float sinA = Mathf.Sin(rad);
            float cosA = Mathf.Cos(rad);
            directionList.Add(new Vector3(startDirection.x * cosA + startDirection.y * sinA,
                -startDirection.x * sinA + startDirection.y * cosA, 0));
        }

   接下来计算六芒星中各顶点的位置,要构建六芒星,除了每个属性的顶点外,还需要一个中心点。属性点根据每个属性的方向(单位向量)*属性值可得,算法如下:

1
2
3
4
5
6
7
8
9
10
11
Mesh mesh = new Mesh();
        // 设置顶点位置属性
        int verticesCount = starsCount + 1;
        List vertices = new List(verticesCount);
        vertices.Add(Vector3.zero);
        for (int i = 1; i < verticesCount; ++i)
        {
            int index = i - 1;
            vertices.Add(directionList[index] * this.attributes[index] / this.fullStrength * rectTransform.sizeDelta.x);
        }
        mesh.SetVertices(vertices);

  为了表现更丰富一点,我们为每个属性设置一个颜色,属性的颜色值根据属性强度变深,算法如下:

1
2
3
4
5
6
7
8
9
10
11
// 设置颜色属性
        List colors = new List();
        colors.Add(new Color32(255, 255, 255, 255));
        for (int i = 0; i < starsCount; ++i)
        {
            float strength = attributes[i] / rectTransform.sizeDelta.x;
            byte r = (byte)(strength * 200);
            Color32 c = new Color32(r, 0, 0, 255);
            colors.Add(c);
        }
        mesh.SetColors(colors);

  Mesh对象的顶点属性设置完成后,还要为顶点设置索引数组,六芒星网格是由6个三角形构建而成,这6个三角形有一个共点(中心点),通过中心点及任意两个相邻的属性顶点组成6个三角形,算法如下:

1
2
3
4
5
6
7
8
9
10
11
// 设置索引属性
        int[] indices = new int[3 * starsCount];
        for (int i = 0; i < starsCount; ++i)
        {
            int index = 3 * i;
            indices[index] = 0;
            indices[index + 1] = i + 1;
            indices[index + 2] = (i + 2) > starsCount ? (i + 2 - starsCount) : (i + 2);
        }
        mesh.SetIndices(indices, MeshTopology.Triangles, 0);
        canvasRenderer.SetMesh(mesh);

最后设置材质

1
2
Material material = new Material(Shader.Find("UI/Default"));
        canvasRenderer.SetMaterial(material, null);

效果如下图

源码地址 

原文地址 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引