The basic idea

The last article briefly introduced the bug of WebGL drawing Line, and this article will talk about how to solve this problem.

At the end of the last article, I briefly mentioned the idea of solving the problem, which is to simulate lines through triangles.

Taking a line segment composed of two endpoints as an example, only two endpoints are specified when drawing a line. If a line segment is simulated by a triangle, at least two triangles are required, as shown in the following figure:





A line segment simulated by two triangles

So to draw a line segment, you need six vertices, two triangles; In the figure above, you can see that some vertices are shared. In fact, you only need four vertices, and then draw two triangles by index. I’m sure those of you familiar with WebGL will understand this way of drawing by index.

If you want to draw two connected line segments, you need to add two vertices, or six vertices, to draw four triangles, and so on, eight vertices to draw three connected line segments, and six triangles to draw; It follows from this that drawing a Line with n endpoints requires: 2 * n vertices, (n-1) * 2 triangles.

For a line segment, the parameters controlled are really only the coordinates of the two endpoints and the width of the line.

From the above analysis, we know that given a series of points (n) and the width of the line, the number of vertices needed to draw a line segment is n * 2.

How to compute vertices

Two endpoints

How do you compute n vertices? To start with a simple 2-d plot example, now assume that two endpoints are given:

(-50, 0) and (50,0), to draw a line of width 2, there are four vertices in total. The first vertex is the offset from the first endpoint + the line width. The line width is 2, so the base of the offset should be 2/2 = 1.

The second vertex is the offset * (-1) from the first endpoint + line width, which is also 2, so the cardinality of the offset should be 2/2 * (-1) = -1;

And so on, how do you offset it? This has to do with the direction of the line segment, which in the example can be calculated using the second endpoint – the first endpoint:

(50,0) – (-50, 0) = (100,0), after normalization, is (1,0), which is the direction vector of the line segment, and represents the positive direction of the line segment along the X-axis. For the first vertex, the offset direction should be (1,0) rotated 90 degrees counterclockwise. That is, the direction perpendicular to the line segment (there are two directions perpendicular to the line segment, here based on the right hand rule, choose the one 90 degrees counterclockwise). After 90 degrees rotation, the vector is programmed (0, -1).

If the vector (x,y) is rotated 90 degrees counterclockwise, it becomes (-y, x);

For the second vertex, the offset should be rotated 90 degrees clockwise, but previously, we have changed the base of the offset to -1, so we can assume that the offset is still rotated 90 degrees counterclockwise, as shown in the figure:





Calculate vertex offset direction based on segment direction

From this, the position of the first vertex can be obtained:

(-50, 0) – (0, -1) * 1 = (-50, -1),

The position of the second vertex is:

(-50, 0) – (0, -1) * 1 = (-50, 1)

Similarly for the third and fourth vertices.

Multiple endpoints

In fact, if it is multiple endpoints, the case discussed above only applies to the case of the first and last endpoints in the multiple endpoints. For the middle endpoints, the offset direction should be considered comprehensively in the case of the two line segments connected by this endpoint. The same examples are illustrated:

Assume that the three endpoints are (-50, 0), (0,0), (0,50). Now calculate the two vertices (third and fourth) corresponding to the second endpoint (0,0), as shown in figure:





Three endpoint

At this point, to calculate the positions of the two vertices of the middle endpoint, the directions of the two antenna segments connected by the endpoint should be considered:





Segment direction Calculates the offset direction

The general idea of calculation is to calculate the direction of the first line segment by subtracting the endpoint and the previous endpoint:

(0,0) – (-50, 0) = (50,0) = (1,0) (normalization)

Calculate the direction of the second line segment by subtracting the next endpoint of this endpoint:

(0,50) – (0,0) = (0,50) = (0,1) (normalization)

Then add the two direction vectors and rotate 90 degrees counterclockwise in rotation to get the offset direction:

(1,0) + (0,1) = (1,1) = (0.707,0.707) (normalization)

After rotation, offset direction is programmed (-0.707, 0.707),

It should be noted that the offset base at this time has actually changed, and the offset at the corner should become large at this time, that is, there is a magnification factor. This magnification factor can be obtained by dotting the direction of the first line segment with the offset direction of 1 /. However, if the Angle between two line segments is very small, the value of the dot product is also very small, and the magnification factor is very large. In order not to make the sharp corner appear large, we generally limit the magnification factor to no more than 2. So the formula can become:

1 / Max (offset direction. Direction of the first line segment, 0.5)

How do I organize vertex data

Above a lot about how to compute the vertex coordinates, in fact, the text described the calculation method of the all are in the vertex shader, but also can only be calculated in the shader, because eventually show to vertex is associated with the lens on the screen, in this paper, we simply use the 2 d case simulation, calculate if the js end, will greatly consumption performance. We haven’t figured out how to compute the data we’re going to pass to the vertex shader. It’s not really bullshit, because you can’t organize data into the vertex shader until you know how to compute the final vertex in the shader.

In the case of “multiple endpoints” above, we can summarize what data is needed to calculate a vertex:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

So in the shader we need to define four attribute variables position, offset, positionPrev, positionNext to receive the endpoint coordinates, offset, the previous endpoint coordinates, and the next endpoint coordinates.

For the first two vertices, its endpoint does not have the previous endpoint, at this time the previous endpoint is taken endpoint coordinates, and then judge in the shader if the previous endpoint point coordinates == endpoint coordinates, it indicates the first endpoint; The case is calculated using two endpoints.

Lower than the latter two vertices, its endpoint does not have the latter endpoint, at this time the latter endpoint is taken endpoint coordinates, and then judge in the shader if the latter endpoint point coordinates == endpoint coordinates, it indicates that it is the last endpoint; The case is calculated using two endpoints.

For intermediate vertices, where there are both endpoint coordinates, the coordinates of the previous endpoint, and the coordinates of the latter endpoint, the case of the previous multiple endpoints is used.

Before or in the three examples of endpoints, for example, three of the endpoints (0, 50), (0, 0), (0,50,0), line width of 2 (note that at this point is the 3 d coordinate, simulation is before with the 2 d coordinates on the screen to simulate the vertices in the shader by perspective transformation into a 2 d coordinates)

Then the data of the four variables of the first vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(50,0,0), 2/2, (50,0,0) (0,0,0)

The data of the four variables of the second vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(50,0,0), -2/2, (50,0,0) (0,0,0)

The data of the four variables of the third vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(0,0,0), 2/2, (50,0,0) (0,50,0)

The data of the four variables at the fourth vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(0,0,0), -2/2, (50,0,0) (0,50,0)

The data of the four variables of the fifth vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(0,50,0), 2/2, (0,0,0) (0,50,0)

The data of the four variables at the sixth vertex are:

Endpoint coordinates, offsets, previous endpoint coordinates, last endpoint coordinates

(0,50,0), -2/2, (0,0,0) (0,50,0)

At this point, we know how to organize the data needed to draw vertices.

A code explanation will be posted in the next article.

If you are interested in WebGL, you can learn about the 3D computer room project we developed with WebGL:

HTML5, not only looks beautiful (# 2: Create the most beautiful 3D room)