上一篇Imgui例子逐行解析

头文件区

#include <GLFW/glfw3.h>Code language: HTML, XML (xml)

引入 GLFW 窗口库头文件:负责创建窗口、处理鼠标 / 键盘输入、管理 OpenGL 上下文、窗口消息循环。

GLFW 是一个用来创建和管理窗口的库,是C语言开发的。它是独立的,不属于Imgui,但是IMGUI用到了它。所以需要引用它。读者在上一节中,已经把它下载到项目目录里面了。并且页配置集成到了项目中了。

#include "imgui.h"Code language: CSS (css)

这是imgui的核心头文件,里面有所有 UI 控件、上下文、样式、绘制基础 API等等。

#include "backends/imgui_impl_glfw.h"Code language: PHP (php)

这是imgui和glfw的对接桥梁,负责把glfw中窗口鼠标、键盘、窗口尺寸等等转发给 ImGui

#include "backends/imgui_impl_opengl3.h"Code language: PHP (php)

ImGui OpenGL3 渲染后端适配层:生成 OpenGL 着色器、顶点缓冲,将 ImGui UI 图形提交给 GPU 绘制。

#include <cstdio>Code language: HTML, XML (xml)

C++ 标准 C 输入输出库,用于printf打印错误日志。


int main()

入口函数,相信不用小编多说了。

GLFW 初始化

    // Initialize GLFW
    if (!glfwInit())
    {
        printf("GLFW initialization failed\n");
        return -1;
    }Code language: JavaScript (javascript)

glfwInit():初始化 GLFW 全局资源(例如显卡、窗口驱动、输入设备)

如果不通过,则弹出错误提示,并且返回-1 程序就异常退出,操作系统会捕捉到这个-1

OpenGL 版本配置

    // OpenGL 3.3
    const char* glsl_version = "#version 330";Code language: JavaScript (javascript)

定义 GLSL 着色器版本字符串,OpenGL3.3 对应 GLSL 330

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);

设置 OpenGL 主版本号为 3

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

设置 OpenGL 次版本号为 3

 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

使用核心模式 Core Profile

创建窗口

    // Create window
    GLFWwindow* window = glfwCreateWindow(1000, 600, "ImGui Minimal Demo (VS2022)", nullptr, nullptr);Code language: JavaScript (javascript)

窗口宽高是1000*600,窗口标题是“ImGui Minimal Demo (VS2022)”,第 4 参数,是nullptr空指针,表示窗口模式,第 5 参数,是否共享 OpenGL 上下文的窗口,nullptr = 不共享。

返回窗口句柄指针GLFWwindow*

 if (!window)
    {
        glfwTerminate();
        return -1;
    }Code language: JavaScript (javascript)

上面的GLFWwindow window 如果窗口创建失败句柄为 nullptr

glfwTerminate() 销毁所有 GLFW 资源

然后返回-1,告诉操作系统,程序错误退出。

glfwMakeContextCurrent(window);Code language: JavaScript (javascript)

将当前窗口绑定为 OpenGL 渲染上下文,后续所有 OpenGL 绘制指令都作用于该窗口

glfwSwapInterval(1);

开启垂直同步,参数 1 = 每帧等待显示器刷新,限制帧率和显示器刷新率同步,防止画面撕裂;0 = 关闭 VSync,无帧率限制。

以上这个配置很重要,如果没有开启,那么显示器刷新的时候和glfw刷新不同步,会导致画面出现错乱。

ImGui 全局初始化

IMGUI_CHECKVERSION(); // 校验头文件与后端版本一致性,版本不符直接断言报错
ImGui::CreateContext(); // 创建ImGui全局上下文,存储UI所有运行状态
ImGuiIO& io = ImGui::GetIO(); // 获取IO配置对象,管控输入、字体、全局开关等设置
ImGui::StyleColorsDark(); // 加载官方深色UI配色样式Code language: PHP (php)

绑定 GLFW+OpenGL 后端

ImGui_ImplGlfw_InitForOpenGL(window, true);Code language: JavaScript (javascript)

第二个参数设置true是,让 ImGui 接管所有输入事件(鼠标、键盘),自动屏蔽输入穿透到游戏底层

 ImGui_ImplOpenGL3_Init(glsl_version);

