一、 目录与文件部署

从官网获取 IMGUI 代码库,在项目 extern 目录下新建 imgui 目录,将相关文件复制进去,构建出如下目录结构:

.
├── build
├── extern
│   ├── glfw
│   ├── glm
│   └── imgui
│       ├── backends
│       │   ├── imgui_impl_glfw.cpp
│       │   ├── imgui_impl_glfw.h
│       │   ├── imgui_impl_vulkan.cpp
│       │   └── imgui_impl_vulkan.h
│       ├── imconfig.h
│       ├── imgui_demo.cpp
│       ├── imgui_draw.cpp
│       ├── imgui_internal.h
│       ├── imgui_tables.cpp
│       ├── imgui_widgets.cpp
│       ├── imgui.cpp
│       ├── imgui.h
│       ├── imstb_rectpack.h
│       ├── imstb_textedit.h
│       ├── imstb_truetype.h
│       └── LICENSE.txt
└── stb

二、CMakeLists 配置 - 接入 ImGUI 依赖

(一)路径与文件设置

CMakeLists.txt 中,添加 ImGUI 相关配置:

# 设置外部库目录及各库路径
...
set(IMGUI_ROOT ${EXTERNAL_LIB_DIR}/imgui) # 递归收集源文件
file(GLOB_RECURSE SOURCE_FILES src/*.cpp src/*.c)

(二)构建与链接 ImGUI 库

# 构建 imgui 静态库,指定实现文件
add_library(imgui STATIC${IMGUI_ROOT}/imgui.cpp${IMGUI_ROOT}/imgui_demo.cpp${IMGUI_ROOT}/imgui_draw.cpp${IMGUI_ROOT}/imgui_widgets.cpp${IMGUI_ROOT}/imgui_tables.cpp${IMGUI_ROOT}/backends/imgui_impl_glfw.cpp${IMGUI_ROOT}/backends/imgui_impl_vulkan.cpp
)# 配置 imgui 头文件包含目录
target_include_directories(imgui PUBLIC${IMGUI_ROOT}${GLFW_ROOT}/include$<TARGET_PROPERTY:Vulkan::Vulkan,INTERFACE_INCLUDE_DIRECTORIES>
)# 查找 Vulkan 库
find_package(Vulkan REQUIRED)# 链接库到项目
target_link_libraries(${PROJECT_NAME} PRIVATEVulkan::Vulkanimgui     ${GLFW_LIB}
)

三、主代码集成 - main.cpp 中 ImGUI 接入

(一)头文件引入

...
#include <imgui/imgui.h>
#include <imgui/backends/imgui_impl_glfw.h>
#include <imgui/backends/imgui_impl_vulkan.h>#include "renderer/VkRenderer.h"
#include "scene/Camera.h"
#include "ObjModelLoader.h"
#include "GltfModelLoader.h"
#include "HelloRect.h"

(二)初始化与回调

GLFWwindow* window;
const uint32_t WIDTH = 1920;
const uint32_t HEIGHT = 1000;
Camera camera(glm::vec3(5.0f, 5.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), 45.0f, 0.01f, 1000.0f);
VkContext vkcontext{};// 帧缓冲大小变化回调
static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {vkcontext.framebufferResized = true;
}// 窗口初始化
void initWindow() {glfwInit();glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);window = glfwCreateWindow(WIDTH, HEIGHT, "Hello Vulkan", nullptr, nullptr);glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
}

(三)ImGUI 主题设置

// ImGUI 主题配置(含中文字体加载)
void setImguiTheme() {float baseFontSize = 16.0f;ImGuiIO& io = ImGui::GetIO();ImFont* font = io.Fonts->AddFontFromFileTTF("assets/fonts/msyh.ttc",baseFontSize,nullptr,io.Fonts->GetGlyphRangesChineseFull());IM_ASSERT(font != nullptr);ImGui::StyleColorsDark();ImGui::GetStyle().WindowRounding = 4.0f; 
}   

(四)主函数流程

int main() {initWindow();vkcontext.window = window;vkcontext.camera = &camera;// 加载模型并设置MeshInstance* objModel = ObjModelLoader::loadModel("assets/models/viking_room.obj", "assets/models/viking_room.png");objModel->modelMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f));objModel->modelMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(3.0f, 3.0f, 3.0f));vkcontext.meshInstances.push_back(objModel);// Vulkan 初始化if (!vkInit(&vkcontext)) {throw std::runtime_error("Vulkan 初始化失败!");}// ImGUI 上下文等初始化IMGUI_CHECKVERSION();ImGui::CreateContext();ImGuiIO& io = ImGui::GetIO();io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;setImguiTheme();ImGui_ImplGlfw_InitForVulkan(window, true);ImGui_ImplVulkan_InitInfo init_info = {};// 填充 init_info 字段...ImGui_ImplVulkan_Init(&init_info);// 上传 ImGUI 字体(独立命令缓冲)VkCommandBufferAllocateInfo allocInfo{};// 配置 allocInfo...VkCommandBuffer font_cmd;if (vkAllocateCommandBuffers(vkcontext.device, &allocInfo, &font_cmd) != VK_SUCCESS) {throw std::runtime_error("无法为 ImGui 字体上传分配命令缓冲区!");}VkCommandBufferBeginInfo begin_info = {};begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;vkBeginCommandBuffer(font_cmd, &begin_info);ImGui_ImplVulkan_CreateFontsTexture();vkEndCommandBuffer(font_cmd);VkSubmitInfo submit_info = {};submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;submit_info.commandBufferCount = 1;submit_info.pCommandBuffers = &font_cmd;vkQueueSubmit(vkcontext.graphicsQueue, 1, &submit_info, VK_NULL_HANDLE);vkDeviceWaitIdle(vkcontext.device);ImGui_ImplVulkan_DestroyFontsTexture();// 主循环try {while (!glfwWindowShouldClose(window)) {glfwPollEvents();// 1. ImGui 新帧ImGui_ImplVulkan_NewFrame();ImGui_ImplGlfw_NewFrame();ImGui::NewFrame();// 2. 构建UIImGui::ShowDemoWindow();ImGui::Render();vkRender(&vkcontext, ImGui::GetDrawData());}// 资源清理vkDeviceWaitIdle(vkcontext.device);ImGui_ImplVulkan_Shutdown();ImGui_ImplGlfw_Shutdown();ImGui::DestroyContext();vkClean(&vkcontext);glfwDestroyWindow(window);glfwTerminate();for (MeshInstance* mesh: vkcontext.meshInstances) {delete mesh;}} catch (const std::exception& e) {std::cerr << e.what() << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}

四、渲染器代码更新 - VkRenderer 调整

(一)函数声明修改(VkRenderer.h)

void vkRender(VkContext* vkcontext, ImDrawData* imguiDrawData); 

(二)描述符池与命令缓冲更新(VkRenderer.cpp)

1. 描述符池创建调整
// 创建描述符池,增大容量
{std::array<VkDescriptorPoolSize, 2> poolSizes{};size_t meshCount = ctx->meshInstances.size();poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_CONCURRENT_FRAMES * meshCount)+ 1;poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;poolSizes[1].descriptorCount = static_cast<uint32_t>(MAX_CONCURRENT_FRAMES * meshCount) + 1;VkDescriptorPoolCreateInfo poolInfo{};poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());poolInfo.pPoolSizes = poolSizes.data();poolInfo.maxSets = static_cast<uint32_t>(MAX_CONCURRENT_FRAMES * meshCount)+1;poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;if (vkCreateDescriptorPool(ctx->device, &poolInfo, nullptr, &ctx->descriptorPool) != VK_SUCCESS) {throw std::runtime_error("创建描述符池失败!");}
}
2. 命令缓冲录制修改
void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, ImDrawData* imguiDrawData, VkContext* ctx) {// 原有模型绘制循环...for (size_t i = 0; i < ctx->meshInstances.size(); ++i) {// 模型绘制逻辑}// 绘制 ImGUI 内容ImGui_ImplVulkan_RenderDrawData(imguiDrawData, commandBuffer);vkCmdEndRenderPass(commandBuffer);if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {throw std::runtime_error("录制命令缓冲失败!");}
}

五、整合要点与总结

(一)核心流程

  1. Vulkan 基础准备:完成 VkInstanceVkDeviceSwapChain 等渲染器核心组件初始化,特别注意描述符池需预留足够空间给 ImGUI 与主渲染。
  2. ImGUI 初始化:通过 ImGui::CreateContext(); 创建上下文,配置 IO(如中文字体、交互支持),设置主题样式,再初始化 GLFW + Vulkan 后端。
  3. 字体上传:需用独立命令缓冲,上传后通过 vkDeviceWaitIdle 保证同步,避免渲染异常。
  4. 主循环集成:每帧调用 NewFrame、构建 UI(如 ShowDemoWindow )、Render,最后在 Vulkan 命令缓冲中调用 ImGui_ImplVulkan_RenderDrawData 绘制 UI。

(二)常见问题与解决

  • 描述符池报错:若出现 vkFreeDescriptorSets 报错,检查是否添加 VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT 标志;若报空间不足(如错误码 -1000069000 ),需增大 maxSetspoolSizes
  • 命令缓冲问题:字体上传必须用独立缓冲,否则易引发同步问题,导致渲染异常。
  • 样式定制:通过 ImGui::GetStyle() 调整圆角、配色,结合 ImGuiIO 加载自定义字体(如中文字体),灵活美化界面。

(三)关键总结

Vulkan 集成 ImGUI 需重点关注资源池管理(描述符池容量与标志)、命令缓冲同步(字体上传独立处理)、ImGUI 初始化流程。遇到验证层报错,优先排查描述符池配置;样式需求可通过 ImGUI 自身接口灵活实现,确保渲染流程与 UI 交互顺畅协同 。

在这里插入图片描述
当前代码分支:14_integrated_DearImGUI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/910610.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/910610.shtml
英文地址,请注明出处:http://en.pswp.cn/news/910610.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux设备框架:kset与kobject基本介绍

系列文章目录 Linux设备框架&#xff1a;kset与kobject基本介绍 [link] Linux设备框架&#xff1a;kset与kobject源码分析 [link] kset与kobject基本介绍 一、前言二、kobject、kset和设备的关系2.1 kset 结构体2.2 kobject 结构体 三、总结 一、前言 Linux 设备模型如同一座拥…

【AI论文】扩展大型语言模型(LLM)智能体在测试时的计算量

摘要&#xff1a;扩展测试时的计算量在提升大型语言模型&#xff08;LLMs&#xff09;的推理能力方面已展现出显著成效。在本研究中&#xff0c;我们首次系统地探索了将测试时扩展方法应用于语言智能体&#xff0c;并研究了该方法在多大程度上能提高其有效性。具体而言&#xf…

LeapMotion-PhysicalHandsManager 类详解

PhysicalHandsManager 类详解 这个类是 Ultraleap 物理手交互系统的核心管理器,负责处理手部物理交互的不同模式。下面我将详细解析这个类的结构和功能: 类概述 PhysicalHandsManager 继承自 LeapProvider,是物理手交互系统的中央控制器: public class PhysicalHandsMa…

vue-22(理解组合式 API:setup、ref、reactive)

Vue.js 中的组合式 API 代表了我们构建和组织组件方式的重大转变。它为传统的选项式 API 提供了一种更灵活、更强大的替代方案&#xff0c;尤其适用于复杂的应用程序。本章将深入探讨组合式 API 的核心概念&#xff1a;setup函数、ref和reactive&#xff0c;为你构建更可维护、…

【Golang玩转MCP】-实现一个加减乘除MCP服务

文章目录 概要1 首先创建一个MCP服务器2 添加MCP工具如何测试我们的MCP服务功能是否正常呢小结 概要 今天我们使用golang简单实现一个加减乘除MCP服务 1 首先创建一个MCP服务器 s : server.NewMCPServer("Hello World Server","1.0.0",server.WithToolCa…

计算机网络期末 网络基础概述

目录 网络的定义历史发展(了解) 网络的分类&#xff0c;功能和应用(熟悉) 网络的组成与结构(理解) 网络的 OSI 七层参考模型(熟悉) 网络的 TCP/IP 四次模型(理解) 网络有关性能指标(掌握) 网络的定义历史发展(了解) 计算机网络是什么 四个阶段 总结 网络 互连网 因特网的…

SwiftUI学习笔记day4: Lecture 4 | Stanford CS193p 2023

Lecture 4 | Stanford CS193p 2023 课程链接&#xff1a;https://www.youtube.com/watch?v4CkEVfdqjLw 代码仓库&#xff1a;iOS 课程大纲&#xff1a; 简要课程大纲&#xff1a;SwiftUI 高级主题 Swift 访问控制&#xff08;Access Control&#xff09; 5 个级别&#xff1…

Docker 高级管理——容器通信技术与数据持久化

目录 一、Docker 容器的网络模式 1. Bridge 模式 2. Host 模式 3. Container 模式 4. None 模式 5. Overlay 模式 6. Macvlan 模式 7. 自定义网络模式 二、端口映射 1. 端口映射 2. 随机映射端口 3. 指定映射端口 &#xff08;1&#xff09;固定端口 &#xff08;…

git操作案例 -设置远程分支,并提交到新远程新分支

文章目录 前言一、分析当前的问题二、修改远程仓库地址&#xff08;一&#xff09;修改远程仓库地址场景 现有保留远程分支场景替换现有远程分支 二、 找回已经提交的文件场景&#xff1a;提交后&#xff0c;代码在本地仓库但未推送 三、同步远程分支四、提交到新远程的新分支 …

mysql一张表,其中一个字段设置了唯一索引,又设置了普通索引,查询的时候很慢,没有走普通索引,是const

问题分析 在 MySQL 中&#xff0c;当一个字段同时存在唯一索引和普通索引时&#xff0c;查询优化器通常会优先选择最严格的索引&#xff08;即能最快缩小结果集的索引&#xff09;。在你的场景中&#xff0c;优化器选择了唯一索引并将查询视为const类型&#xff0c;这通常是高…

ARCGIS国土超级工具集1.6更新说明

ARCGIS国土超级工具集V1.6版本&#xff0c;功能已增加至60 个。本次更新在V1.5版本的基础上&#xff0c;除修复了使用时发现的若干小问题外&#xff0c;还更新及新增了若干工具。其中勘测定界工具栏更新了界址点西北角重排工具&#xff0c;新增了提示图斑起始点、指定图斑起始点…

零基础学习RabbitMQ(2)--Linux安装RabbitMQ

注意&#xff1a;这里使用的是ubuntu系统 1. 安装Erlang RabbitMQ需要Erlang语言的支持&#xff0c;在安装rabbitMQ之前需要安装Erlang #更新软件包 sudo apt-get update #安装erlang sudo apt-get install erlang 安装后输入 rel可查看Erlang版本&#xff1a; 输入halt().…

Centos进单用户模式

一、开机按E 二、修改里面的linux行 把ro 修改成rw init/sysroot/bin/sh 修改前&#xff1a; 修改后&#xff1a; 三、ctrl x退出&#xff0c;进入单用户模式

RabbitMQ 的工作流程

RabbitMQ 是一个消息中间件&#xff0c;实现了生产者消费者模型&#xff0c;可以用来接收、存储、转发消息。 专有名词介绍 要了解 RabbitMQ 的工作流程&#xff0c;我们需要先了解下面几个关键词&#xff1a; 1、Producer 生产者&#xff0c;即向 RabbitMQ 发送消息。 2…

HTTP——不同版本区别

目录 HTTP1.0和HTTP1.1的区别 HTTP1.1相比HTTP1.0性能上的改进&#xff1a; 但是HTTP1.1还是有性能瓶颈&#xff1a; HTTP/2做了什么优化&#xff1f; HTTP/3的优点 HTTP与HTTPS的区别 HTTPS的工作原理 1.ClientHello 2.ServerHello 3.客户端回应 4.服务器的最后回应…

关于M0+芯片的IAP应用导致延时不准确解释

前言&#xff1a;在给项目中使用的M0芯片做IAP功能时一切一切都是那么的自然水到渠成&#xff0c;但是笔者在实现完IAP功能后&#xff0c;却发现APP端挂载的单总线功能崩溃了&#xff0c;最开始没有怀疑是bootload导致的。因为笔者在使用同一篇代码的时候单总线挂载的设备不同&…

安卓登录学习笔记

1. 背景与目标 (Background and Goal) 背景: 我们要创建一个用户登录界面。用户输入用户名和密码&#xff0c;点击“登录”按钮。应用会显示一个加载中的“圈圈”&#xff08;ProgressBar&#xff09;&#xff0c;然后模拟一个耗时2秒的网络请求。根据请求结果&#xff0c;界面…

Git(三):分支管理

文章目录 Git(三)&#xff1a;分支管理理解分支创建分支切换分支合并分支删除分支合并冲突分支管理策略分支策略Bug分支删除临时分支 Git(三)&#xff1a;分支管理 理解分支 本章介绍Git的杀手级功能之一&#xff1a;分支 分支就 是科幻电影里面的平行宇宙&#xff0c;当你正…

电子电气架构 --- 电气架构基础(汽车电子)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

RestClient 功能介绍、完整使用示例演示, 和RestTemplate、WebClient 对比

RestClient功能介绍 RestClient是Spring Framework 6.1版本引入的同步HTTP客户端&#xff0c;旨在替代老旧的RestTemplate&#xff0c;提供更现代、流畅的API设计。其核心特点包括&#xff1a; 流畅API&#xff08;Fluent API&#xff09;&#xff1a; 支持链式调用&#xff0…