Unity UGUI draws elegant line segments

Unity UGUI draws elegant line segments

introduction

Sometimes, we need to draw line segments in unity, the most common way is to use LineRenderercomponents. But sometimes LineRendererit is not so suitable for us to use. For example, when we need to draw a line segment on the UI layer, of course, through a series of coordinate transformations, it can be perfectly LineRendererpresented on the UI layer, but it is not very convenient. At this time we can write something ourselves.

MaskableGraphic

There is this class in the UI, as long as we overload its OnPopulateMeshmethod, we can construct some triangular faces to present any shape. Actually it's very similar MeshFilter. There are two main methods:

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

line of thought

a straight line
Different from a line in the mathematical sense, in mathematics, a line segment is determined by two endpoints, but in unity, our line segment must have a width, otherwise it cannot be displayed. The most basic line segment must have four vertices, 2 3 Corner faces, as shown in the figure above.
When we give two vertices of a line segment, it is not difficult to calculate 4 vertices. As long as we know the width of the line, it can be easily calculated by some methods, such as:

// 首先计算线的方向
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 );

However, most of the lines used in practice are not straight lines but lines made up of many points. Then there will be a problem:
2
if the above calculation method is used, where the line segment turns, it is unavoidable that there will be a gap at the "outside of the bend" of the two line segments, and overlap at the "inside of the bend". How to solve this problem elegantly.
My idea is:
insert image description here
as shown in the figure above, find the direction of the two segments (blue dotted line) respectively, then turn 90° to get the yellow dotted line, calculate the average, and get the pink solid line. Half the width of the line segment, divided by cos(α), gives the edge intersection. The specific code is as follows:

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);
	}
}

For the convenience of processing, it is divided into three cases for processing. The first node has no predecessor node, and the last node has no successor node. Take it out and deal with it separately, so that the thinking is clearer. The key is the middle node. According to the above idea, the code is as follows:

/// <summary>
/// 处理中间节点
/// </summary>
/// <param name="prev">上一个顶点</param>
/// <param name="cur">当前顶点</param>
/// <param name="next">下一个顶点</param>
/// <param name="vh">顶点管理器</param>
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);
}

Then it's done, and you can construct line segments on the GUI as you like. As follows:

Unity UGUI MaskableGraphic draws line segments

continue to improve

In fact, there are still many things that can be improved, but with the above foundation, it is easy to expand many interesting functions. For example, the head and tail nodes can be made into round heads, and the corners can be increased. Bessel calculations can also be added. Finally, of course you can also set the UV per vertex! ! In the example, the UV is not set, but in fact AddVertthe method supports UV setting.

Guess you like

Origin blog.csdn.net/sdhexu/article/details/126593171