固定功能顶点处理
顶点获取通过可配置的状态来控制,作为一个逻辑上独立的图形管线阶段。
顶点属性
顶点着色器可以定义输入变量,这些变量接收由绘制命令从一个或多个 VkBuffer 传输的顶点属性数据。顶点着色器输入变量通过间接绑定绑定到缓冲区,其中顶点着色器将一个顶点输入属性编号与每个变量关联,顶点输入属性与每个管线的顶点输入绑定关联,而顶点输入绑定通过 vkCmdBindVertexBuffers 命令与每个绘制的特定缓冲区关联。顶点输入属性和顶点输入绑定描述还包含格式信息,用于控制如何从缓冲区内存中提取数据并将其转换为顶点着色器期望的格式。
有 VkPhysicalDeviceLimits::maxVertexInputAttributes 个顶点输入属性和 VkPhysicalDeviceLimits::maxVertexInputBindings 个顶点输入绑定(每个都由从零开始的索引引用),其中至少有与顶点输入绑定一样多的顶点输入属性。应用程序可以将多个顶点输入属性交错存储在单个缓冲区中,并使用单个顶点输入绑定来访问这些属性。
在 GLSL 中,顶点着色器使用 location 布局限定符将输入变量与顶点输入属性编号关联。Component 布局限定符将顶点着色器输入变量的分量与顶点输入属性的分量关联。
// Assign location M to variableName
layout (location=M, component=2) in vec2 variableName;
// Assign locations [N,N+L) to the array elements of variableNameArray
layout (location=N) in vec4 variableNameArray[L];
在 SPIR-V 中,顶点着色器使用 Location 修饰将输入变量与顶点输入属性编号关联。Component 修饰将顶点着色器输入变量的分量与顶点输入属性的分量关联。Location 和 Component 修饰通过 OpDecorate 指令指定。
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "variableName"
OpName %15 "variableNameArray"
OpDecorate %18 BuiltIn VertexIndex
OpDecorate %19 BuiltIn InstanceIndex
OpDecorate %9 Location M
OpDecorate %9 Component 2
OpDecorate %15 Location N
...
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 2
%8 = OpTypePointer Input %7
%9 = OpVariable %8 Input
%10 = OpTypeVector %6 4
%11 = OpTypeInt 32 0
%12 = OpConstant %11 L
%13 = OpTypeArray %10 %12
%14 = OpTypePointer Input %13
%15 = OpVariable %14 Input
...
属性位置和组件分配
Location 修饰指定使用哪个顶点输入属性来读取和解释变量将要消耗的数据。
当使用 16 位或 32 位标量或向量数据类型声明的顶点着色器输入变量被分配 Location 时,其值取自使用对应的 VkVertexInputAttributeDescription::location 指定的输入属性的分量。使用的分量取决于变量的类型和变量声明中指定的 Component 修饰,如 16 位和 32 位输入变量访问的输入属性分量 中所述。任何 16 位或 32 位标量或向量输入都将消耗单个 Location。对于 16 位和 32 位数据类型,缺少的组件将使用 下文 中描述的默认值填充。
如果实现支持 storageInputOutput16,则顶点着色器输入变量的宽度可以为 16 位。
在以下所有组件分配规范中,如果启用了 vertexAttributeRobustness 并且没有为正在读取的着色器顶点属性 Location 指定 VkVertexInputAttributeDescription::location,则对于下面指定的每个等效的 (x,y,z,w) 组件消耗条目,将使用值 (0,0,0,0) 或 (0,0,0,1)。
| 16 位或 32 位数据类型 | Component 修饰 |
消耗的分量 |
|---|---|---|
标量 |
0 或未指定 |
(x, o, o, o) |
标量 |
1 |
(o, y, o, o) |
标量 |
2 |
(o, o, z, o) |
标量 |
3 |
(o, o, o, w) |
双分量向量 |
0 或未指定 |
(x, y, o, o) |
双分量向量 |
1 |
(o, y, z, o) |
双分量向量 |
2 |
(o, o, z, w) |
三分量向量 |
0 或未指定 |
(x, y, z, o) |
三分量向量 |
1 |
(o, y, z, w) |
四分量向量 |
0 或未指定 |
(x, y, z, w) |
由“o”指示的分量可供其他来自同一属性的输入变量使用,如果使用,则要么用输入格式中的相应分量(如果存在)填充,要么使用默认值填充。
当使用 32 位浮点矩阵类型声明的顶点着色器输入变量被分配 Location i 时,其值取自从对应的 VkVertexInputAttributeDescription::location 开始的连续输入属性。此类矩阵被视为列向量的数组,其值取自 32 位输入矩阵变量访问的输入属性 中标识的输入属性。 VkVertexInputAttributeDescription::format 必须使用与相应类型的列向量对应的 VkFormat 指定。Component 修饰不能与矩阵类型一起使用。
| 数据类型 | 列向量类型 | 消耗的位置 | 消耗的分量 |
|---|---|---|---|
mat2 |
双分量向量 |
i, i+1 |
(x, y, o, o), (x, y, o, o) |
mat2x3 |
三分量向量 |
i, i+1 |
(x, y, z, o), (x, y, z, o) |
mat2x4 |
四分量向量 |
i, i+1 |
(x, y, z, w), (x, y, z, w) |
mat3x2 |
双分量向量 |
i, i+1, i+2 |
(x, y, o, o), (x, y, o, o), (x, y, o, o) |
mat3 |
三分量向量 |
i, i+1, i+2 |
(x, y, z, o), (x, y, z, o), (x, y, z, o) |
mat3x4 |
四分量向量 |
i, i+1, i+2 |
(x, y, z, w), (x, y, z, w), (x, y, z, w) |
mat4x2 |
双分量向量 |
i, i+1, i+2, i+3 |
(x, y, o, o), (x, y, o, o), (x, y, o, o), (x, y, o, o) |
mat4x3 |
三分量向量 |
i, i+1, i+2, i+3 |
(x, y, z, o), (x, y, z, o), (x, y, z, o), (x, y, z, o) |
mat4 |
四分量向量 |
i, i+1, i+2, i+3 |
(x, y, z, w), (x, y, z, w), (x, y, z, w), (x, y, z, w) |
用 “o” 表示的组件可供来自同一属性的其他输入变量使用,如果使用,则会填充来自输入的相应组件(如果存在),或使用默认值。
当使用标量或向量 64 位数据类型声明的顶点着色器输入变量被分配 Location i 时,其值取自连续的输入属性,从相应的 VkVertexInputAttributeDescription::location 开始。使用的 Location 插槽和 Component 字取决于变量的类型和变量声明中指定的 Component 修饰符,如 64 位输入变量访问的输入属性位置和组件 中所述。对于 64 位数据类型,不提供默认属性值。输入变量不得使用超出属性提供的组件数量。
| 输入格式 | 消耗的位置 | 64 位数据类型 | Location 修饰符 |
Component 修饰 |
使用的 32 位组件 |
|---|---|---|---|---|---|
R64 |
i |
标量 |
i |
0 或未指定 |
(x, y, -, -) |
R64G64 |
i |
标量 |
i |
0 或未指定 |
(x, y, o, o) |
标量 |
i |
2 |
(o, o, z, w) |
||
双分量向量 |
i |
0 或未指定 |
(x, y, z, w) |
||
R64G64B64 |
i, i+1 |
标量 |
i |
0 或未指定 |
(x, y, o, o), (o, o, -, -) |
标量 |
i |
2 |
(o, o, z, w), (o, o, -, -) |
||
标量 |
i+1 |
0 或未指定 |
(o, o, o, o), (x, y, -, -) |
||
双分量向量 |
i |
0 或未指定 |
(x, y, z, w), (o, o, -, -) |
||
三分量向量 |
i |
未指定 |
(x, y, z, w), (x, y, -, -) |
||
R64G64B64A64 |
i, i+1 |
标量 |
i |
0 或未指定 |
(x, y, o, o), (o, o, o, o) |
标量 |
i |
2 |
(o, o, z, w), (o, o, o, o) |
||
标量 |
i+1 |
0 或未指定 |
(o, o, o, o), (x, y, o, o) |
||
标量 |
i+1 |
2 |
(o, o, o, o), (o, o, z, w) |
||
双分量向量 |
i |
0 或未指定 |
(x, y, z, w), (o, o, o, o) |
||
双分量向量 |
i+1 |
0 或未指定 |
(o, o, o, o), (x, y, z, w) |
||
三分量向量 |
i |
未指定 |
(x, y, z, w), (x, y, o, o) |
||
四分量向量 |
i |
未指定 |
(x, y, z, w), (x, y, z, w) |
用 “o” 表示的组件可供来自同一属性的其他输入变量使用。 用 “-” 表示的组件不适用于输入变量,因为 64 位数据类型没有提供默认值,并且输入格式不提供数据。
当使用 64 位浮点矩阵类型声明的顶点着色器输入变量被分配 Location i 时,其值取自连续的输入属性位置。此类矩阵被视为列向量数组,其值取自输入属性,如 64 位输入变量访问的输入属性位置和组件 中所示。每个列向量从紧跟前一个列向量的最后一个 Location 的 Location 开始。分配给每个矩阵的属性和组件数量由矩阵维度决定,范围从两个到八个位置。
当使用数组类型声明的顶点着色器输入变量被分配位置时,其值取自连续的输入属性,从相应的 VkVertexInputAttributeDescription::location 开始。分配给每个元素的属性和组件的数量根据数组元素的类型和数组声明中指定的 Component 修饰符(如果有)确定,如上所述。数组的每个元素按顺序分配给连续的位置,但都在每个位置内的同一指定组件。
仅支持使用上述指定的数据类型和组件修饰符声明的输入变量。仅当两个变量的 Component 字不重叠时,才允许它们共享同一个 Location 插槽。如果多个变量共享同一个 Location 插槽,它们必须都具有相同的 SPIR-V 浮点组件类型或都具有相同宽度的标量类型组件。
顶点输入描述
应用程序通过将 VkGraphicsPipelineCreateInfo::pVertexInputState 指针设置为 VkPipelineVertexInputStateCreateInfo 结构,指定作为图形管线创建一部分的顶点输入属性和顶点输入绑定描述。或者,如果使用启用了 VK_DYNAMIC_STATE_VERTEX_INPUT_EXT 动态状态创建图形管线,则顶点输入属性和顶点输入绑定描述将使用 vkCmdSetVertexInputEXT 动态指定,并且 VkGraphicsPipelineCreateInfo::pVertexInputState 指针将被忽略。
VkPipelineVertexInputStateCreateInfo 结构的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkPipelineVertexInputStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineVertexInputStateCreateFlags flags;
uint32_t vertexBindingDescriptionCount;
const VkVertexInputBindingDescription* pVertexBindingDescriptions;
uint32_t vertexAttributeDescriptionCount;
const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
} VkPipelineVertexInputStateCreateInfo;
-
sType是一个 VkStructureType 值,用于标识此结构。 -
pNext为NULL或指向扩展此结构的结构的指针。 -
flags保留供将来使用。 -
vertexBindingDescriptionCount是pVertexBindingDescriptions中提供的顶点绑定描述的数量。 -
pVertexBindingDescriptions是指向 VkVertexInputBindingDescription 结构数组的指针。 -
vertexAttributeDescriptionCount是pVertexAttributeDescriptions中提供的顶点属性描述的数量。 -
pVertexAttributeDescriptions是指向 VkVertexInputAttributeDescription 结构数组的指针。
// Provided by VK_VERSION_1_0
typedef VkFlags VkPipelineVertexInputStateCreateFlags;
VkPipelineVertexInputStateCreateFlags 是一个用于设置掩码的位掩码类型,但目前保留供将来使用。
每个顶点输入绑定由 VkVertexInputBindingDescription 结构指定,定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkVertexInputBindingDescription {
uint32_t binding;
uint32_t stride;
VkVertexInputRate inputRate;
} VkVertexInputBindingDescription;
-
binding是此结构描述的绑定编号。 -
stride是缓冲区中连续元素之间的字节步幅。 -
inputRate是一个 VkVertexInputRate 值,指定顶点属性寻址是顶点索引的函数还是实例索引的函数。
VkVertexInputBindingDescription::inputRate 的可能值,指定从缓冲区中提取顶点属性的速率,如下所示:
// Provided by VK_VERSION_1_0
typedef enum VkVertexInputRate {
VK_VERTEX_INPUT_RATE_VERTEX = 0,
VK_VERTEX_INPUT_RATE_INSTANCE = 1,
} VkVertexInputRate;
-
VK_VERTEX_INPUT_RATE_VERTEX指定顶点属性寻址是顶点索引的函数。 -
VK_VERTEX_INPUT_RATE_INSTANCE指定顶点属性寻址是实例索引的函数。
每个顶点输入属性由 VkVertexInputAttributeDescription 结构指定,定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkVertexInputAttributeDescription {
uint32_t location;
uint32_t binding;
VkFormat format;
uint32_t offset;
} VkVertexInputAttributeDescription;
-
location是此属性的着色器输入位置编号。 -
binding是此属性从中获取数据的绑定编号。 -
format是顶点属性数据的大小和类型。 -
offset是此属性相对于顶点输入绑定中元素起点的字节偏移量。
要动态设置顶点输入属性和顶点输入绑定描述,请调用:
// Provided by VK_EXT_shader_object, VK_EXT_vertex_input_dynamic_state
void vkCmdSetVertexInputEXT(
VkCommandBuffer commandBuffer,
uint32_t vertexBindingDescriptionCount,
const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions,
uint32_t vertexAttributeDescriptionCount,
const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions);
-
commandBuffer是将记录命令的命令缓冲区。 -
vertexBindingDescriptionCount是pVertexBindingDescriptions中提供的顶点绑定描述的数量。 -
pVertexBindingDescriptions是指向 VkVertexInputBindingDescription2EXT 结构数组的指针。 -
vertexAttributeDescriptionCount是pVertexAttributeDescriptions中提供的顶点属性描述的数量。 -
pVertexAttributeDescriptions是指向 VkVertexInputAttributeDescription2EXT 结构数组的指针。
当使用 着色器对象 绘图时,或者当使用在 VkPipelineDynamicStateCreateInfo::pDynamicStates 中设置的 VK_DYNAMIC_STATE_VERTEX_INPUT_EXT 创建图形管线时,此命令为后续绘图命令设置顶点输入属性和顶点输入绑定描述状态。否则,此状态由用于创建当前活动的管线的 VkGraphicsPipelineCreateInfo::pVertexInputState 值指定。
如果使用 着色器对象 绘图,或者如果绑定的管线状态对象也是在启用了 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE 动态状态的情况下创建的,则可以使用 vkCmdBindVertexBuffers2 来代替 vkCmdSetVertexInputEXT 以动态设置步幅。
pVertexAttributeDescriptions 数组中未指定的范围 [0,VkPhysicalDeviceLimits::maxVertexInputAttributes) 内任何位置的顶点属性描述都变为未定义。
VkVertexInputBindingDescription2EXT 结构定义如下:
// Provided by VK_EXT_shader_object, VK_EXT_vertex_input_dynamic_state
typedef struct VkVertexInputBindingDescription2EXT {
VkStructureType sType;
void* pNext;
uint32_t binding;
uint32_t stride;
VkVertexInputRate inputRate;
uint32_t divisor;
} VkVertexInputBindingDescription2EXT;
-
sType是一个 VkStructureType 值,用于标识此结构。 -
pNext为NULL或指向扩展此结构的结构的指针。 -
binding是此结构描述的绑定编号。 -
stride是缓冲区中连续元素之间的字节步幅。 -
inputRate是一个 VkVertexInputRate 值,指定顶点属性寻址是顶点索引的函数还是实例索引的函数。 -
当启用实例化渲染时,
divisor是使用相同顶点属性值的连续实例的数量。如果启用了vertexAttributeInstanceRateDivisor特性,则此成员 可以 是1以外的值。例如,如果除数为 N,则在移动到下一个顶点属性之前,相同的顶点属性将应用于 N 个连续实例。divisor的最大值取决于实现,可以使用VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT::maxVertexAttribDivisor查询。如果启用了vertexAttributeInstanceRateZeroDivisor特性,则divisor的值 可以 为0。在这种情况下,相同的顶点属性将应用于所有实例。
VkVertexInputAttributeDescription2EXT 结构定义如下:
// Provided by VK_EXT_shader_object, VK_EXT_vertex_input_dynamic_state
typedef struct VkVertexInputAttributeDescription2EXT {
VkStructureType sType;
void* pNext;
uint32_t location;
uint32_t binding;
VkFormat format;
uint32_t offset;
} VkVertexInputAttributeDescription2EXT;
-
sType是一个 VkStructureType 值,用于标识此结构。 -
pNext为NULL或指向扩展此结构的结构的指针。 -
location是此属性的着色器输入位置编号。 -
binding是此属性从中获取数据的绑定编号。 -
format是顶点属性数据的大小和类型。 -
offset是此属性相对于顶点输入绑定中元素起点的字节偏移量。
要将顶点缓冲区绑定到命令缓冲区以用于后续的绘制命令,请调用:
// Provided by VK_VERSION_1_0
void vkCmdBindVertexBuffers(
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets);
-
commandBuffer是将命令记录到其中的命令缓冲区。 -
firstBinding是第一个顶点输入绑定的索引,该绑定的状态由该命令更新。 -
bindingCount是由该命令更新状态的顶点输入绑定的数量。 -
pBuffers是指向缓冲区句柄数组的指针。 -
pOffsets是指向缓冲区偏移数组的指针。
从 pBuffers 和 pOffsets 数组的第 i 个元素中取出的值将替换顶点输入绑定 firstBinding + i 的当前状态,其中 i 的取值范围是 [0, bindingCount)。顶点输入绑定的起始位置更新为 pBuffers[i] 缓冲区起始位置的偏移量 pOffsets[i] 处。所有使用这些绑定的顶点输入属性都将在后续的绘制命令中使用这些更新后的地址进行地址计算。如果启用了nullDescriptor特性,则 pBuffers 的元素可以是 VK_NULL_HANDLE,并且可以被顶点着色器使用。如果顶点输入属性绑定到一个为 VK_NULL_HANDLE 的顶点输入绑定,则从内存中取出的值被认为是零,并且缺失的 G、B 或 A 分量会用 (0填充。
或者,为了将顶点缓冲区及其大小和步幅绑定到命令缓冲区以供后续绘制命令使用,请调用
// Provided by VK_VERSION_1_3
void vkCmdBindVertexBuffers2(
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes,
const VkDeviceSize* pStrides);
或等效的命令
// Provided by VK_EXT_extended_dynamic_state, VK_EXT_shader_object
void vkCmdBindVertexBuffers2EXT(
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets,
const VkDeviceSize* pSizes,
const VkDeviceSize* pStrides);
-
commandBuffer是将命令记录到其中的命令缓冲区。 -
firstBinding是第一个顶点输入绑定的索引,该绑定的状态由该命令更新。 -
bindingCount是由该命令更新状态的顶点输入绑定的数量。 -
pBuffers是指向缓冲区句柄数组的指针。 -
pOffsets是指向缓冲区偏移数组的指针。 -
pSizes为NULL或指向从pBuffers绑定顶点数据的字节大小的数组的指针。 -
pStrides为NULL或指向缓冲区步幅数组的指针。
从 pBuffers 和 pOffsets 数组的第 i 个元素中取出的值将替换顶点输入绑定 firstBinding + i 的当前状态,其中 i 的取值范围是 [0, bindingCount)。顶点输入绑定的起始位置更新为 pBuffers[i] 缓冲区起始位置的偏移量 pOffsets[i] 处。如果 pSizes 不为 NULL,则 pSizes[i] 指定从 pBuffers[i] 加上 pOffsets[i] 对应的元素开始的顶点缓冲区的绑定大小。如果 pSizes[i] 是 VK_WHOLE_SIZE,则绑定大小是从 pBuffers[i] 加上 pOffsets[i] 到缓冲区 pBuffers[i] 的末尾。所有使用这些绑定的顶点输入属性都将在后续的绘制命令中使用这些更新后的地址进行地址计算。如果启用了nullDescriptor特性,则 pBuffers 的元素可以是 VK_NULL_HANDLE,并且可以被顶点着色器使用。如果顶点输入属性绑定到一个为 VK_NULL_HANDLE 的顶点输入绑定,则从内存中取出的值被认为是零,并且缺失的 G、B 或 A 分量会用 (0填充。
此命令还动态设置缓冲区 pBuffers[i] 中连续元素之间的字节步幅为相应的 pStrides[i] 值,当使用着色器对象进行绘制时,或者当图形管线在 VkPipelineDynamicStateCreateInfo::pDynamicStates 中设置了 VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE 时。否则,步幅由用于创建当前活动管线的 VkVertexInputBindingDescription::stride 值指定。
如果使用着色器对象进行绘制,或者如果绑定的管线状态对象也是通过启用 VK_DYNAMIC_STATE_VERTEX_INPUT_EXT 动态状态创建的,则可以使用 vkCmdSetVertexInputEXT 代替 vkCmdBindVertexBuffers2 来设置步幅。
|
与设置相同的静态状态不同, |
实例化渲染中的顶点属性除数
如果启用了 vertexAttributeInstanceRateDivisor 功能,并且 VkPipelineVertexInputStateCreateInfo 的 pNext 链包含一个 VkPipelineVertexInputDivisorStateCreateInfo 结构,则该结构控制在启用实例化渲染时如何将顶点属性分配给实例。
VkPipelineVertexInputDivisorStateCreateInfo 结构定义如下
// Provided by VK_VERSION_1_4
typedef struct VkPipelineVertexInputDivisorStateCreateInfo {
VkStructureType sType;
const void* pNext;
uint32_t vertexBindingDivisorCount;
const VkVertexInputBindingDivisorDescription* pVertexBindingDivisors;
} VkPipelineVertexInputDivisorStateCreateInfo;
或等效的
// Provided by VK_KHR_vertex_attribute_divisor
typedef VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoKHR;
或等效的
// Provided by VK_EXT_vertex_attribute_divisor
typedef VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoEXT;
-
sType是一个 VkStructureType 值,用于标识此结构。 -
pNext为NULL或指向扩展此结构的结构的指针。 -
vertexBindingDivisorCount是pVertexBindingDivisors数组中的元素数量。 -
pVertexBindingDivisors是指向 VkVertexInputBindingDivisorDescription 结构数组的指针,该数组指定每个绑定的除数值。
每个绑定的单独除数值使用 VkVertexInputBindingDivisorDescription 结构指定,该结构定义如下
// Provided by VK_VERSION_1_4
typedef struct VkVertexInputBindingDivisorDescription {
uint32_t binding;
uint32_t divisor;
} VkVertexInputBindingDivisorDescription;
或等效的
// Provided by VK_KHR_vertex_attribute_divisor
typedef VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionKHR;
或等效的
// Provided by VK_EXT_vertex_attribute_divisor
typedef VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionEXT;
-
binding是指定除数的绑定编号。 -
divisor是在启用实例化渲染时,将使用相同的顶点属性值的连续实例数。例如,如果除数是 N,则在移动到下一个顶点属性之前,相同的顶点属性将应用于 N 个连续的实例。divisor的最大值取决于实现,可以使用 VkPhysicalDeviceVertexAttributeDivisorProperties::maxVertexAttribDivisor查询。如果启用了vertexAttributeInstanceRateZeroDivisor功能,则divisor的值**可以**为0。在这种情况下,相同的顶点属性将应用于所有实例。
如果未使用此结构为属性定义除数值,则除数具有 1 的逻辑默认值。
顶点输入地址计算
每个 vertexIndex 和 instanceIndex 的每个属性的地址计算如下
-
令
attribDesc为 VkPipelineVertexInputStateCreateInfo::pVertexAttributeDescriptions的成员,其中 VkVertexInputAttributeDescription::location等于顶点输入属性编号。 -
令
bindingDesc为 VkPipelineVertexInputStateCreateInfo::pVertexBindingDescriptions的成员,其中 VkVertexInputAttributeDescription::binding等于attribDesc.binding。 -
令
vertexIndex为绘制中顶点的索引(对于vkCmdDraw,是firstVertex和firstVertex+vertexCount之间的值;对于vkCmdDrawIndexed,是从索引缓冲区获取的值加上vertexOffset),令instanceIndex为绘制的实例编号(是firstInstance和firstInstance+instanceCount之间的值)。 -
令
offset为使用pOffsets在vkCmdBindVertexBuffers或vkCmdBindVertexBuffers2期间指定的绑定顶点缓冲区中的偏移量数组。 -
令
divisor为 VkPipelineVertexInputDivisorStateCreateInfo::pVertexBindingDivisors的成员,其中 VkVertexInputBindingDivisorDescription::binding等于attribDesc.binding。如果顶点绑定状态是动态设置的,则令divisor为 vkCmdSetVertexInputEXT 调用中pVertexBindingDescriptions参数的成员,其中 VkVertexInputBindingDescription2EXT::binding等于attribDesc.binding。 -
令
stride为 VkPipelineVertexInputStateCreateInfo::pVertexBindingDescriptions->stride的成员,除非存在动态状态导致该值被忽略。在这种情况下,该值将从以下最后一个值设置:-
vkCmdSetVertexInputEXT::
pVertexBindingDescriptions->stride -
vkCmdBindVertexBuffers2::
pStride,如果不是NULL
-
bufferBindingAddress = buffer[binding].baseAddress + offset[binding];
if (bindingDesc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
effectiveVertexOffset = vertexIndex * stride;
else
if (divisor == 0)
effectiveVertexOffset = firstInstance * stride;
else
effectiveVertexOffset = (firstInstance + ((instanceIndex - firstInstance) / divisor)) * stride;
attribAddress = bufferBindingAddress + effectiveVertexOffset + attribDesc.offset;
顶点输入提取
对于每个属性,原始数据从 attribAddress 开始提取,并根据 数值类型,从 VkVertexInputAttributeDescription 的 format 转换为浮点数、无符号整数或有符号整数。format 的数值类型 **必须** 与着色器中输入变量的数值类型匹配。当且仅当 format 是 64 位数据类型时,着色器中的输入变量 **必须** 声明为 64 位数据类型。如果 format 是 64 位格式,或者 legacyVertexAttributes 功能未启用,并且 format 是打包格式,则 attribAddress **必须** 是 打包格式 中描述的格式大小(以字节为单位)的倍数。否则,如果 format 是 64 位格式,或者 legacyVertexAttributes 功能未启用,则 attribAddress **必须** 是 format 指示的组件类型大小(以字节为单位)的倍数(参见 格式)。对于不是 64 位数据类型的属性,每个分量都根据其类型和大小(如 格式定义 部分中为每个 VkFormat 定义的那样)转换为输入变量的格式,使用 16 位浮点数、无符号 11 位浮点数、无符号 10 位浮点数、定点数据转换 和 共享指数到 RGB 中的适当公式。小于 32 位的有符号整数分量进行符号扩展。不是 64 位数据类型的属性以与 转换为 RGBA 中描述的相同方式扩展为四个分量。顶点着色器输入变量中的分量数量不必与格式中的分量数量完全匹配。如果顶点着色器具有较少的分量,则丢弃额外的分量。