创建索引缓冲

在本章节我们通过绘制矩形来演示索引缓冲的使用。修改顶点数据定义矩形的4个顶点:

const std::vector<Vertex> vertices = {
        {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
        {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
        {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
        {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
};

代码中,我们将矩形左上角的顶点设置为红色,右上角的顶点设置为绿色,右下角的顶点设置蓝色,左下角的顶点设置为白色。我们添加一个新的数组indices来存储索引数据:

const std::vector<uint16_t> indices = {
            0, 1, 2, 2, 3, 0
};

我们可以使用uint16_t或uint32_t变量类型作为索引的类型,对于不重复的顶点数据小于65535的情况,使用uint16_t变量类型作为索引类型可以节约一半的内存空间。

和顶点数据一样,我们需要将索引数据加载到一个VkBuffer来让GPU可以访问它。我们定义了两个类成员变量来存储索引缓冲对象:

VkBuffer vertexBuffer;
VkDeviceMemory vertexBufferMemory;
VkBuffer indexBuffer;
VkDeviceMemory indexBufferMemory;

添加createIndexBuffer函数用于索引缓冲创建,它和内容和createVertexBuffer函数的内容几乎一样:

void initVulkan() {
        ...
    createVertexBuffer();
    createIndexBuffer();
        ...
}

void createIndexBuffer() {
    VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();

    VkBuffer stagingBuffer;
    VkDeviceMemory stagingBufferMemory;
    createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);

    void* data;
    vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
    memcpy(data, indices.data(), (size_t) bufferSize);
    vkUnmapMemory(device, stagingBufferMemory);

    createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);

    copyBuffer(stagingBuffer, indexBuffer, bufferSize);

    vkDestroyBuffer(device, stagingBuffer, nullptr);
    vkFreeMemory(device, stagingBufferMemory, nullptr);
}

和createVertexBuffer函数相比,只有两处明显的不同。bufferSize现在的值为顶点索引个数乘以索引变量类型所占字节大小。indexBuffer的用法标记为VK_BUFFER_USAGE_INDEX_BUFFER_BIT。除此之外的处理和顶点缓冲的创建是相同的。我们也需要创建一个暂存缓冲来存储indices数组中的索引数据,然后复制暂存缓冲中的索引数据到GPU能够快速访问的缓冲中。

应用程序退出前,我们需要清除创建的索引缓冲对象:

void cleanup() {
    cleanupSwapChain();

    vkDestroyBuffer(device, indexBuffer, nullptr);
    vkFreeMemory(device, indexBufferMemory, nullptr);

    vkDestroyBuffer(device, vertexBuffer, nullptr);
    vkFreeMemory(device, vertexBufferMemory, nullptr);

        ...
}