A polygon results from the decomposition of a triangle strip, triangle fan
or a series of independent triangles. Like points and line segments,
polygon rasterization is controlled by several variables in the
VkPipelineRasterizationStateCreateInfo
structure.
The first step of polygon rasterization is to determine whether the triangle is back-facing or front-facing. This determination is made based on the sign of the (clipped or unclipped) polygon’s area computed in framebuffer coordinates. One way to compute this area is:
where $x_f^i$ and $y_f^i$ are the $x$ and $y$ framebuffer coordinates of the $i$ th vertex of the $n$ -vertex polygon (vertices are numbered starting at zero for the purposes of this computation) and $i \oplus 1$ is $(i + 1)~ \textrm{mod}~ n$ .
The interpretation of the sign of
$a$
is determined by the
VkPipelineRasterizationStateCreateInfo
::frontFace
property of
the currently active pipeline, which takes the following values:
typedef enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, VK_FRONT_FACE_CLOCKWISE = 1, } VkFrontFace;
If frontFace
is set to VK_FRONT_FACE_COUNTER_CLOCKWISE
, a triangle with
positive area is considered front-facing. If it is set to
VK_FRONT_FACE_CLOCKWISE
, a triangle with negative area is considered
front-facing. Any triangle which is not front-facing is back-facing,
including zero-area triangles.
Once the orientation of triangles is determined, they are culled according
to the setting of the
VkPipelineRasterizationStateCreateInfo
::cullMode
property of the
currently active pipeline, which takes the following values:
typedef enum VkCullModeFlagBits { VK_CULL_MODE_NONE = 0, VK_CULL_MODE_FRONT_BIT = 0x00000001, VK_CULL_MODE_BACK_BIT = 0x00000002, VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, } VkCullModeFlagBits;
If the cullMode
is set to VK_CULL_MODE_NONE
no triangles are
discarded, if it is set to VK_CULL_MODE_FRONT_BIT
front-facing
triangles are discarded, if it is set to VK_CULL_MODE_BACK_BIT
then
back-facing triangles are discarded and if it is set to
VK_CULL_MODE_FRONT_AND_BACK
then all triangles are discarded.
Following culling, fragments are produced for any triangles which have not
been discarded.
The rule for determining which fragments are produced by polygon rasterization is called point sampling. The two-dimensional projection obtained by taking the x and y framebuffer coordinates of the polygon’s vertices is formed. Fragments are produced for any pixels for which any sample points lie inside of this polygon. Coverage bits that correspond to sample points that satisfy the point sampling criteria are 1, other coverage bits are 0. Special treatment is given to a sample whose sample location lies on a polygon edge. In such a case, if two polygons lie on either side of a common edge (with identical endpoints) on which a sample point lies, then exactly one of the polygons must result in a covered sample for that fragment during rasterization. As for the data associated with each fragment produced by rasterizing a polygon, we begin by specifying how these values are produced for fragments in a triangle. Define barycentric coordinates for a triangle. Barycentric coordinates are a set of three numbers, $a$ , $b$ , and $c$ , each in the range $\lbrack 0, 1\rbrack$ , with $a + b + c = 1$ . These coordinates uniquely specify any point $p$ within the triangle or on the triangle’s boundary as
where $p_a$ , $p_b$ , and $p_c$ are the vertices of the triangle. $a$ , $b$ , and $c$ are determined by:
where $A(lmn)$ denotes the area in framebuffer coordinates of the triangle with vertices $l$ , $m$ , and $n$ .
Denote an associated datum at $p_a$ , $p_b$ , or $p_c$ as $f_a$ , $f_b$ , or $f_c$ , respectively. Then the value $f$ of a datum at a fragment produced by rasterizing a triangle is given by:
Equation 24.3. triangle_perspective_interpolation
where
$w_a$
,
$w_b$
, and
$w_c$
are the
clip
$w$
coordinates of
$p_a$
,
$p_b$
,
and
$p_c$
, respectively.
$a$
,
$b$
, and
$c$
are the barycentric coordinates of the location at which
the data are produced - this must be a pixel center or the location of
a sample. When rasterizationSamples
is
VK_SAMPLE_COUNT_1_BIT
, the pixel center must be used. Depth values
for triangles must be interpolated by
where $z_a$ , $z_b$ , and $z_c$ are the depth values of $p_a$ , $p_b$ , and $p_c$ , 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 triangle_perspective_interpolation. When the NoPerspective
decoration is used, interpolation is performed in the same fashion as for
depth values, as described in Equation triangle_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.
For a polygon with more than three edges, such as are produced by clipping a triangle, a convex combination of the values of the datum at the polygon’s vertices must be used to obtain the value assigned to each fragment produced by the rasterization algorithm. That is, it must be the case that at every fragment
where $n$ is the number of vertices in the polygon and $f_i$ is the value of $f$ at vertex $i$ . For each $i$ , $0 \leq a_i \leq 1$ and $\sum_{i=1}^{n}a_i = 1$ . The values of $a_i$ may differ from fragment to fragment, but at vertex $i$ , $a_i = 1$ and $a_j = 0$ for $j \neq i$ .
Note | |
---|---|
One algorithm that achieves the required behavior is to triangulate a polygon (without adding any vertices) and then treat each triangle individually as already discussed. A scan-line rasterizer that linearly interpolates data along each edge and then linearly interpolates data across each horizontal span from edge to edge also satisfies the restrictions (in this case, the numerator and denominator of equation Equation triangle_perspective_interpolation are iterated independently and a division performed for each fragment). |
The method of rasterization for polygons is determined by the
VkPipelineRasterizationStateCreateInfo
::polygonMode
property of
the currently active pipeline, which takes the following values:
typedef enum VkPolygonMode { VK_POLYGON_MODE_FILL = 0, VK_POLYGON_MODE_LINE = 1, VK_POLYGON_MODE_POINT = 2, } VkPolygonMode;
The polygonMode
selects which method of rasterization is used for
polygons. If polygonMode
is VK_POLYGON_MODE_POINT
, then the
vertices of polygons are treated, for rasterization purposes, as if they had
been drawn as points. VK_POLYGON_MODE_LINE
causes polygon edges to be
drawn as line segments. VK_POLYGON_MODE_FILL
causes polygons to render
using the polygon rasterization rules in this section.
Note that these modes affect only the final rasterization of polygons: in particular, a polygon’s vertices are shaded and the polygon is clipped and possibly culled before these modes are applied.
The depth values of all fragments generated by the rasterization of a
polygon can be offset by a single value that is computed for that polygon.
This behavior is controlled by the depthBiasEnable
,
depthBiasConstantFactor
, depthBiasClamp
, and
depthBiasSlopeFactor
members of
VkPipelineRasterizationStateCreateInfo
, or by the corresponding
parameters to the vkCmdSetDepthBias
command if depth bias state is
dynamic.
void vkCmdSetDepthBias( VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor);
commandBuffer
is the command buffer into which the command will be
recorded.
depthBiasConstantFactor
is a scalar factor controlling the
constant depth value added to each fragment.
depthBiasClamp
is the maximum (or minimum) depth bias of a
fragment.
depthBiasSlopeFactor
is a scalar factor applied to a fragment’s
slope in depth bias calculations.
If depthBiasEnable
is VK_FALSE
, no depth bias is applied and the
fragment’s depth values are unchanged.
depthBiasSlopeFactor
scales the maximum depth slope of the polygon,
and depthBiasConstantFactor
scales an implementation-dependent
constant that relates to the usable resolution of the depth buffer. The
resulting values are summed to produce the depth bias value which is then
clamped to a minimum or maximum value specified by depthBiasClamp
.
depthBiasSlopeFactor
, depthBiasConstantFactor
, and
depthBiasClamp
can each be positive, negative, or zero.
The maximum depth slope $m$ of a triangle is
where $(x_f, y_f, z_f)$ is a point on the triangle. $m$ may be approximated as
The minimum resolvable difference $r$ is an implementation-dependent parameter that depends on the depth buffer representation. It is the smallest difference in framebuffer coordinate $z$ values that is guaranteed to remain distinct throughout polygon rasterization and in the depth buffer. All pairs of fragments generated by the rasterization of two polygons with otherwise identical vertices, but $z_f$ values that differ by $r$, will have distinct depth values.
For fixed-point depth buffer representations, $r$ is constant throughout the range of the entire depth buffer. For floating-point depth buffers, there is no single minimum resolvable difference. In this case, the minimum resolvable difference for a given polygon is dependent on the maximum exponent, $e$ , in the range of $z$ values spanned by the primitive. If $n$ is the number of bits in the floating-point mantissa, the minimum resolvable difference, $r$ , for the given primitive is defined as
If no depth buffer is present, $r$ is undefined.
The bias value $o$ for a polygon is
$m$ is computed as described above. If the depth buffer uses a fixed-point representation, $m$ is a function of depth values in the range $[0,1]$ , and $o$ is applied to depth values in the same range.
For fixed-point depth buffers, fragment depth values are always limited to the range $[0,1]$ by clamping after depth bias addition is performed. Fragment depth values are clamped even when the depth buffer uses a floating-point representation.