• Unity UGUI 绘制优雅的线段


    Unity UGUI 绘制优雅的线段

    引言

    有时候,我们需要在unity中绘制线段,最常规的做法就是使用LineRenderer组件了。但有时候我们LineRenderer用起来并不那么适合,比如,我们需要在UI层绘制线段时,当然通过一系列的坐标转换,可以完美的将LineRenderer呈现在UI层,但总归不是很方便。这时候我们就可以自己写一些东西了。

    MaskableGraphic

    UI里面有这个类,只要我们重载它的OnPopulateMesh方法,就可以构造一些三角面,用于呈现任何形状。其实它很类似MeshFilter。主要用到两个方法:

    VertexHelper.AddVert			// 添加顶点
    VertexHelper.AddTriangle		// 添加三角面
    
    • 1
    • 2

    构造线的思路

    一段直线
    与数学意义上的线不同,在数学上,一条线段由两个端点确定,但在unity中,我们的线段必须要有宽度,否则无法显示,最基本的线段要有四个顶点,2个3角面,如上图所示。
    当我们给定线段的两个顶点时,计算4个顶点,并不难,只要知道线的宽度,通过一些方法很容易就能算出来,比如:

    // 首先计算线的方向
    Vector2 dir = EndPosition - StartPosition;
    
    // 然后将方向旋转90°。
    Vector2 left = (Quaternion.AngleAxis(90, Vector3.forward) * dir).normalized;
    
    // 然后就可以计算出四个顶点:
    Vector2 leftBottom = EndPostion + left * HalfLineWidth;
    Vector2 rightBottom = EndPostion + ( - Left * HalfLineWidth );
    Vector2 leftTop = StartPosition + left * HalfLineWidth;
    Vector2 rightTop = StartPosition + ( - left * HalfLineWidth );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    但是,实际中使用的线多半并不是直线,而是由很多点构成的线。那么就会存在问题:
    2
    如果使用上面的计算方法,在线段转弯的地方,无法避免两条线段的“弯外处”会出现缺口,而“弯内”处出现重叠。如何优雅的解决此问题呢。
    我的思路是:
    在这里插入图片描述
    如上图所示,分别求两段的方向(蓝色虚线),然后转90°得到黄色虚线,求平均,得到粉色实线。线段宽度的一半,除以cos(α),就能得到边缘的交点。具体代码如下:

    int count = positions.Count;
    int csub1 = count - 1;
    for (int i = 0; i < count; ++ i )
    {
    	int ia1 = i + 1;
    	int is1 = i - 1;
    	
    	if( i == 0 )
    	{
    		// 处理第一个节点
    	    FiristPoint(positions[i], positions[ia1], vh);
    	}
    	else if( i == csub1 )
    	{
    		// 处理最后一个节点
    	    LastPoint(positions[is1], positions[i], vh);
    	}
    	else
    	{
    		// 处理中间的节点
    	    MidPoint(positions[is1], positions[i], positions[ia1], vh);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    为了方便处理,分为三种情况进行处理,第一个节点没有前继节点,最后一个节点没有后继节点,单独拿出来处理一下,这样思路比较清晰。关键是中间的节点,按照上面的思路,代码如下:

    /// 
    /// 处理中间节点
    /// 
    /// 上一个顶点
    /// 当前顶点
    /// 下一个顶点
    /// 顶点管理器
    private void MidPoint(Vector2 prev, Vector2 cur, Vector2 next, VertexHelper vh)
    {
        Vector2 left1 = (orthogonality * (cur - prev)).normalized;
        Vector2 left2 = (orthogonality * (next - cur)).normalized;
    
        Vector2 left = ((left1 + left2) * 0.5f).normalized;
        float a = Vector2.Angle(left1, left2) * Mathf.Deg2Rad * 0.5f;
    
        float r = Radius / Mathf.Cos(a);
    
        vh.AddVert(cur + left * r, color, Vector2.zero);
        vh.AddVert(cur + left * -r, color, Vector2.zero);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    然后就完成了,就可以所心所欲的在GUI上构造线段了。如下所示:

    Unity UGUI MaskableGraphic绘制线段

    继续完善

    实际上可以完善的地方还有很多,但有了上面的基础,很容易就能扩充很多有意思的功能,比如,首尾节点可以搞成圆头状的,转弯的地方可以增加过度。还可以加入贝塞尔计算。最后,当然还可以设置每个顶点的UV!!在例子中没有去设置UV,但实际上AddVert方法支持UV设置。

  • 相关阅读:
    【C++--类和对象】开篇
    智慧校园-档案管理系统总体概述
    【虹科案例】​使用虹科数字化仪测量遥远恒星的直径
    vue中实现文件批量打包压缩下载(以及下载跨域问题分析)
    HTTP请求:GET/POST请求
    使用量子玻尔兹曼机推进机器学习:新范式
    猫头虎的技术笔记:Spring Boot启动报错解决方案
    隧道未来如何发展?路网全息感知,颠覆公路交通安全史
    前端开发面试题—CSS盒子模型
    selenium headless 无头模式慢
  • 原文地址:https://blog.csdn.net/sdhexu/article/details/126593171