前往
大廳
主題

Vulkan學習筆記 : 建立Vertex buffer

%%鼠 拒收病婿 | 2024-12-22 06:00:15 | 巴幣 128 | 人氣 93

Vertex buffer

vertex buffer(頂點緩衝區)是一種用於存儲頂點數據的內存區域。頂點數據包括頂點的位置、顏色、法線、紋理坐標等信息,這些數據是構建3D模型的基本單位。

在Vulkan中建立Vertex buffer

  1. 創建頂點緩衝區:首先,你需要創建一個頂點緩衝區來存儲頂點數據。這通常通過vkCreateBuffer函數來完成。你需要指定緩衝區的大小和用途(如頂點緩衝區)。
  2. 分配內存:創建頂點緩衝區後,你需要為其分配內存。這可以通過vkAllocateMemory函數來完成。你需要指定內存的大小和屬性(如可見性和可訪問性)。
  3. 綁定內存:分配內存後,你需要將內存綁定到頂點緩衝區。這可以通過vkBindBufferMemory函數來完成。
  4. 填充數據:綁定內存後,你可以將頂點數據填充到頂點緩衝區中。這通常通過映射內存(vkMapMemory)並將數據複製到映射內存中來完成。完成後,記得解除映射(vkUnmapMemory)。
  5. 設置頂點輸入描述符:在渲染管線中,你需要設置頂點輸入描述符來告訴Vulkan如何解釋頂點數據。這通常通過VkPipelineVertexInputStateCreateInfo結構來完成。
  6. 綁定頂點緩衝區:在渲染過程中,你需要將頂點緩衝區綁定到命令緩衝區。這可以通過vkCmdBindVertexBuffers函數來完成。
  7. 發送繪製命令:最後,你可以發送繪製命令來渲染頂點數據。這通常通過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中指定

建立Pipeline的地方,就需先指定好binding的數量、格式等等。
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

在draw loop中bind vertex buffers
void ltn::Model::bind(VkCommandBuffer& cmdbuffer)
{
    VkBuffer vertexBuffers[] = { vertexBuffer };
    VkDeviceSize offsets[] = { 0 };
    vkCmdBindVertexBuffers(cmdbuffer, 0, 1, vertexBuffers, offsets);

}

Vertex Shader需配合binding

例如我們attribute有vec2 position 與vec3 color,分別定義在location 0,1,則vertex shader input定義如下
#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;
}


成果:

多個binding間的關係可以看這篇文章: https://blog.csdn.net/smcnjyddx0623/article/details/135269761



送禮物贊助創作者 !
0
留言

創作回應

相關創作

更多創作