8.2 顶点数据
如果你所使用的图形管线需要顶点数据,在执行任何绘制操作前,你需要绑定用来获取数据的哦缓冲区。当缓冲区被用来作为顶点数据的来源时,它们有时也被称为顶点缓冲区。把缓冲区当作顶点数据来用的命令是vkCmdBindVertexBuffers(),它的原型是:
voidvkCmdBindVertexBuffers (
VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets);
和缓冲区所绑定命令缓冲区通过commandBuffer指定。一个给定的管线可能会引用很多个顶点缓冲区,vkCmdBindVertexBuffers()能够更新特定的命令缓冲区的一部分。需要更新的第一个绑定的索引通过firstBinding指定,需要更新的连续的绑定个数通过bindingCount指定。要更新非连续的顶点缓冲区范围,你需要多次调用vkCmdBindVertexBuffers()。
pBuffers参数是一个指向bindingCount个VKBufferhandle的数组的指针,pOffsets是一个指向缓冲区对象内bindingCount个偏移量的数组,偏移量亦即每个绑定数据开始的位置。pOffsets的值以字节为单位。一个很合理的做法是把相同的缓冲区对象以不同的位置(如果有需要甚至是相同的开始位置)绑定到一个命令缓冲区,在pBuffers数组中多次包含同一个VkBuffer类型的handle即可。
缓冲区内的数据的布局和格式被将要使用顶点数据的管线所定义。因此,数据的格式在这里没有被指定,但是在用来创建管线的VkPipelineVertexInputStateCreateInfo的VkPipelineVertexInputStateCreateInfo数据中定义。回到第七章“”,我们在Listing7.3里展示了一个用C++数据结构构造间隔顶点数据的例子。Listing8.1 展示了一个稍微高级的例子,使用一个缓冲区来存储位置数据,另一缓冲区来存储顶点法相和纹理坐标。
Listing8.1 分离顶点属性的构造
typedefstruct vertex_t
{
vmath::vec3 normal;
vmath::vec2 texcoord;
} vertex;
static const
VkVertexInputBindingDescription vertexInputBindings[] =
{
{ 0, sizeof(vmath::vec4), VK_VERTEX_INPUT_RATE_VERTEX }, // Buffer 1
{ 1, sizeof(vertex), VK_VERTEX_INPUT_RATE_VERTEX } // Buffer 2
};
static const
VkVertexInputAttributeDescription vertexAttributes[] =
{
{ 0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0 }, // Position
{ 1, 1, VK_FORMAT_R32G32B32_SFLOAT, 0 }, // Normal
{ 2, 1, VK_FORMAT_R32G32_SFLOAT, sizeof(vmath::vec3) } // Tex Coord
};
static const
VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
nullptr, //pNext
0, //flags
vkcore::utils::arraysize(vertexInputBindings), //vertexBindingDescription-Count
vertexInputBindings, // pVertexBinding-Descriptions
vkcore::utils::arraysize(vertexAttributes), // vertexAttribute-DescriptionCount
vertexAttributes //pVertexAttribute- Descriptions
};
在Listing 8.1中,我们已经用两个缓冲区定义了三个顶点属性。在第一个缓冲区里,只有一个简单的vec4变量,用来表示位置。这个缓冲区的步长因此是vec4的大小,是16字节。在第二个缓冲区里,我们存储了间隔的每一个顶点的法相和纹理坐标。我们以vertex类型结构表示,让编译器自动计算步长。