24.5. Line Segments

A line is drawn by generating a set of fragments overlapping a rectangle centered on the line segment. Each line segment has an associated width that controls the width of that rectangle.

The line width is set by the lineWidth property of VkPipelineRasterizationStateCreateInfo in the currently active pipeline if the pipeline was not created with VK_DYNAMIC_STATE_LINE_WIDTH enabled. Otherwise, the line width is set by calling vkCmdSetLineWidth:


void vkCmdSetLineWidth(
    VkCommandBuffer                             commandBuffer,
    float                                       lineWidth);

Not all line widths need be supported for line segment rasterization, but width 1.0 antialiased segments must be provided. The range and gradations are obtained from the lineWidthRange and lineWidthGranularity members of VkPhysicalDeviceLimits. If, for instance, the size range is from 0.1 to 2.0 and the gradation size is 0.1, then the size 0.1, 0.2, …, 1.9, 2.0 are supported. Additional line widths may also be supported. There is no requirement that these widths be equally spaced. If an unsupported width is requested, the nearest supported width is used instead.

24.5.1. Basic Line Segment Rasterization

Rasterized line segments produce fragments which intersect a rectangle centered on the line segment. Two of the edges are parallel to the specified line segment; each is at a distance of one-half the current width from that segment in directions perpendicular to the direction of the line. The other two edges pass through the line endpoints and are perpendicular to the direction of the specified line segment. Coverage bits that correspond to sample points that intersect the rectangle are 1, other coverage bits are 0.

Next we specify how the data associated with each rasterized fragment are obtained. Let $\mathbf{p}_r = (x_d, y_d)$ be the framebuffer coordinates at which associated data are evaluated. This may be the pixel center of a fragment or the location of a sample within the fragment. When rasterizationSamples is VK_SAMPLE_COUNT_1_BIT, the pixel center must be used. Let $\mathbf{p}_a = (x_a, y_a)$ and $\mathbf{p}_b = (x_b,y_b)$ be initial and final endpoints of the line segment, respectively. Set

\[ t = {{( \mathbf{p}_r - \mathbf{p}_a ) \cdot ( \mathbf{p}_b - \mathbf{p}_a )} \over {\| \mathbf{p}_b - \mathbf{p}_a \|^2 }} \]

(Note that $t=0$ at $\mathbf{p}_a$ and $t=1$ at $\mathbf{p}_b$ . Also note that this calculation projects the vector from $\mathbf{p}_a$ to $\mathbf{p}_r$ onto the line, and thus computes the normalized distance of the fragment along the line.)

The value of an associated datum $f$ for the fragment, whether it be a shader output or the clip $w$ coordinate, is found as

Equation 24.1. line_perspective_interpolation

\[ f = {{ (1-t) {f_a / w_a} + t { f_b / w_b} } \over {(1-t) / w_a + t / w_b }} \]

where $f_a$ and $f_b$ are the data associated with the starting and ending endpoints of the segment, respectively; $w_a$ and $w_b$ are the clip $w$ coordinates of the starting and ending endpoints of the segments, respectively. However, depth values for lines must be interpolated by

Equation 24.2. line_noperspective_interpolation

\[ z = (1-t) z_a + t z_b \]

where $z_a$ and $z_b$ are the depth values of the starting and ending endpoints of the segment, respectively.

The NoPerspective and Flat interpolation decorations can be used with fragment shader inputs to declare how they are interpolated. When neither decoration is applied, interpolation is performed as described in Equation line_perspective_interpolation. When the NoPerspective decoration is used, interpolation is performed in the same fashion as for depth values, as described in Equation line_noperspective_interpolation. When the Flat decoration is used, no interpolation is performed, and outputs are taken from the corresponding input value of the provoking vertex corresponding to that primitive.

The above description documents the preferred method of line rasterization, and must be used when the implementation advertises the strictLines limit in VkPhysicalDeviceLimits as VK_TRUE.

When strictLines is VK_FALSE, the edges of the lines are generated as a parallelogram surrounding the original line. The major axis is chosen by noting the axis in which there is the greatest distance between the line start and end points. If the difference is equal in both directions then the X axis is chosen as the major axis. Edges 2 and 3 are aligned to the minor axis and are centered on the endpoints of the line as in Figure 24.1, “Non strict lines”, and each is lineWidth long. Edges 0 and 1 are parallel to the line and connect the endpoints of edges 2 and 3. Coverage bits that correspond to sample points that intersect the parallelogram are 1, other coverage bits are 0.

Samples that fall exactly on the edge of the parallelogram follow the polygon rasterization rules.

Interpolation occurs as if the parallelogram was decomposed into two triangles where each pair of vertices at each end of the line has identical attributes.

Figure 24.1. Non strict lines