Unity利用UGUI中Graphic绘制曲线图

我们在创建可视UI组件时,可以通过继承Graphic来实现一些UI上的绘制功能。官方案例 中通过重写了 OnPopulateMesh 函数实现了一个绘制彩色四边形的效果。
利用该方法,结合一些对地形数据的处理,我们可以制作像下图这样的地形剖面图效果:

Unity利用UGUI中Graphic绘制曲线图_第1张图片

主要思路

Graphic 是UGUI的核心组件,附件画面的显示。关于其原理,可以参考大佬博客,这里我们只谈谈几个小细节与关键步骤。

首先, UIVertex是用来管理UI顶点的一个结构体,我们可以将我们计算所得的顶点的位置信息存在这个结构体中(它是以像素为单位的)。
其次,右上角的剖面图上显示的变化的线其实是由诸多小矩形组成。我们在计算好顶点位置,给UIVertex赋值完之后,便可调用VertexHelper.AddUIVertexQuad(UIVertexs) 来将一个矩形加入到渲染中。
最后,我们需要调用刷新函数,SetAllDirty() 是分别设置Layout布局、Vertices顶点和Material材质为Dirty。我们这里只需要调用SetVerticesDirty()即可(每次修改参数都要调用其刷新)。

这边提供一个顶点数据设置的函数实现,另外的坐标轴、刻度线、坐标轴箭头等的实现方式类似。


        [Header("坐标轴显示属性")]
        public float width = 200;
        public float height = 200;
        public float lineWidth = 5;
        public Vector2 offset = new Vector2(2, 2);
        
        [Header("坐标轴数据属性")]
        public Vector2 axleMaxValue = new Vector2(100, 100);
        public Vector2 axleMinValue = Vector3.zero;
        public List<Vector2[]> datas = new List<Vector2[]>();
   
        /// 
        /// 设置顶点属性
        /// 
        private void SetData(VertexHelper vh)
        {
            foreach (var data in datas)
            {
                Vector2[] pixelPoints = new Vector2[data.Length];
                for (int i = 0; i < data.Length; i++)
                {
                    pixelPoints[i].x = (data[i].x - axleMinValue.x) / axleMaxValue.x * width;
                    pixelPoints[i].y = (data[i].y - axleMinValue.y) / axleMaxValue.y * height;
                    pixelPoints[i] += offset;
                }

                UIVertex[] verts = new UIVertex[4];
                for (int i = 0; i < verts.Length; i++)
                {
                    verts[i].color = Color.blue;
                }

                for (int i = 0; i < pixelPoints.Length - 1; i++)
                {
                    SetVerts(pixelPoints[i], pixelPoints[i + 1], lineWidth, verts);
                    vh.AddUIVertexQuad(verts);
                }

				// 设置UI顶点数据
                void SetVerts(Vector2 _start, Vector2 _end, float _width, UIVertex[] _verts)
                {
                    Vector2[] tmp = GetRect(_start, _end, _width);	 
                    _verts[0].position = tmp[0];
                    _verts[1].position = tmp[1];
                    _verts[2].position = tmp[3];
                    _verts[3].position = tmp[2];
                }
                
                // 获取两点组成的矩形边框, 起始点,终止点,宽度
        		Vector2[] GetRect(Vector2 _start, Vector2 _end, float _width)
        		{
            		Vector2[] rect = new Vector2[4];
            		Vector2 dir = GetHorizontalDir(_end - _start);	// 获取水平向右的向量
            		rect[0] = _start + dir * _width;
            		rect[1] = _start - dir * _width;
            		rect[2] = _end + dir * _width;
            		rect[3] = _end - dir * _width;
            		return rect;
       			}
            }
        }

至于数据的获取,我这边是利用两点间的距离和方向,每隔一小段距离取一个点,获取其在地表的高度。以距离和高度组成vector2数组作为参数赋值给datas。下面是个获取data的函数实现。

    /// 
    /// 获取起点到终点的高度分析
    /// 
    /// 起点
    /// 终点
    /// x为对应点到起点的距离,y为对应点的高度
    public Vector2[] GetHeights(Vector3 start,Vector3 end)
    {
        float dis = Vector3.Distance(start, end);
        Vector3 dir = (end - start).normalized;
        int count = (int)dis / 5;

        Vector2[] result = new Vector2[count + 1];
        for (int i = 0; i < count; i++)
        {
            Vector3 pos = TerrainUtility.GetPositionOnTerrain(start + dir * i * 5);
            result[i] = new Vector2(i * 5, pos.y);
        }
        result[count] = new Vector2(dis, TerrainUtility.GetPositionOnTerrain(end).y);

        return result;
    }

就酱。

你可能感兴趣的:(Unity)