402 lines
18 KiB
Plaintext
402 lines
18 KiB
Plaintext
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
|
// Copyright notice at https://www.khronos.org/registry/speccopyright.html
|
|
|
|
[[vertexpostproc]]
|
|
= Fixed-Function Vertex Post-Processing
|
|
|
|
After programmable vertex processing, the following fixed-function
|
|
operations are applied to vertices of the resulting primitives:
|
|
|
|
* Flatshading (see <<vertexpostproc-flatshading,Flatshading>>).
|
|
* Primitive clipping, including client-defined half-spaces (see
|
|
<<vertexpostproc-clipping,Primitive Clipping>>).
|
|
* Shader output attribute clipping (see
|
|
<<vertexpostproc-clipping-shader-outputs,Clipping Shader Outputs>>).
|
|
* Perspective division on clip coordinates (see
|
|
<<vertexpostproc-coord-transform,Coordinate Transformations>>).
|
|
* Viewport mapping, including depth range scaling (see
|
|
<<vertexpostproc-viewport,Controlling the Viewport>>).
|
|
* Front face determination for polygon primitives (see
|
|
<<primsrast-triangles-basic,Basic Triangle Rasterization>>).
|
|
|
|
ifdef::editing-notes[]
|
|
[NOTE]
|
|
.editing-note
|
|
====
|
|
TODO:Odd that this one link to a different chapter is in this list.
|
|
====
|
|
endif::editing-notes[]
|
|
|
|
Next, rasterization is performed on primitives as described in chapter
|
|
<<primsrast,Rasterization>>.
|
|
|
|
|
|
[[vertexpostproc-flatshading]]
|
|
== Flatshading
|
|
|
|
_Flatshading_ a vertex output attribute means to assign all vertices of the
|
|
primitive the same value for that output.
|
|
|
|
The output values assigned are those of the _provoking vertex_ of the
|
|
primitive. The provoking vertex depends on the primitive topology, and is
|
|
generally the ``first'' vertex of the primitive. For primitives not
|
|
processed by tessellation or geometry shaders, the provoking vertex is
|
|
selected from the input vertices according to the following table.
|
|
|
|
<<<
|
|
|
|
.Provoking vertex selection
|
|
[align="center",cols="75%,25%"]
|
|
|========================================
|
|
|Primitive type of primitive latexmath:[$i$] | Provoking vertex number
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_POINT_LIST | latexmath:[$i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_LINE_LIST | latexmath:[$2 i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_LINE_STRIP | latexmath:[$i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST | latexmath:[$3 i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP | latexmath:[$i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN | latexmath:[$i + 1$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY | latexmath:[$4 i + 1$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY | latexmath:[$i + 1$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY | latexmath:[$6 i$]
|
|
|ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY | latexmath:[$2 i$]
|
|
|========================================
|
|
|
|
ifdef::editing-notes[]
|
|
[NOTE]
|
|
.editing-note
|
|
====
|
|
TODO: Add full caption:
|
|
|
|
Provoking vertex selection. The output values used for flatshading the i^th^
|
|
primitive generated by drawing commands with the indicated primitive type
|
|
are derived from the corresponding values of the vertex whose index is shown
|
|
in the table. Primitives and vertices are numbered starting from zero.
|
|
====
|
|
endif::editing-notes[]
|
|
|
|
Flatshading is applied to those vertex attributes that
|
|
<<interfaces-iointerfaces-matching,match>> fragment input attributes
|
|
which are decorated as code:Flat.
|
|
|
|
If a geometry shader is active, the output primitive topology is either
|
|
points, line strips, or triangle strips, and the selection of the provoking
|
|
vertex behaves according to the corresponding row of the table. If a
|
|
tessellation evaluation shader is active and a geometry shader is not
|
|
active, the provoking vertex is undefined but must: be one of the vertices
|
|
of the primitive.
|
|
|
|
|
|
[[vertexpostproc-clipping]]
|
|
== Primitive Clipping
|
|
|
|
Primitives are culled against the _cull volume_ and then clipped to the
|
|
_clip volume_. In clip coordinates, the _view volume_ is defined by:
|
|
|
|
latexmath:[$
|
|
\begin{array}{c}
|
|
-w_c \leq x_c \leq w_c \\
|
|
-w_c \leq y_c \leq w_c \\
|
|
0 \leq z_c \leq w_c \\
|
|
\end{array}
|
|
$]
|
|
|
|
This view volume can: be further restricted by as many as
|
|
sname:VkPhysicalDeviceLimits::pname:maxClipDistances client-defined
|
|
half-spaces.
|
|
|
|
The cull volume is the intersection of up to
|
|
sname:VkPhysicalDeviceLimits::pname:maxCullDistances client-defined
|
|
half-spaces (if no client-defined cull half-spaces are enabled, culling
|
|
against the cull volume is skipped).
|
|
|
|
A shader must: write a single cull distance for each enabled cull half-space
|
|
to elements of the code:CullDistance array. If the cull distance for any
|
|
enabled cull half-space is negative for all of the vertices of the primitive
|
|
under consideration, the primitive is discarded. Otherwise the primitive is
|
|
clipped against the clip volume as defined below.
|
|
|
|
The clip volume is the intersection of up to the value of
|
|
sname:VkPhysicalDeviceLimits::pname:maxClipDistances client-defined
|
|
half-spaces with the view volume (if no client-defined clip half-spaces are
|
|
enabled, the clip volume is the view volume).
|
|
|
|
A shader must: write a single clip distance for each enabled clip
|
|
half-space to elements of the code:ClipDistance array. Clip half-space
|
|
latexmath:[$i$] is then given by the set of points satisfying the inequality
|
|
|
|
latexmath:[$c_i(P) \geq 0$]
|
|
|
|
where latexmath:[$c_i(P)$] is the value of clip distance latexmath:[$i$] at
|
|
point latexmath:[$P$]. For point primitives, latexmath:[$c_i(P)$] is simply
|
|
the clip distance for the vertex in question. For line and triangle
|
|
primitives, per-vertex clip distances are interpolated using a weighted
|
|
mean, with weights derived according to the algorithms described in sections
|
|
<<primsrast-lines-basic,Basic Line Segment Rasterization>> and
|
|
<<primsrast-polygons-basic,Basic Polygon Rasterization>>, using the
|
|
perspective interpolation equations.
|
|
|
|
The number of client-defined clip and cull half-spaces that are enabled is
|
|
determined by the explicit size of the built-in arrays code:ClipDistance and
|
|
code:CullDistance, respectively, declared as an output in the interface of
|
|
the entry point of the final shader stage before clipping.
|
|
|
|
Depth clamping is enabled or disabled via the pname:depthClampEnable enable
|
|
of the sname:VkPipelineRasterizationStateCreateInfo structure. If depth
|
|
clamping is enabled, the plane equation
|
|
|
|
latexmath:[$0 \leq z_c \leq w_c$]
|
|
|
|
(see the clip volume definition above) is ignored by view
|
|
volume clipping (effectively, there is no near or far plane clipping).
|
|
|
|
If the primitive under consideration is a point, then clipping passes it
|
|
unchanged if it lies within the clip volume; otherwise, it is discarded.
|
|
|
|
If the primitive is a line segment, then clipping does nothing to it if it
|
|
lies entirely within the clip volume, and discards it if it lies entirely
|
|
outside the volume.
|
|
|
|
If part of the line segment lies in the volume and part lies outside, then
|
|
the line segment is clipped and new vertex coordinates are computed for one
|
|
or both vertices. A clipped line segment endpoint lies on both the original
|
|
line segment and the boundary of the clip volume.
|
|
|
|
This clipping produces a value, latexmath:[$0 \leq t \leq 1$], for each
|
|
clipped vertex. If the coordinates of a clipped vertex are
|
|
latexmath:[${\textbf P}$] and the original vertices' coordinates are
|
|
latexmath:[${\textbf P}_1$] and latexmath:[${\textbf P}_2$], then
|
|
latexmath:[$t$] is given by
|
|
|
|
latexmath:[${\textbf P} = t{\textbf P}_1 + (1-t){\textbf P}_2.$]
|
|
|
|
The value of latexmath:[$t$] is used to clip vertex output attributes as
|
|
described in <<vertexpostproc-clipping-shader-outputs,Clipping Shader
|
|
Outputs>>.
|
|
|
|
If the primitive is a polygon, it passes unchanged if every one of its edges
|
|
lie entirely inside the clip volume, and it is discarded if every one of its
|
|
edges lie entirely outside the clip volume. If the edges of the polygon
|
|
intersect the boundary of the clip volume, the intersecting edges are
|
|
reconnected by new edges that lie along the boundary of the clip volume -
|
|
in some cases requiring the introduction of new vertices into a polygon.
|
|
|
|
If a polygon intersects an edge of the clip volume's boundary, the clipped
|
|
polygon must: include a point on this boundary edge.
|
|
|
|
Primitives rendered with user-defined half-spaces must: satisfy a
|
|
complementarity criterion. Suppose a series of primitives is drawn where
|
|
each vertex latexmath:[$i$] has a single specified clip distance
|
|
latexmath:[$d_i$] (or a number of similarly specified clip distances, if
|
|
multiple half-spaces are enabled). Next, suppose that the same series of
|
|
primitives are drawn again with each such clip distance replaced by
|
|
latexmath:[$-d_i$] (and the graphics pipeline is otherwise the same). In
|
|
this case, primitives mustnot: be missing any pixels, and pixels mustnot: be
|
|
drawn twice in regions where those primitives are cut by the clip planes.
|
|
|
|
|
|
[[vertexpostproc-clipping-shader-outputs]]
|
|
== Clipping Shader Outputs
|
|
|
|
Next, vertex output attributes are clipped. The output values associated
|
|
with a vertex that lies within the clip volume are unaffected by clipping.
|
|
If a primitive is clipped, however, the output values assigned to vertices
|
|
produced by clipping are clipped.
|
|
|
|
Let the output values assigned to the two vertices latexmath:[${\textbf
|
|
P}_1$] and latexmath:[${\textbf P}_2$] of an unclipped edge be
|
|
latexmath:[${\textbf c}_1$] and latexmath:[${\textbf c}_2$]. The value of
|
|
latexmath:[$t$] (see <<vertexpostproc-clipping,Primitive Clipping>>) for a
|
|
clipped point latexmath:[${\textbf P}$] is used to obtain the output value
|
|
associated with latexmath:[${\textbf P}$] as
|
|
|
|
latexmath:[${\textbf c} = t {\textbf c}_1 + (1-t){\textbf c}_2. $]
|
|
|
|
(Multiplying an output value by a scalar means multiplying each of _x_, _y_,
|
|
_z_, and _w_ by the scalar.)
|
|
|
|
Since this computation is performed in clip space before division by
|
|
latexmath:[$w_c$], clipped output values are perspective-correct.
|
|
|
|
Polygon clipping creates a clipped vertex along an edge of the clip
|
|
volume's boundary. This situation is handled by noting that polygon clipping
|
|
proceeds by clipping against one half-space at a time. Output value clipping
|
|
is done in the same way, so that clipped points always occur at the
|
|
intersection of polygon edges (possibly already clipped) with the clip
|
|
volume's boundary.
|
|
|
|
For vertex output attributes whose matching fragment input attributes are
|
|
decorated with code:NoPerspective, the value
|
|
of latexmath:[$t$] used to obtain the output value associated with
|
|
latexmath:[${\textbf P}$] will be adjusted to produce results that vary
|
|
linearly in framebuffer space.
|
|
|
|
Output attributes of integer or unsigned integer type must: always be
|
|
flatshaded. Flatshaded attributes are constant over the primitive being
|
|
rasterized (see <<primsrast-lines-basic,Basic Line Segment Rasterization>>
|
|
and <<primsrast-polygons-basic,Basic Polygon Rasterization>>), and no
|
|
interpolation is performed. The output value latexmath:[${\textbf c}$] is
|
|
taken from either latexmath:[${\textbf c}_1$] or latexmath:[${\textbf
|
|
c}_2$], since flatshading has already occurred and the two values are
|
|
identical.
|
|
|
|
|
|
[[vertexpostproc-coord-transform]]
|
|
== Coordinate Transformations
|
|
|
|
_Clip coordinates_ for a vertex result from shader execution, which yields a
|
|
vertex coordinate code:Position.
|
|
|
|
Perspective division on clip coordinates yields _normalized device
|
|
coordinates_, followed by a _viewport_ transformation (see
|
|
<<vertexpostproc-viewport,Controlling the Viewport>>) to convert these
|
|
coordinates into _framebuffer coordinates_.
|
|
|
|
If a vertex in clip coordinates has a position given by
|
|
|
|
latexmath:[$\left(\begin{array}{c} x_c \\ y_c \\ z_c \\ w_c \end{array}\right)$]
|
|
|
|
then the vertex's normalized device coordinates are
|
|
|
|
latexmath:[$
|
|
\left(\begin{array}{c} x_d \\ y_d \\ z_d \end{array}\right) =
|
|
\left(\begin{array}{c} \frac{x_c}{w_c} \\ \frac{y_c}{w_c} \\ \frac{z_c}{w_c} \end{array}\right)
|
|
$]
|
|
|
|
|
|
[[vertexpostproc-viewport]]
|
|
== Controlling the Viewport
|
|
|
|
The viewport transformation is determined by the selected viewport's width
|
|
and height in pixels, latexmath:[$p_x$] and latexmath:[$p_y$], respectively,
|
|
and its center latexmath:[$(o_x, o_y)$] (also in pixels), as well as its
|
|
depth range min and max determining a depth range scale value
|
|
latexmath:[$p_z$] and a depth range bias value latexmath:[$o_z$] (defined
|
|
below). The vertex's framebuffer coordinates,
|
|
latexmath:[$\left(\begin{array}{c} x_f \\ y_f \\ z_f \end{array}\right),$]
|
|
are given by
|
|
|
|
latexmath:[$
|
|
\left(\begin{array}{c} x_f \\ y_f \\ z_f \end{array}\right) =
|
|
\left(\begin{array}{c}
|
|
\frac{ p_x }{ 2 } x_d + o_x \\
|
|
\frac{ p_y }{ 2 } y_d + o_y \\
|
|
p_z \times z_d + o_z
|
|
\end{array}\right).
|
|
$]
|
|
|
|
Multiple viewports are available and are numbered zero up to the value of
|
|
sname:VkPhysicalDeviceLimits::pname:maxViewports. The number of viewports
|
|
used by a pipeline is controlled by the pname:viewportCount member of the
|
|
sname:VkPipelineViewportStateCreateInfo structure used in pipeline creation:
|
|
|
|
include::../structs/VkPipelineViewportStateCreateInfo.txt[]
|
|
|
|
The members of the sname:VkPipelineViewportStateCreateInfo structure are as
|
|
follows:
|
|
|
|
* pname:sType is the type of this structure.
|
|
* pname:pNext is `NULL` or a pointer to an extension-specific structure.
|
|
* pname:flags is reserved for future use.
|
|
* pname:viewportCount is the number of viewports used by the pipeline.
|
|
* pname:pViewports is a pointer to an array of slink:VkViewport structs,
|
|
defining the viewport transforms. If the viewport state is dynamic, this
|
|
member is ignored.
|
|
* pname:scissorCount is the number of <<fragops-scissor,scissors>> and
|
|
must: match the number of viewports.
|
|
* pname:pScissors is a pointer to an array of sname:VkRect2D structs which
|
|
define the rectangular bounds of the scissor for the corresponding
|
|
viewport. If the scissor state is dynamic, this member is ignored.
|
|
|
|
include::../validity/structs/VkPipelineViewportStateCreateInfo.txt[]
|
|
|
|
If a geometry shader is active and has an output variable decorated with
|
|
code:ViewportIndex, the viewport transformation uses the viewport
|
|
corresponding to the value assigned to code:ViewportIndex taken from an
|
|
implementation-dependent vertex of each primitive. If the value of
|
|
code:ViewportIndex is outside the range zero to the value of
|
|
pname:viewportCount minus one for a primitive, or if the geometry shader did
|
|
not assign a value to code:ViewportIndex for all vertices of a primitive due
|
|
to flow control, the results of the viewport transformation of the vertices
|
|
of such primitives are undefined. If no geometry shader is active, or if the
|
|
geometry shader does not have an output decorated with code:ViewportIndex,
|
|
the viewport numbered zero is used by the viewport transformation.
|
|
|
|
A single vertex can: be used in more than one individual primitive, in
|
|
primitives such as ename:VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP. In this case,
|
|
the viewport transformation is applied separately for each primitive.
|
|
|
|
If the bound pipeline state object was not created with the
|
|
ename:VK_DYNAMIC_STATE_VIEWPORT dynamic state enabled, viewport
|
|
transformation parameters are specified using the pname:pViewports
|
|
member of sname:VkPipelineViewportStateCreateInfo in the pipeline state
|
|
object. If the pipeline state object was created with the
|
|
ename:VK_DYNAMIC_STATE_VIEWPORT dynamic state enabled, the viewport
|
|
transformation parameters are dynamically set and changed with the command:
|
|
|
|
include::../protos/vkCmdSetViewport.txt[]
|
|
|
|
* pname:commandBuffer is the command buffer into which the command will be
|
|
recorded.
|
|
* pname:firstViewport is the index of the first viewport whose parameters
|
|
are updated by the command.
|
|
* pname:viewportCount is the number of viewports whose parameters are
|
|
updated by the command.
|
|
* pname:pViewports is a pointer to an array of slink:VkViewport structures
|
|
specifying viewport parameters.
|
|
|
|
The viewport parameters taken from element latexmath:[$i$] of
|
|
pname:pViewports replace the current state for the viewport index
|
|
latexmath:[$\mathit{firstViewport}+i$], for latexmath:[$i$] in
|
|
latexmath:[$[0, viewportCount)$].
|
|
|
|
include::../validity/protos/vkCmdSetViewport.txt[]
|
|
|
|
Either of these methods of setting the viewport transformation parameters
|
|
use the sname:VkViewport struct:
|
|
|
|
include::../structs/VkViewport.txt[]
|
|
|
|
* pname:x and pname:y are the viewport's upper left corner
|
|
latexmath:[$(x,y)$].
|
|
* pname:width and pname:height are the viewport's width and height,
|
|
respectively.
|
|
* pname:minDepth and pname:maxDepth are the depth range for the viewport.
|
|
It is valid for pname:minDepth to be greater than or equal to
|
|
pname:maxDepth.
|
|
|
|
include::../validity/structs/VkViewport.txt[]
|
|
|
|
The framebuffer depth coordinate latexmath:[$z_f$] may: be represented using
|
|
either a fixed-point or floating-point representation. However, a
|
|
floating-point representation must: be used if the depth/stencil attachment
|
|
has a floating-point depth component. If an latexmath:[$m$]-bit fixed-point
|
|
representation is used, we assume that it represents each value
|
|
latexmath:[$\frac{k}{2^m - 1}$], where latexmath:[$k \in \{ 0,1, \ldots,
|
|
2^m-1 \}$], as latexmath:[$k$] (e.g. 1.0 is represented in binary as a
|
|
string of all ones).
|
|
|
|
The viewport parameters shown in the above equations are found from these
|
|
values as
|
|
|
|
[latexmath]
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
\begin{align*}
|
|
o_x & = x + \frac{width}{2} \\
|
|
o_y & = y + \frac{height}{2} \\
|
|
o_z & = minDepth \\
|
|
p_x & = width \\
|
|
p_y & = height \\
|
|
p_z & = maxDepth - minDepth.
|
|
\end{align*}
|
|
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
The width and height of the <<features-limits-maxViewportDimensions,
|
|
implementation-dependent maximum viewport dimensions>> must: be greater
|
|
than or equal to the width and height of the largest image which can: be
|
|
created and attached to a framebuffer.
|
|
|
|
The floating-point viewport bounds are represented with an
|
|
<<features-limits-viewportSubPixelBits,implementation-dependent precision>>.
|
|
|
|
|