固定功能顶点后处理
变换反馈
在任何其他固定功能顶点后处理之前,光栅化前着色器阶段中最后一个着色器的顶点输出可以写入绑定到命令缓冲区的一个或多个变换反馈缓冲区。要捕获顶点输出,最后一个光栅化前着色器阶段着色器必须使用 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是视口的深度范围。
|
尽管有这些名称, |
帧缓冲深度坐标 zf 可以使用定点或浮点表示形式。但是,如果深度/模板附件具有浮点深度分量,则必须使用浮点表示形式。如果使用 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 分量。
实现相关的最大视口尺寸 的宽度和高度必须大于或等于可以创建并附加到帧缓冲区的最大图像的宽度和高度。
浮点视口边界以实现相关的精度表示。