初始化 OpenGL3 渲染后端,传入 GLSL 版本字符串,编译 UI 绘制用的顶点 / 片段着色器、创建 GPU 缓冲

float slider_value = 0.5f;    // 滑动条绑定数值
int click_count = 0;          // 按钮点击计数
bool show_full_demo = false;  // 控制是否显示ImGui官方演示窗口Code language: JavaScript (javascript)

以上几个参数用来存储控件的值。每次刷新UI,都会读取或者修改,跨帧保留数值

主渲染循环

程序核心,每秒循环几十到上百次

while (!glfwWindowShouldClose(window))Code language: JavaScript (javascript)

窗口未收到关闭信号,例如 点击右上角 x关闭按钮或者Alt+F4,就持续渲染。

glfwPollEvents();

轮询窗口系统所有消息,例如鼠标点击 移动 键盘按键按下,窗口缩放 关闭等等。

 ImGui_ImplOpenGL3_NewFrame();

OpenGL 后端帧前置更新:重置渲染资源、准备下一帧绘制缓存

ImGui_ImplGlfw_NewFrame();

GLFW 后端帧前置更新:读取当前鼠标坐标、按键状态、窗口尺寸,写入 ImGui IO 输入数据

ImGui::NewFrame();Code language: CSS (css)

开启新一帧 UI 布局计算,必须在所有ImGui::xxx()控件代码前调用;内部清空上一帧绘制指令,准备收集本帧 UI 数据

ui控件数据变更构建部分

// Draw custom UI panel
ImGui::Begin("Control Panel");                // 开启自定义控制面板窗口
ImGui::Text("Hello ImGui + VS2022");          // 输出静态文本
ImGui::SliderFloat("Slider Value", &slider_value, 0.f, 1.f); // 浮点滑动条,绑定数值变量

if (ImGui::Button("Click to Count"))          // 创建点击按钮,按下返回true
    click_count++;                            // 按钮点击后计数器+1
ImGui::SameLine();                            // 下一个控件与当前同行显示
ImGui::Text("Click Count: %d", click_count);  // 打印按钮点击次数

ImGui::Checkbox("Show Full ImGui Demo Window", &show_full_demo); // 复选框控制演示窗口显隐
ImGui::End();                                 // 结束当前自定义窗口绘制

if (show_full_demo)
    ImGui::ShowDemoWindow(&show_full_demo);    // 打开ImGui官方全套演示窗口Code language: C++ (cpp)

以上部分,是用来每次循环,就显示内容,检查是否点击了按钮,如果是就计数器增加。打印计数器等等。

真正绘制渲染部分

// Render ImGui draw data
ImGui::Render();                                        // 生成本帧UI顶点绘制数据
int width, height;
glfwGetFramebufferSize(window, &width, &height);        // 获取窗口实际渲染分辨率
glViewport(0, 0, width, height);                       // 设置OpenGL渲染视口铺满窗口
glClearColor(0.12f, 0.12f, 0.12f, 1.f);                // 设置窗口清屏底色(深灰色)
glClear(GL_COLOR_BUFFER_BIT);                           // 清空画布颜色缓冲
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());// 用OpenGL绘制所有ImGui界面

glfwSwapBuffers(window);                                // 交换前后缓冲区,显示画面Code language: JavaScript (javascript)

退出后清除资源部分

如下是用户退出后,进行资源清理部分

// Cleanup resources
ImGui_ImplOpenGL3_Shutdown();  // 释放OpenGL渲染后端资源(着色器、缓冲等)
ImGui_ImplGlfw_Shutdown();     // 释放GLFW窗口适配后端资源
ImGui::DestroyContext();       // 销毁ImGui全局上下文,释放UI内存
glfwDestroyWindow(window);     // 关闭GLFW窗口,销毁窗口句柄
glfwTerminate();               // 彻底卸载GLFW库,释放全局窗口/输入资源
return 0;                      // 程序正常退出,返回成功码0Code language: JavaScript (javascript)

销毁顺序和初始化顺序完全相反,防止内存泄漏、资源残留。

ok,本部分解析上一节课的的例子,读者有什么不明白,可以下方留言。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注