Vertex buffer
在Vulkan中建立Vertex buffer
- 創建頂點緩衝區:首先,你需要創建一個頂點緩衝區來存儲頂點數據。這通常通過vkCreateBuffer函數來完成。你需要指定緩衝區的大小和用途(如頂點緩衝區)。
- 分配內存:創建頂點緩衝區後,你需要為其分配內存。這可以通過vkAllocateMemory函數來完成。你需要指定內存的大小和屬性(如可見性和可訪問性)。
- 綁定內存:分配內存後,你需要將內存綁定到頂點緩衝區。這可以通過vkBindBufferMemory函數來完成。
- 填充數據:綁定內存後,你可以將頂點數據填充到頂點緩衝區中。這通常通過映射內存(vkMapMemory)並將數據複製到映射內存中來完成。完成後,記得解除映射(vkUnmapMemory)。
- 設置頂點輸入描述符:在渲染管線中,你需要設置頂點輸入描述符來告訴Vulkan如何解釋頂點數據。這通常通過VkPipelineVertexInputStateCreateInfo結構來完成。
- 綁定頂點緩衝區:在渲染過程中,你需要將頂點緩衝區綁定到命令緩衝區。這可以通過vkCmdBindVertexBuffers函數來完成。
- 發送繪製命令:最後,你可以發送繪製命令來渲染頂點數據。這通常通過vkCmdDraw或vkCmdDrawIndexed函數來完成。
範例:定義Vertexbuffer binding結構
struct Vertex { glm::vec2 pos; glm::vec3 color; static VkVertexInputBindingDescription getBindingDescription() { VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = 0; bindingDescription.stride = sizeof(Vertex); bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return bindingDescription; } static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() { // 2 attr in vertex : pos and color std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT; attributeDescriptions[0].offset = offsetof(Vertex, pos); attributeDescriptions[1].binding = 0; attributeDescriptions[1].location = 1; attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; attributeDescriptions[1].offset = offsetof(Vertex, color); return attributeDescriptions; } }; |
// temp dummy data: const std::vector<Vertex> vertices = { {{0.0f, -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}} }; |
建立Vertex buffer
void ltn::Model::createVBO() { VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(vertices[0]) * vertices.size(); bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; // The buffer will only be used from the graphics queue, bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; if (vkCreateBuffer(coreInstance.get_device(), &bufferInfo, nullptr, &vertexBuffer) != VK_SUCCESS) { throw std::runtime_error("failed to create vertex buffer!"); } VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(coreInstance.get_device(), vertexBuffer, &memRequirements); VkMemoryAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(coreInstance.get_physical_device(), memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); if (vkAllocateMemory(coreInstance.get_device(), &allocInfo, nullptr, &vertexBufferMemory) != VK_SUCCESS) { throw std::runtime_error("failed to allocate vertex buffer memory!"); } vkBindBufferMemory(coreInstance.get_device(), vertexBuffer, vertexBufferMemory, 0); //copy data void* data; vkMapMemory(coreInstance.get_device(), vertexBufferMemory, 0, bufferInfo.size, 0, &data); memcpy(data, vertices.data(), (size_t)bufferInfo.size); vkUnmapMemory(coreInstance.get_device(), vertexBufferMemory); } |
在Pipeline中指定
VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; auto bindingDescription = Vertex::getBindingDescription(); auto attributeDescriptions = Vertex::getAttributeDescriptions(); vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size()); vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); |
在Draw command中bind
void ltn::Model::bind(VkCommandBuffer& cmdbuffer) { VkBuffer vertexBuffers[] = { vertexBuffer }; VkDeviceSize offsets[] = { 0 }; vkCmdBindVertexBuffers(cmdbuffer, 0, 1, vertexBuffers, offsets); } |
Vertex Shader需配合binding
#version 450 layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { gl_Position = vec4(inPosition, 0.0, 1.0); fragColor = inColor; } |

