固定功能顶点后处理
变换反馈
在任何其他固定功能顶点后处理之前,光栅化前着色器阶段中最后一个着色器的顶点输出可以写入绑定到命令缓冲区的一个或多个变换反馈缓冲区。要捕获顶点输出,最后一个光栅化前着色器阶段着色器必须使用 Xfb
执行模式声明。使用 XfbBuffer
修饰的输出将写入到绑定到命令缓冲区时对应的变换反馈缓冲区。变换反馈缓冲区通过使用vkCmdBindTransformFeedbackBuffersEXT绑定到命令缓冲区。变换反馈通过调用vkCmdBeginTransformFeedbackEXT激活,并通过调用vkCmdEndTransformFeedbackEXT停用。写入顶点数据后,可以使用vkCmdDrawIndirectByteCountEXT启动新的绘制,其中 vertexCount
来自先前变换反馈写入的字节数。
当单个点、线或三角形图元在变换反馈处于活动状态时到达变换反馈阶段时,指定输出变量的值将被组装成图元并附加到绑定的变换反馈缓冲区。激活变换反馈后,第一个组装图元的值将写入绑定变换反馈缓冲区的起始偏移量,后续图元将附加到该缓冲区。如果指定了可选的 pCounterBuffers
和 pCounterBufferOffsets
参数,则会调整变换反馈缓冲区内的起始点,以便将数据附加到先前写入的值,该值由实现存储在计数器缓冲区中的值指示。
对于多顶点图元,给定顶点的所有值在写入任何其他顶点的值之前写入。当transformFeedbackPreservesProvokingVertex
功能未启用时,实现可以先写入图元内的任何顶点,但是该图元的所有后续顶点必须按照一致的绕序写入,该顺序定义如下
-
如果几何或细分着色均未激活,则图元内的顶点将根据用于执行绘制命令的VkPipelineInputAssemblyStateCreateInfo定义的图元拓扑描述的绕序附加。
-
如果几何着色已激活,则图元内的顶点将根据
OutputPoints
、OutputLineStrip
或OutputTriangleStrip
执行模式定义的图元拓扑描述的绕序附加。
当transformFeedbackPreservesProvokingVertex
功能启用时,除了以一致的绕序写入顶点外,顶点顺序必须保留每个图元的激发顶点
如果transformFeedbackPreservesTriangleFanProvokingVertex
为 VK_FALSE
,并且几何或曲面细分着色器均未激活,并且图元拓扑结构为 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
,那么即使启用了transformFeedbackPreservesProvokingVertex
功能,每个图元写入的第一个顶点也是实现定义的。
当捕获顶点时,与每个变换反馈缓冲区关联的步幅(由 XfbStride
修饰符指示)表示在变换反馈缓冲区中为每个顶点保留的存储字节数。对于捕获的每个顶点,每个带有 Offset
修饰符的输出属性都将被写入到为该顶点保留的存储空间中。当写入数组或结构类型的输出变量时,单个数组元素或结构成员将按顺序紧密打包写入。对于向量类型,单个分量按顺序写入。对于矩阵类型,输出将作为列向量数组写入。
如果具有指定变换反馈偏移量的输出的任何分量没有被其着色器写入,则该分量记录的值是未定义的。输出变量的所有分量必须以对齐到分量大小的偏移量写入。输出变量的每个分量的大小必须至少为 32 位。当捕获顶点时,保留的存储空间中任何未与具有指定变换反馈偏移量的输出变量关联的部分都将保持不变。
当变换反馈处于非活动状态时,不记录任何顶点。如果 pCounterBuffers
和 pCounterBufferOffsets
数组中存在有效的计数器缓冲区句柄和计数器缓冲区偏移量,则对相应变换反馈缓冲区的写入将从计数器缓冲区位置中存储的值表示的字节偏移量开始。
条带或扇形图元的各个线或三角形将被提取并单独记录。不完整的图元不会被记录。
当使用几何着色器将顶点发射到多个顶点流时,当输出图元类型有足够的顶点发射时,将为每个流组装并输出图元。分配给给定变换反馈缓冲区的所有输出都必须来自单个顶点流。
变换反馈缓冲区的大小由 vkCmdBindTransformFeedbackBuffersEXT 的 pSizes
参数为每个绑定的缓冲区定义,或由绑定缓冲区的大小定义,以较小者为准。如果任何变换反馈缓冲区中剩余的空间小于基于该 XfbBuffer
的 XfbStride
计算的该图元的所有顶点数据的大小,则该图元的任何顶点数据都不会记录在任何变换反馈缓冲区中,并且在所有变换反馈缓冲区对应的 VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT
查询中写入的图元数量的值不再递增。
任何对未绑定到变换反馈缓冲区的 XfbBuffer
的输出都将被忽略。
要将变换反馈缓冲区绑定到命令缓冲区以在后续绘图命令中使用,请调用
// Provided by VK_EXT_transform_feedback
void vkCmdBindTransformFeedbackBuffersEXT(
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes);
-
commandBuffer
是将命令记录到的命令缓冲区。 -
firstBinding
是第一个变换反馈绑定的索引,该绑定的状态由命令更新。 -
bindingCount
是要更新状态的变换反馈绑定的数量。 -
pBuffers
是指向缓冲区句柄数组的指针。 -
pOffsets
是指向缓冲区偏移量数组的指针。 -
pSizes
是NULL
或指向VkDeviceSize
缓冲区大小数组的指针,指定要捕获到相应变换反馈缓冲区的最大字节数。如果pSizes
为NULL
,或者pSizes
数组元素的值为VK_WHOLE_SIZE
,则捕获的最大字节数将是相应缓冲区的大小减去缓冲区偏移量。
从 pBuffers
、pOffsets
和 pSizes
的元素 i 获取的值将替换变换反馈绑定 firstBinding
+ i 的当前状态,其中 i 在 [0, bindingCount
) 范围内。变换反馈绑定将更新为从缓冲区 pBuffers
[i] 的起始位置开始,偏移量由 pOffsets
[i] 指示。
通过调用以下命令,激活特定转换反馈缓冲区的转换反馈:
// Provided by VK_EXT_transform_feedback
void vkCmdBeginTransformFeedbackEXT(
VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer* pCounterBuffers,
const VkDeviceSize* pCounterBufferOffsets);
-
commandBuffer
是将命令记录到的命令缓冲区。 -
firstCounterBuffer
是对应于pCounterBuffers
[0] 和pCounterBufferOffsets
[0] 的第一个转换反馈缓冲区的索引。 -
counterBufferCount
是pCounterBuffers
和pCounterBufferOffsets
数组的大小。 -
pCounterBuffers
是NULL
或指向计数器缓冲区的 VkBuffer 句柄数组的指针。每个缓冲区都包含一个 4 字节的整数值,表示从相应的转换反馈缓冲区的起始位置开始捕获顶点数据的字节偏移量。如果存储到计数器缓冲区位置的字节偏移量是使用 vkCmdEndTransformFeedbackEXT 完成的,则可以用于从先前的位置恢复转换反馈。如果pCounterBuffers
为NULL
,则转换反馈将开始在所有绑定的转换反馈缓冲区中捕获到字节偏移量为零的顶点数据。对于pCounterBuffers
的每个 VK_NULL_HANDLE 元素,转换反馈将开始在相应的绑定转换反馈缓冲区中捕获到字节零的顶点数据。 -
pCounterBufferOffsets
是NULL
或指向VkDeviceSize
值数组的指针,该数组指定每个pCounterBuffers
内的偏移量,其中先前写入了计数器值。这些偏移量处每个计数器缓冲区中的位置必须足够大,以包含 4 个字节的数据。此数据是先前转换反馈捕获到此缓冲区的字节数。如果pCounterBufferOffsets
为NULL
,则假定偏移量为零。
活动的转换反馈缓冲区将捕获从绑定图形管道中相应的 XfbBuffer
发出的图元。任何未输出到活动转换反馈缓冲区的 XfbBuffer
都不会被捕获。
通过调用以下命令,使特定转换反馈缓冲区的转换反馈变为非活动状态
// Provided by VK_EXT_transform_feedback
void vkCmdEndTransformFeedbackEXT(
VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer* pCounterBuffers,
const VkDeviceSize* pCounterBufferOffsets);
-
commandBuffer
是将命令记录到的命令缓冲区。 -
firstCounterBuffer
是对应于pCounterBuffers
[0] 和pCounterBufferOffsets
[0] 的第一个转换反馈缓冲区的索引。 -
counterBufferCount
是pCounterBuffers
和pCounterBufferOffsets
数组的大小。 -
pCounterBuffers
为NULL
或指向计数器缓冲区的 VkBuffer 句柄数组的指针。计数器缓冲区用于记录每个转换反馈缓冲区的当前字节位置,其中将捕获下一个顶点输出数据。后续的 vkCmdBeginTransformFeedbackEXT 调用可以使用此信息来从该位置恢复转换反馈捕获。 vkCmdDrawIndirectByteCountEXT 也可以使用它来确定绘制调用的顶点计数。 -
pCounterBufferOffsets
为NULL
或指向VkDeviceSize
值数组的指针,指定pCounterBuffers
中每个计数器缓冲区内可以写入计数值的偏移量。这些偏移量处每个计数器缓冲区中的位置必须足够大,能够容纳 4 个字节的数据。存储在此位置的数据是从转换反馈缓冲区绑定的起始位置开始的字节偏移量,其中将写入下一个顶点数据。如果pCounterBufferOffsets
为NULL
,则假定偏移量为零。
视口混合
发送到给定视口的每个图元都会在其裁剪坐标上应用混合和可选的求反。应用的混合取决于视口索引,并由 VkPipelineViewportSwizzleStateCreateInfoNV
管线状态控制。
// Provided by VK_NV_viewport_swizzle
typedef struct VkPipelineViewportSwizzleStateCreateInfoNV {
VkStructureType sType;
const void* pNext;
VkPipelineViewportSwizzleStateCreateFlagsNV flags;
uint32_t viewportCount;
const VkViewportSwizzleNV* pViewportSwizzles;
} VkPipelineViewportSwizzleStateCreateInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
为NULL
或指向扩展此结构的结构的指针。 -
flags
保留供将来使用。 -
viewportCount
是管线使用的视口混合的数量。 -
pViewportSwizzles
是指向 VkViewportSwizzleNV 结构体数组的指针,定义了视口混合(swizzle)。
// Provided by VK_NV_viewport_swizzle
typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;
VkPipelineViewportSwizzleStateCreateFlagsNV
是用于设置掩码的位掩码类型,但目前保留供将来使用。
VkPipelineViewportSwizzleStateCreateInfoNV
状态通过将此结构体添加到 VkPipelineViewportStateCreateInfo
结构体的 pNext
链,并使用 vkCreateGraphicsPipelines 设置图形管线状态来设置。
要动态设置视口混合状态,请调用
// Provided by VK_EXT_extended_dynamic_state3 with VK_NV_viewport_swizzle, VK_EXT_shader_object with VK_NV_viewport_swizzle
void vkCmdSetViewportSwizzleNV(
VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewportSwizzleNV* pViewportSwizzles);
-
commandBuffer
是将记录命令的命令缓冲区。 -
firstViewport
是由命令更新其参数的第一个视口的索引。 -
viewportCount
是由命令更新其参数的视口数量。 -
pViewportSwizzles
是一个指向 VkViewportSwizzleNV 结构体数组的指针,指定视口混合。
当使用着色器对象进行绘制时,或者当图形管线创建时,在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV
,此命令为后续绘制命令设置视口混合状态。否则,此状态由用于创建当前活动管线的 VkPipelineViewportSwizzleStateCreateInfoNV::viewportCount
和 VkPipelineViewportSwizzleStateCreateInfoNV::pViewportSwizzles
值指定。
从 0 到 viewportCount
- 1 指定的每个视口的 x、y、z、w 混合状态被设置为 VkViewportSwizzleNV 结构体中对应的 x
、y
、z
和 w
。每个分量都是 VkViewportCoordinateSwizzleNV 类型,它决定了该分量的混合类型。x
的值计算位置的新 x 分量为:
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV) x' = x;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV) x' = -x;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV) x' = y;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV) x' = -y;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV) x' = z;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV) x' = -z;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV) x' = w;
if (x == VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV) x' = -w;
对 y
、z
和 w
坐标执行类似的选取。此混合在裁剪和透视除法之前应用。如果未指定活动视口索引的混合,则 x
的混合为 VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV
,y
为 VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV
,z
为 VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV
,而 w
为 VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV
。
视口混合参数通过将 VkGraphicsPipelineCreateInfo
的 pNext
指针设置为指向 VkPipelineViewportSwizzleStateCreateInfoNV
结构体来指定。VkPipelineViewportSwizzleStateCreateInfoNV 使用 VkViewportSwizzleNV
来设置视口混合参数。
VkViewportSwizzleNV
结构体定义如下:
// Provided by VK_NV_viewport_swizzle
typedef struct VkViewportSwizzleNV {
VkViewportCoordinateSwizzleNV x;
VkViewportCoordinateSwizzleNV y;
VkViewportCoordinateSwizzleNV z;
VkViewportCoordinateSwizzleNV w;
} VkViewportSwizzleNV;
-
x
是一个 VkViewportCoordinateSwizzleNV 值,指定要应用于图元 x 分量的混合操作 -
y
是一个 VkViewportCoordinateSwizzleNV 值,指定要应用于图元 y 分量的混合操作 -
z
是一个 VkViewportCoordinateSwizzleNV 值,指定要应用于图元 z 分量的混合操作 -
w
是一个 VkViewportCoordinateSwizzleNV 值,指定要应用于图元 w 分量的混合操作
VkViewportSwizzleNV::x
、y
、z
和 w
成员的可能值,指定图元相应分量的混合如下:
// Provided by VK_NV_viewport_swizzle
typedef enum VkViewportCoordinateSwizzleNV {
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
} VkViewportCoordinateSwizzleNV;
这些值在视口混合中详细描述。
平面着色
平面着色一个顶点输出属性意味着将图元的所有顶点分配给该输出的相同值。分配的输出值是图元的引发顶点的值。平面着色应用于那些与被装饰为 Flat
的片段输入属性匹配的顶点属性。
如果网格着色(mesh)、几何着色(geometry)或曲面细分着色(tessellation shading)均未激活,则触发顶点由执行绘制命令时使用的、由VkPipelineInputAssemblyStateCreateInfo定义的图元拓扑结构的topology
确定。
如果激活了使用 MeshNV
Execution
Model
的着色器,则触发顶点由OutputPoints
、OutputLinesNV
或OutputTrianglesNV
执行模式定义的图元拓扑结构确定。
如果激活了使用 MeshEXT
Execution
Model
的着色器,则触发顶点由OutputPoints
、OutputLinesEXT
或OutputTrianglesEXT
执行模式定义的图元拓扑结构确定。
如果几何着色处于激活状态,则触发顶点由OutputPoints
、OutputLineStrip
或OutputTriangleStrip
执行模式定义的图元拓扑结构确定。
对于给定的图元拓扑结构,管线的触发顶点模式决定哪个顶点是触发顶点。要指定触发顶点模式,请在创建管线时,将 VkPipelineRasterizationProvokingVertexStateCreateInfoEXT
结构体包含在VkPipelineRasterizationStateCreateInfo::pNext
链中。
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT
结构体的定义如下:
// Provided by VK_EXT_provoking_vertex
typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkProvokingVertexModeEXT provokingVertexMode;
} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
为NULL
或指向扩展此结构的结构的指针。 -
provokingVertexMode
是一个 VkProvokingVertexModeEXT 值,用于选择触发顶点模式。
如果在创建管线时未提供此结构体,则管线将使用 VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT
模式。
如果 provokingVertexModePerPipeline
限制为 VK_FALSE
,则渲染过程实例中绑定的所有管线必须具有相同的 provokingVertexMode
。
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT::provokingVertexMode
的可能值如下:
// Provided by VK_EXT_provoking_vertex
typedef enum VkProvokingVertexModeEXT {
VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0,
VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1,
} VkProvokingVertexModeEXT;
-
VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT
指定触发顶点是图元使用的顶点列表中第一个非邻接顶点。 -
VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT
指定触发顶点是图元使用的顶点列表中最后一个非邻接顶点。
这些模式在图元拓扑结构中进行了更精确的描述。
要动态设置 provokingVertexMode
状态,请调用:
// Provided by VK_EXT_extended_dynamic_state3 with VK_EXT_provoking_vertex, VK_EXT_provoking_vertex with VK_EXT_shader_object
void vkCmdSetProvokingVertexModeEXT(
VkCommandBuffer commandBuffer,
VkProvokingVertexModeEXT provokingVertexMode);
-
commandBuffer
是将记录命令的命令缓冲区。 -
provokingVertexMode
指定provokingVertexMode
状态。
当使用着色器对象进行绘制,或者在VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT
的情况下创建图形管线时,此命令为后续绘制命令设置 provokingVertexMode
状态。否则,此状态由用于创建当前活动管线的 VkPipelineRasterizationProvokingVertexStateCreateInfoEXT::provokingVertexMode
值指定。
图元裁剪
图元会根据剔除体进行剔除,然后被裁剪到裁剪体。在裁剪坐标中,视见体定义为:
其中,如果 VkPipelineViewportDepthClipControlCreateInfoEXT::negativeOneToOne
为 VK_TRUE
,则 zm 等于 -wc,否则 zm 等于零。
此视见体可以受到最多 VkPhysicalDeviceLimits
::maxClipDistances
个应用程序定义的半空间的进一步限制。
剔除体是最多 VkPhysicalDeviceLimits
::maxCullDistances
个应用程序定义的半空间的交集(如果未启用任何应用程序定义的剔除半空间,则会跳过针对剔除体的剔除)。
着色器必须为每个启用的剔除半空间向 CullDistance
数组的元素写入单个剔除距离。如果对于正在考虑的图元的所有顶点,任何启用剔除半空间的剔除距离为负,则该图元将被丢弃。否则,该图元将按照如下定义被裁剪到裁剪体。
裁剪体是最多 VkPhysicalDeviceLimits
::maxClipDistances
个应用程序定义的半空间与视见体的交集(如果未启用任何应用程序定义的裁剪半空间,则裁剪体为视见体)。
着色器必须为每个启用的裁剪半空间向 ClipDistance
数组的元素写入单个裁剪距离。裁剪半空间 i 由满足以下不等式的点集给出:
-
ci(P) ≥ 0
其中 ci(P) 是点 P 处的裁剪距离 i。对于点图元,ci(P) 只是相关顶点的裁剪距离。对于线和三角形图元,每个顶点的裁剪距离使用加权平均值进行插值,权重根据 基本线段光栅化 和 基本多边形光栅化 部分中描述的算法得出,并使用透视插值方程。
启用的应用程序定义的裁剪和剔除半空间的数量分别由内置数组 ClipDistance
和 CullDistance
的显式大小决定,这两个数组在裁剪之前的最终着色器阶段的入口点的接口中声明为输出。
如果图形管线状态中存在 VkPipelineRasterizationDepthClipStateCreateInfoEXT,则当 VkPipelineRasterizationDepthClipStateCreateInfoEXT::depthClipEnable
为 VK_FALSE
时,深度裁剪将被禁用。否则,如果不存在 VkPipelineRasterizationDepthClipStateCreateInfoEXT,则当 VkPipelineRasterizationStateCreateInfo::depthClampEnable
为 VK_TRUE
时,深度裁剪将被禁用。
要动态设置启用或禁用深度钳位,请调用
// Provided by VK_EXT_extended_dynamic_state3, VK_EXT_shader_object
void vkCmdSetDepthClampEnableEXT(
VkCommandBuffer commandBuffer,
VkBool32 depthClampEnable);
-
commandBuffer
是将记录命令的命令缓冲区。 -
depthClampEnable
指定是否启用深度钳位。
当使用着色器对象进行绘制时,或者当使用在VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置的 VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT
创建图形管线时,此命令设置后续绘制命令是否启用或禁用深度钳位。否则,此状态由用于创建当前活动管线的VkPipelineRasterizationStateCreateInfo::depthClampEnable
值指定。
如果动态更改深度钳位状态,并且创建管线时未启用 VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT
,则当禁用深度钳位时启用深度裁剪,反之亦然。
要动态设置启用或禁用深度裁剪,请调用
// Provided by VK_EXT_depth_clip_enable with VK_EXT_extended_dynamic_state3, VK_EXT_depth_clip_enable with VK_EXT_shader_object
void vkCmdSetDepthClipEnableEXT(
VkCommandBuffer commandBuffer,
VkBool32 depthClipEnable);
-
commandBuffer
是将记录命令的命令缓冲区。 -
depthClipEnable
指定是否启用深度裁剪。
当使用着色器对象进行绘制时,或者当使用在VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置的 VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT
创建图形管线时,此命令设置后续绘制命令是否启用或禁用深度裁剪。否则,此状态由用于创建当前活动管线的VkPipelineRasterizationDepthClipStateCreateInfoEXT::depthClipEnable
值指定,如果未指定 VkPipelineRasterizationDepthClipStateCreateInfoEXT
,则由 VkPipelineRasterizationStateCreateInfo::depthClampEnable
的反向值指定。
当禁用深度裁剪时,平面方程
-
zm ≤ zc ≤ wc
(请参阅上面的裁剪体定义)被视图体裁剪忽略(实际上,没有近平面或远平面裁剪)。
如果正在考虑的图元是点或线段,则如果其顶点完全位于裁剪体内部,则裁剪将保持不变。
VkPhysicalDevicePointClippingProperties::pointClippingBehavior
的可能值,指定顶点位于裁剪体外部的点图元的裁剪行为如下:
// Provided by VK_VERSION_1_1
typedef enum VkPointClippingBehavior {
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
// Provided by VK_KHR_maintenance2
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
// Provided by VK_KHR_maintenance2
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY,
} VkPointClippingBehavior;
或等效的
// Provided by VK_KHR_maintenance2
typedef VkPointClippingBehavior VkPointClippingBehaviorKHR;
-
VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES
指定如果顶点位于任何裁剪平面(包括边界视图体的平面)之外,则丢弃该图元。 -
VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY
指定仅当顶点位于任何用户裁剪平面之外时才丢弃该图元。
如果线段的任何一个顶点位于裁剪体之外,则 **可以** 裁剪该线段,并为位于裁剪体外部的每个顶点计算新的顶点坐标。裁剪的线段端点位于原始线段和裁剪体的边界上。
此裁剪为每个裁剪的顶点生成一个值 0 ≤ t ≤ 1。如果裁剪顶点的坐标为 P,而未裁剪的线段的顶点坐标为 P1 和 P2,则 t 满足以下方程
-
P = t P1 + (1-t) P2.
t 用于裁剪顶点输出属性,如 裁剪着色器输出 中所述。
如果图元是多边形,如果其每个边都完全位于裁剪体内部,则该多边形将保持不变,否则将被裁剪或丢弃。如果多边形的边与裁剪体边界相交,则相交的边将通过位于裁剪体边界上的新边重新连接 - 在某些情况下需要将新顶点引入多边形中。
如果多边形与裁剪体边界的边相交,则裁剪后的多边形 **必须** 包括此边界边上的一个点。
使用应用程序定义的半空间渲染的图元必须满足互补性准则。假设绘制一系列图元,其中每个顶点 i 都有一个指定的裁剪距离 di (如果启用了多个半空间,则可能有多个类似指定的裁剪距离)。接下来,假设再次绘制相同的图元系列,但将每个此类裁剪距离替换为 -di (并且图形管线的其余部分保持不变)。在这种情况下,图元不能遗漏任何像素,并且在被裁剪平面切割的区域中,像素不能被绘制两次。
VkPipelineViewportDepthClipControlCreateInfoEXT
结构定义如下:
// Provided by VK_EXT_depth_clip_control
typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkBool32 negativeOneToOne;
} VkPipelineViewportDepthClipControlCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
为NULL
或指向扩展此结构的结构的指针。 -
negativeOneToOne
将视图体中的 zm 设置为 -wc
要动态设置 negativeOneToOne
,请调用:
// Provided by VK_EXT_depth_clip_control with VK_EXT_extended_dynamic_state3, VK_EXT_depth_clip_control with VK_EXT_shader_object
void vkCmdSetDepthClipNegativeOneToOneEXT(
VkCommandBuffer commandBuffer,
VkBool32 negativeOneToOne);
-
commandBuffer
是将记录命令的命令缓冲区。 -
negativeOneToOne
指定negativeOneToOne
状态。
当使用 着色器对象 进行绘制,或者在创建图形管线时,在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT
时,此命令会为后续绘制命令设置 negativeOneToOne
状态。否则,此状态由用于创建当前活动管线的 VkPipelineViewportDepthClipControlCreateInfoEXT::negativeOneToOne
值指定。
裁剪着色器输出
接下来,裁剪顶点输出属性。与位于裁剪体内的顶点关联的输出值不受裁剪的影响。但是,如果裁剪了图元,则分配给由裁剪产生的顶点的输出值也将被裁剪。
假设未裁剪的边的两个顶点 P1 和 P2 的输出值分别为 c1 和 c2。对于裁剪点 P,t 的值(请参阅图元裁剪)用于获得与 P 关联的输出值,如下所示:
-
c = t c1 + (1-t) c2.
(将输出值乘以标量意味着将 x、y、z 和 w 的每个分量都乘以该标量。)
由于此计算是在除以 wc 之前在裁剪空间中执行的,因此裁剪的输出值是透视正确的。
多边形裁剪会在裁剪体的边界边缘创建一个裁剪的顶点。通过注意多边形裁剪每次都针对一个半空间进行裁剪来处理这种情况。输出值裁剪也以相同的方式完成,以便裁剪点始终出现在多边形边缘(可能已裁剪)与裁剪体边界的交点处。
对于其匹配的片段输入属性使用 NoPerspective
修饰的顶点输出属性,用于获得与 P 关联的输出值的 t 值将进行调整,以产生在帧缓冲区空间中线性变化的结果。
控制视口 W 缩放
如果启用了视口 W 缩放,则剪辑坐标的 W 分量将按照以下方式,由相应视口提供的系数进行修改。
-
wc' = xcoeff xc + ycoeff yc + wc
VkPipelineViewportWScalingStateCreateInfoNV
结构定义如下:
// Provided by VK_NV_clip_space_w_scaling
typedef struct VkPipelineViewportWScalingStateCreateInfoNV {
VkStructureType sType;
const void* pNext;
VkBool32 viewportWScalingEnable;
uint32_t viewportCount;
const VkViewportWScalingNV* pViewportWScalings;
} VkPipelineViewportWScalingStateCreateInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
为NULL
或指向扩展此结构的结构的指针。 -
viewportWScalingEnable
控制是否启用视口 W 缩放。 -
viewportCount
是 W 缩放使用的视口数量,如果启用了视口 W 缩放,则必须与管线中的视口数量匹配。 -
pViewportWScalings
是指向 VkViewportWScalingNV 结构数组的指针,这些结构定义了相应视口的 W 缩放参数。如果视口 W 缩放状态是动态的,则忽略此成员。
VkPipelineViewportWScalingStateCreateInfoNV
状态通过将此结构添加到 VkPipelineViewportStateCreateInfo
结构的 pNext
链中,并使用 vkCreateGraphicsPipelines 设置图形管线状态来设置。
要动态设置 viewportWScalingEnable
状态,请调用
// Provided by VK_EXT_extended_dynamic_state3 with VK_NV_clip_space_w_scaling, VK_EXT_shader_object with VK_NV_clip_space_w_scaling
void vkCmdSetViewportWScalingEnableNV(
VkCommandBuffer commandBuffer,
VkBool32 viewportWScalingEnable);
-
commandBuffer
是将记录命令的命令缓冲区。 -
viewportWScalingEnable
指定viewportWScalingEnable
状态。
当使用 着色器对象 绘图,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV
时创建时,此命令为后续的绘制命令设置 viewportWScalingEnable
状态。否则,此状态由用于创建当前活动管线的 VkPipelineViewportWScalingStateCreateInfoNV::viewportWScalingEnable
值指定。
要动态设置视口 W 缩放参数,请调用
// Provided by VK_NV_clip_space_w_scaling
void vkCmdSetViewportWScalingNV(
VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewportWScalingNV* pViewportWScalings);
-
commandBuffer
是将记录命令的命令缓冲区。 -
firstViewport
是由命令更新其参数的第一个视口的索引。 -
viewportCount
是由命令更新其参数的视口数量。 -
pViewportWScalings
是指向 VkViewportWScalingNV 结构数组的指针,用于指定视口参数。
从 pViewportWScalings
的元素 i 中获取的视口参数将替换视口索引为 firstViewport
+ i 的当前状态,其中 i 在 [0, viewportCount
) 范围内。
当使用 着色器对象 绘图,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV
时创建时,此命令为后续的绘制命令设置视口 W 缩放。否则,此状态由用于创建当前活动管线的 VkPipelineViewportWScalingStateCreateInfoNV::pViewportWScalings
值指定。
VkPipelineViewportWScalingStateCreateInfoNV 和 vkCmdSetViewportWScalingNV 都使用 VkViewportWScalingNV
来设置视口变换参数。
VkViewportWScalingNV
结构的定义如下:
// Provided by VK_NV_clip_space_w_scaling
typedef struct VkViewportWScalingNV {
float xcoeff;
float ycoeff;
} VkViewportWScalingNV;
-
xcoeff
和ycoeff
分别是视口在 x 和 y 方向上的 W 缩放因子。
坐标变换
顶点的裁剪坐标来自着色器执行,其产生一个顶点坐标 Position
。
在裁剪坐标上进行透视除法会产生归一化设备坐标,然后进行视口变换(请参阅 控制视口),将这些坐标转换为帧缓冲区坐标。
如果裁剪坐标中的顶点位置由下式给出:
则该顶点的归一化设备坐标为:
渲染通道变换
可以为渲染通道实例启用渲染通道变换。由顶点着色器执行产生的裁剪坐标 (xc, yc) 在 XY 平面中,以原点为中心旋转 0、90、180 或 270 度进行变换。
当启用渲染通道变换时,该变换应用于渲染通道的所有子通道的所有图元。变换后的裁剪坐标中的顶点位置由下式给出:
其中
-
θ 对于
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
为 0 度 -
θ 对于
VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR
为 90 度 -
θ 对于
VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR
为 180 度 -
θ 对于
VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR
为 270 度
变换后的顶点的归一化设备坐标为:
当为渲染通道实例启用渲染通道变换时,将启用以下附加特性:
-
由 VkPipelineViewportStateCreateInfo::
pViewports
或 vkCmdSetViewport 指定的每个 VkViewport 的宽度/高度 (px, py) 及其中心 (ox, oy) 也将由实现以类似方式进行变换。 -
由 VkPipelineViewportStateCreateInfo::
pScissors
或 vkCmdSetScissor 指定的每个剪裁矩形的 (offsetx, offsety) 和 (extentx, extenty) 也将由实现以类似方式进行变换。 -
在 VkCommandBufferInheritanceRenderPassTransformInfoQCOM 和 VkRenderPassBeginInfo 中指定的
renderArea
也将由实现以类似方式进行变换。 -
具有内置装饰
FragCoord
、SamplePosition
或PointCoord
的着色器变量的 (x, y) 分量也将由实现以类似方式进行变换。 -
InterpolateAtOffset
扩展指令的offset
操作数的 (x,y) 分量也将由实现以类似方式进行变换。 -
SPIR-V 导数指令
OpDPdx
、OpDPdy
、OpDPdxCourse
、OpDPdyCourse
、OpDPdxFine
、OpDPdyFine
返回的值也将由实现以类似方式进行变换。
上述的最终结果是,应用程序可以表现得好像是渲染到以VkSurfaceCapabilitiesKHR::currentTransform
为方向的帧缓冲区。换句话说,应用程序可以表现得好像演示引擎将在渲染之后、呈现给用户之前执行交换链图像的转换。实际上,上述各种项目的转换是在渲染进行时由实现处理的。
控制视口
视口变换由所选视口的宽度和高度(以像素为单位),分别为 px 和 py,及其中心 (ox, oy)(也以像素为单位)以及其深度范围最小值和最大值决定,它们确定了深度范围比例值 pz 和深度范围偏移值 oz(定义如下)。顶点的帧缓冲区坐标 (xf, yf) 和深度 zf 由下式给出:
-
xf = (px / 2) xd + ox
-
yf = (py / 2) yd + oy
-
zf = pz × zd + oz
可以使用多个视口,编号从零到 VkPhysicalDeviceLimits
::maxViewports
减一。管线使用的视口数量由管线创建中使用的 VkPipelineViewportStateCreateInfo
结构的 viewportCount
成员控制。
xf 和 yf 的精度有限,其中保留的小数位数由 VkPhysicalDeviceLimits
::subPixelPrecisionBits
指定。当栅格化线段时,小数位数由 VkPhysicalDeviceLineRasterizationProperties
::lineSubPixelPrecisionBits
指定。
VkPipelineViewportStateCreateInfo
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkPipelineViewportStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineViewportStateCreateFlags flags;
uint32_t viewportCount;
const VkViewport* pViewports;
uint32_t scissorCount;
const VkRect2D* pScissors;
} VkPipelineViewportStateCreateInfo;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
为NULL
或指向扩展此结构的结构的指针。 -
flags
保留供将来使用。 -
viewportCount
是管线使用的视口数量。 -
pViewports
是指向 VkViewport 结构数组的指针,定义了视口变换。如果视口状态是动态的,则忽略此成员。 -
scissorCount
是剪裁的数量,并且必须与视口的数量匹配。 -
pScissors
是指向 VkRect2D 结构数组的指针,定义了相应视口的剪裁矩形边界。如果剪裁状态是动态的,则忽略此成员。
要动态设置视口计数和视口,请调用:
// Provided by VK_VERSION_1_3
void vkCmdSetViewportWithCount(
VkCommandBuffer commandBuffer,
uint32_t viewportCount,
const VkViewport* pViewports);
或等效命令:
// Provided by VK_EXT_extended_dynamic_state, VK_EXT_shader_object
void vkCmdSetViewportWithCountEXT(
VkCommandBuffer commandBuffer,
uint32_t viewportCount,
const VkViewport* pViewports);
-
commandBuffer
是将记录命令的命令缓冲区。 -
viewportCount
指定视口计数。 -
pViewports
指定用于绘制的视口。
当使用着色器对象进行绘制,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT
时创建时,此命令设置后续绘制命令的视口计数和视口状态。否则,此状态由用于创建当前活动管线的相应的 VkPipelineViewportStateCreateInfo::viewportCount
和 pViewports
值指定。
要动态设置剪裁计数和剪裁矩形边界,请调用
// Provided by VK_VERSION_1_3
void vkCmdSetScissorWithCount(
VkCommandBuffer commandBuffer,
uint32_t scissorCount,
const VkRect2D* pScissors);
或等效命令:
// Provided by VK_EXT_extended_dynamic_state, VK_EXT_shader_object
void vkCmdSetScissorWithCountEXT(
VkCommandBuffer commandBuffer,
uint32_t scissorCount,
const VkRect2D* pScissors);
-
commandBuffer
是将记录命令的命令缓冲区。 -
scissorCount
指定剪裁计数。 -
pScissors
指定用于绘制的剪裁。
当使用着色器对象进行绘制,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT
时创建时,此命令设置后续绘制命令的剪裁计数和剪裁矩形边界状态。否则,此状态由用于创建当前活动管线的相应的 VkPipelineViewportStateCreateInfo::scissorCount
和 pScissors
值指定。
// Provided by VK_VERSION_1_0
typedef VkFlags VkPipelineViewportStateCreateFlags;
VkPipelineViewportStateCreateFlags
是用于设置掩码的位掩码类型,但目前保留以供将来使用。
一个 *预光栅化着色器阶段* **可以** 将每个图元定向到零个或多个视口。图元的目的地视口由最后一个活动的预光栅化着色器阶段选择,该阶段具有一个用 ViewportIndex
(选择单个视口)或 ViewportMaskNV
(选择多个视口)修饰的输出变量。视口变换使用与分配给 ViewportIndex
的值或 ViewportMaskNV
中设置的位对应的视口,并从每个图元的实现相关的顶点中获取。如果 ViewportIndex
或 ViewportMaskNV
中的任何位对于图元超出零到 viewportCount
减一的范围,或者如果最后一个活动的预光栅化着色器阶段由于流控制而未为图元的所有顶点分配值给 ViewportIndex
或 ViewportMaskNV
,则此类图元的顶点的视口变换产生的值是**未定义的**。如果最后一个 预光栅化着色器阶段 没有用 ViewportIndex
或 ViewportMaskNV
修饰的输出,则视口变换使用编号为零的视口。
单个顶点 **可以** 在多个单独的图元中使用,例如 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
中的图元。在这种情况下,视口变换分别应用于每个图元。
要动态设置视口变换参数,请调用
// Provided by VK_VERSION_1_0
void vkCmdSetViewport(
VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewport* pViewports);
-
commandBuffer
是将记录命令的命令缓冲区。 -
firstViewport
是由命令更新其参数的第一个视口的索引。 -
viewportCount
是由命令更新其参数的视口数量。 -
pViewports
是指向 VkViewport 结构数组的指针,该数组指定视口参数。
此命令为后续使用着色器对象进行绘制的命令,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates
中设置了 VK_DYNAMIC_STATE_VIEWPORT
时,设置视口变换参数状态。否则,此状态由用于创建当前活动管线的 VkPipelineViewportStateCreateInfo
::pViewports
值指定。
从 pViewports
的第 i 个元素获取的视口参数将替换视口索引为 firstViewport
+ i 的当前状态,其中 i 在 [0, viewportCount
) 范围内。
VkPipelineViewportStateCreateInfo 和 vkCmdSetViewport 都使用 VkViewport
来设置视口变换参数。
VkViewport
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkViewport {
float x;
float y;
float width;
float height;
float minDepth;
float maxDepth;
} VkViewport;
-
x
和y
是视口的左上角坐标 (x,y)。 -
width
和height
分别是视口的宽度和高度。 -
minDepth
和maxDepth
是视口的深度范围。
尽管有这些名称, |
帧缓冲深度坐标 z
f 可以使用定点或浮点表示形式。但是,如果深度/模板附件具有浮点深度分量,则必须使用浮点表示形式。如果使用 m 位定点表示形式,我们假设它将每个值
上述公式中显示的视口参数由以下值计算得出:
-
ox =
x
+width
/ 2 -
oy =
y
+height
/ 2 -
oz =
minDepth
(或者,如果 VkPipelineViewportDepthClipControlCreateInfoEXT::negativeOneToOne
为VK_TRUE
,则为 (maxDepth
+minDepth
) / 2) -
px =
width
-
py =
height
-
pz =
maxDepth
-minDepth
(或者,如果 VkPipelineViewportDepthClipControlCreateInfoEXT::negativeOneToOne
为VK_TRUE
,则为 (maxDepth
-minDepth
) / 2)
如果启用了渲染通道变换,则定义视口的 (px,py) 和 (ox, oy) 值将按照渲染通道变换中的描述进行变换,然后再参与视口变换。
应用程序可以为 height
指定一个负值,这将导致在执行变换之前反转裁剪空间中的 y 坐标。当使用负的 height
时,应用程序还应该调整 y
值,使其指向视口的左下角而不是左上角。使用负的 height
允许应用程序避免反转来自最后一个光栅化前着色器阶段的 Position
输出的 y 分量。
实现相关的最大视口尺寸 的宽度和高度必须大于或等于可以创建并附加到帧缓冲区的最大图像的宽度和高度。
浮点视口边界以实现相关的精度表示。