Vulkan學習筆記8—頂點輸入描述與頂點緩沖

一、著色器代碼更新及構建時自動編譯著色器腳本

用內存中的頂點緩沖區替換頂點著色器中硬編碼的頂點數據

之前的頂點著色器:

#version 450layout(location = 0) out vec3 fragColor;// 頂點數據硬編碼
vec2 positions[3] = vec2[](vec2(0.0, -0.5),vec2(0.5, 0.5),vec2(-0.5, 0.5)
);// 顏色數據硬編碼
vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0),vec3(0.0, 1.0, 0.0),vec3(0.0, 0.0, 1.0)
);void main() {gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);fragColor = colors[gl_VertexIndex];
}

現在的頂點著色器:

#version 450layout(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;
}

每次改動著色器都手動輸入glslc 命令把著色器編譯為 spv 字節碼有些效率低下,可在 CMake 構建階段自動調用 glslc 命令編譯著色器,修改 CMakeLists.txt :

# ------------后面追加修改的配置部分-----------# 查找所有著色器源文件
file(GLOB SHADER_SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/assets/shaders/*.vert" "${CMAKE_CURRENT_SOURCE_DIR}/assets/shaders/*.frag")
set(SHADER_SPV_FILES "")
foreach(SHADER ${SHADER_SRC_FILES})message("compile shader file "${SHADER})get_filename_component(FILE_NAME ${SHADER} NAME)set(SPV "${CMAKE_CURRENT_SOURCE_DIR}/assets/shaders/${FILE_NAME}.spv")message("spv path: "${SPV})add_custom_command(OUTPUT ${SPV}COMMAND glslc ${SHADER} -o ${SPV}DEPENDS ${SHADER}COMMENT "Compiling shader ${FILE_NAME}")list(APPEND SHADER_SPV_FILES ${SPV})
endforeach()add_custom_target(CompileShaders ALL DEPENDS ${SHADER_SPV_FILES})add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy_directory${CMAKE_CURRENT_SOURCE_DIR}/assets$<TARGET_FILE_DIR:${PROJECT_NAME}>/assetsCOMMENT "Copying assets to build directory..."
)

二、頂點數據與綁定描述

創建一個VkTypes.h頭文件,添加頂點數據結構體 Vertex,頂點/顏色都作為屬性,這稱為交錯頂點屬性。

#pragma once
#include <vulkan/vulkan.h>#include <array>
#include <glm/glm.hpp>namespace renderer {  // 渲染器相關類和結構的命名空間// 頂點數據結構,包含位置和顏色信息struct Vertex {glm::vec2 pos;  // 二維坐標位置(x,y)glm::vec3 color;  // RGB顏色值// 獲取頂點輸入綁定描述// 描述頂點數據如何按字節偏移量組織在內存中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() {std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};// 位置屬性描述attributeDescriptions[0].binding = 0;  // 對應綁定點索引attributeDescriptions[0].location = 0;  // 在頂點著色器中對應的locationattributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;  // 32位浮點數x2 (x,y)attributeDescriptions[0].offset = offsetof(Vertex, pos);  // 位置屬性的內存偏移// 顏色屬性描述attributeDescriptions[1].binding = 0;  // 對應綁定點索引attributeDescriptions[1].location = 1;  // 在頂點著色器中對應的locationattributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;  // 32位浮點數x3 (R,G,B)attributeDescriptions[1].offset = offsetof(Vertex, color);  // 顏色屬性的內存偏移return attributeDescriptions;}};}  // namespace renderer
  1. Vertex 結構:包含頂點的位置 (pos) 和顏色 (color) 數據
  2. getBindingDescription
    • 告訴 Vulkan 頂點數據如何組織
    • stride 設置為整個 Vertex 大小,表示每個頂點數據是連續排列的
  3. getAttributeDescriptions
    • 定義每個屬性的存儲格式和內存偏移
    • pos 使用 2 個 32 位浮點數 (VK_FORMAT_R32G32_SFLOAT)
    • color 使用 3 個 32 位浮點數 (VK_FORMAT_R32G32B32_SFLOAT)
  4. offsetof 宏:計算結構體成員相對于起始地址的字節偏移量

三、頂點緩沖

可見緩沖區并使用 memcpy 將頂點數據直接復制到其中的最簡單方法開始,之后我們將了解如何使用暫存緩沖區將頂點數據復制到高性能內存中。

在?vkInit 中添加創建頂點緩沖代碼:

// 創建命令池
{...
}// 創建頂點緩沖
{// 1. 創建頂點緩沖區對象VkBufferCreateInfo bufferInfo{};bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; // 結構體類型bufferInfo.size = vkcontext->vertexBufferSize; // 緩沖區大小(字節)bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; // 用作頂點緩沖區bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // 獨占模式(單隊列族訪問)// 創建緩沖區if (vkCreateBuffer(vkcontext->device, &bufferInfo, nullptr, &vkcontext->vertexBuffer) != VK_SUCCESS) {throw std::runtime_error("頂點緩沖創建失敗!");} // 2. 查詢緩沖區內存需求VkMemoryRequirements memRequirements;vkGetBufferMemoryRequirements(vkcontext->device, vkcontext->vertexBuffer, &memRequirements);// 3. 分配內存VkMemoryAllocateInfo allocInfo{};allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; // 結構體類型allocInfo.allocationSize = memRequirements.size; // 分配大小與需求一致// 查找合適的內存類型:主機可見(可映射CPU內存)且具有一致性allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, // 可用內存類型位掩碼VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, // 內存屬性vkcontext->physicalDevice // 物理設備);// 分配內存if (vkAllocateMemory(vkcontext->device, &allocInfo, nullptr, &vkcontext->vertexBufferMemory) != VK_SUCCESS) {throw std::runtime_error("為頂點緩沖分配內存失敗!");}// 4. 將內存綁定到緩沖區vkBindBufferMemory(vkcontext->device, vkcontext->vertexBuffer, vkcontext->vertexBufferMemory, 0);// 5. 向頂點緩沖區寫入數據void* data;// 映射內存到CPU可訪問的地址空間vkMapMemory(vkcontext->device, vkcontext->vertexBufferMemory, 0, bufferInfo.size, 0, &data);// 使用memcpy復制頂點數據到映射的內存區域memcpy(data, vkcontext->vertexData, (size_t) bufferInfo.size);// 解除內存映射(數據已提交)vkUnmapMemory(vkcontext->device, vkcontext->vertexBufferMemory);// 注:由于使用了VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,// 無需額外的內存屏障來確保GPU可見性
}// 創建命令緩沖
{...
}

關鍵步驟解析:

  1. 創建緩沖區對象

    • 指定緩沖區大小和用途(頂點緩沖區)
    • 分享模式設為獨占,因為通常只由圖形隊列族訪問
  2. 查詢內存需求

    • Vulkan 要求先查詢緩沖區的內存需求(大小、對齊和可用內存類型)
  3. 分配內存

    • 創建 CPU 使用 findMemoryType 函數查找符合條件的內存類型
    • 選擇主機可見內存以便 CPU 可以寫入數據
    • 選擇一致性內存以避免手動刷新內存范圍
  4. 綁定內存到緩沖區

    • 將分配的內存塊與緩沖區對象關聯
  5. 數據傳輸

    • 映射內存到 CPU 地址空間
    • 使用memcpy復制頂點數據
    • 解除映射,完成數據傳輸

四、綁定頂點緩沖

修改HelloTriangle類,添加頂點顏色數據:

--------------HelloTriangle.h----------
#pragma once
#include <vector>#include "renderer/VkTypes.h"using namespace renderer;class HelloTriangle {
public:HelloTriangle();std::vector<Vertex> vertices;
};-------------HelloTriangle.cpp-------------
#include "HelloTriangle.h"HelloTriangle::HelloTriangle(): vertices({{{0.0f, -0.5f}, {1.0f, 1.0f, 1.0f}},{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
}) {}

在VkContext 中新增成員變量:

struct VkContext {...void* vertexData;uint32_t vertexNum{0};size_t vertexBufferSize{0};VkBuffer vertexBuffer;VkDeviceMemory vertexBufferMemory;};

在修改主函數邏輯:

int main() {initWindow();vkcontext.window = window;HelloTriangle helloTriangleApp;vkcontext.vertexData = helloTriangleApp.vertices.data();vkcontext.vertexNum = helloTriangleApp.vertices.size();vkcontext.vertexBufferSize = helloTriangleApp.vertices.size() * sizeof(Vertex);if (!vkInit(&vkcontext)) {throw std::runtime_error("Vulkan 初始化失敗!");}try {while (!glfwWindowShouldClose(window)) {glfwPollEvents();vkRender(&vkcontext);}vkDeviceWaitIdle(vkcontext.device);vkClean(&vkcontext);glfwDestroyWindow(window);glfwTerminate();} catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

修改命令錄制部分,綁定頂點緩沖:

VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = vkcontext->swapChainExtent;
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);// --------修改部分開始-----------------------------
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vkcontext->vertexBuffer, offsets);vkCmdDraw(commandBuffer, vkcontext->vertexNum, 1, 0, 0);
//---------修改部分結束--------------------------------------
vkCmdEndRenderPass(commandBuffer);

現在修改下頂點顏色值,構建運行看看效果:

一切正常,Validation Layer 也沒有輸出錯誤日志!

當前代碼分支為 06_vertexInputdescription_vertexbuffer

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84300.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84300.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84300.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Day04_數據結構(棧鏈棧循環隊列)

01.棧 main.c #include "stack.h" int main() { stack_p S(stack_p)create_stack(); //1.入棧 …

PyTorch 的 CUDA GPU 支持 · 安裝五條鐵律(最新版 2025 修訂)(適用于所有用戶)

相關參考資料&#xff08;往期博客&#xff09;&#xff1a; 是否需要預先安裝 CUDA Toolkit&#xff1f;——按使用場景分級推薦及進階說明-CSDN博客 太方便&#xff0c;WIN系統CUDA12.4下使用conda便捷管理虛擬環境中的不同版本的CUDA、cuDNN、PyTorch-CSDN博客 好消息&#…

Django構建簡易視頻編輯管理系統

Django構建簡易視頻編輯管理系統 以下是基于Django構建簡易視頻編輯管理系統的可運行代碼框架&#xff0c;包含核心功能模塊和實現邏輯。該系統支持視頻上傳、基本剪輯操作和管理功能。 環境準備 安裝必要依賴包&#xff1a; pip install django pillow moviepy django-cri…

Java求職者面試題詳解:計算機網絡、操作系統、設計模式與數據結構

Java求職者面試題詳解&#xff1a;計算機網絡、操作系統、設計模式與數據結構 第一輪&#xff1a;基礎概念問題 1. 請解釋TCP和UDP的區別。 2. 什么是操作系統&#xff1f;它的主要功能是什么&#xff1f; 3. 請解釋設計模式中的單例模式&#xff0c;并給出一個實際應用的例…

【mysql】docker運行mysql8.0

背景 mariadb10.5.8報錯&#xff1a;Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘LIMIT ?’ at line 1 所以更換為mysql8.0.39試試 docker run啟動…

C#實現語音預處理:降噪/靜音檢測/自動增益

無論是在音視頻錄制系統&#xff0c;還是音視頻通話系統、或視頻會議系統中&#xff0c;對從麥克風采集到的說話的聲音數據進行預處理&#xff0c;都是是非常必要的。 語音數據預處理主要包括&#xff1a;??降噪&#xff08;Noise Reduction&#xff09;、靜音檢測&#xff0…

組合模式Composite Pattern

模式定義 又稱整體-部分模式 組合多個對象形成 樹形結構 以表示“整體-部分”的結構層次 組合模式對單個對象&#xff08;即葉子對象&#xff09;和組合對象&#xff08;即容器對象&#xff09;的使用具有一致性對象結構型模式 模式結構 Component&#xff1a;抽象構件Leaf&a…

商代大模型:智能重構下的文明曙光與青銅密碼

引言&#xff1a;技術奇點的歷史想象 在人類文明的長河中&#xff0c;技術的進步始終是推動社會變革的核心動力。從青銅冶煉到文字發明&#xff0c;從農業革命到工業革命&#xff0c;每一次技術飛躍都重塑了人類對世界的認知與生存方式。而如今&#xff0c;人工智能的崛起正以…

【Python】python系列之函數作用域

Python 系列文章學習記錄&#xff1a; Python系列之Windows環境安裝配置_開著拖拉機回家的博客-CSDN博客 Python系列之變量和運算符_開著拖拉機回家的博客-CSDN博客 Python系列之判斷和循環_開著拖拉機回家的博客-CSDN博客 Python系列之字符串和列表_開著拖拉機回家的博客…

Unity UI 核心類解析之Graphic

&#x1f9f1; Unity UI 核心類解析&#xff1a;Graphic 類詳解 一、什么是 Graphic&#xff1f; 在 Unity 的 UI 系統中&#xff0c;Graphic 是一個抽象基類&#xff0c;繼承自 UIBehaviour 并實現了 ICanvasElement 接口。它是所有可以被繪制到屏幕上的 UI 元素的基礎類。 …

【Elasticsearch】文檔遷移(Reindex)

文檔遷移 1.為什么要進行 reindex 操作2.Reindex 操作的本質3.實際案例3.1 同集群索引之間的全量數據遷移3.2 同集群索引之間基于特定條件的數據遷移3.2.1 源索引設置檢索條件3.2.2 基于 script 腳本的索引遷移3.2.3 基于預處理管道的數據遷移 3.3 不同集群之間的索引遷移3.4 查…

WordPress 區塊版面配置指南

WordPress 的區塊編輯器(Gutenberg)提供了靈活的版面配置選項&#xff0c;以下是主要配置方法&#xff1a; 基本區塊布局 添加區塊&#xff1a;點擊””按鈕或按”/”鍵快速插入區塊 常用內容區塊&#xff1a; 段落(Paragraph) 標題(Heading) 圖像(Image) 畫廊(Gallery)…

TensorFlow基礎之理解張量

2.理解張量 張量&#xff08;Tensors&#xff09;介紹 張量是物理和工程領域的基礎數學結構。但是過去張量很少在計算機科學里使用。它與離散數學和邏輯學有更多的聯系。隨著機器學習的出現&#xff0c;這種狀態開始顯著的改變&#xff0c;成為連續向量的計算基礎。現代機器學…

Flume 安裝與配置步驟

1.解壓 tar -zxvf apache-flume-1.9.0-bin.tar.gz 2.配置環境變量 vim /etc/profile export FLUME_HOME/home/wang/soft/flume/apache-flume-1.9.0-bin export PATH$PATH:$FLUME_HOME/bin source /etc/profile 3.創建必要的目錄 mkdir -p $FLUME_HOME/conf 4.創建 Flume 配置文…

還原線上 WebView 異常:手機端APP遠程調試

前端調試總被理解為開發階段的事&#xff0c;但在實際項目中&#xff0c;真正困難的調試往往發生在產品上線之后。用戶反饋“看不到內容”、“一直轉圈”、“點了沒反應”&#xff0c;而開發環境無法復現&#xff0c;測試機也正常運行&#xff0c;這時怎么定位、驗證和解決問題…

102頁滿分PPT | 汽車設備制造業企業信息化業務解決方案智能制造汽車黑燈工廠解決方案

這份文檔是一份汽車設備制造業企業信息化業務解決方案&#xff0c;詳細闡述了企業從生產到銷售的全流程信息化建設。針對企業目前手工管理為主、信息化程度低、數據追溯困難等問題&#xff0c;提出了建立統一信息化平臺的目標&#xff0c;涵蓋財務、業務、流程和數據的整合。方…

SQLite 表達式詳解

SQLite 表達式詳解 引言 SQLite 是一個輕量級的數據庫,廣泛用于移動設備和桌面應用程序。SQLite 的表達式是 SQL 語句的核心,它們用于查詢、更新和刪除數據庫中的數據。本文將詳細解釋 SQLite 的各種表達式,并探討它們在數據庫操作中的重要性。 表達式概述 在 SQLite 中…

沉浸式AI交互數字人技術解析

360智匯云沉浸式AI交互數字人支持開發者靈活接入和私有化部署大模型服務&#xff0c;構建面向業務場景的實時音視頻交互能力。系統集成了360智匯云自研的沉浸式AI交互數字人引擎與高性能 RTC 模塊&#xff0c;保障音視頻傳輸過程中的低延遲、高穩定性和高并發承載能力&#xff…

HarmonyOS 評論回復彈窗最佳實踐

HarmonyOS 評論回復彈窗最佳實踐 前言 在移動應用開發中&#xff0c;評論回復功能是一個常見且重要的交互場景。本文將詳細介紹如何在 HarmonyOS 中實現一個功能完善的評論回復彈窗&#xff0c;包括彈窗選型、富文本編輯、軟鍵盤適配等關鍵技術點。 功能概述 我們要實現的評…

Git 回退操作詳解:帶示例的“小白”指南

前言 在日常開發中&#xff0c;我們難免會遇到&#xff1a; 改錯代碼&#xff1a;推送之前才發現某些行根本就不該動提交錯誤&#xff1a;commit 信息打錯、提交到錯誤分支想回到之前版本&#xff1a;測試時發現之前版本是好的&#xff0c;需要回去查看 這就需要用到 Git 的…