24.3 ImGui介绍与使用
「游戏引擎 浅入浅出」是一本开源电子书,PDF/随书代码/资源下载: https://github.com/ThisisGame/cpp-game-engine-book
ImGui是目前最流行的ui库,它长这样。
你能在各种开源引擎、工具、软件看见它,它的风格比较特别,让你一眼就知道,这个软件的界面是ImGui做的。
我们前面也介绍了gui相关的实现,那为什么不使用引擎的gui,而是使用三方的ImGui呢?
1. 选择合适的ui库
虽然前面实现了button、image、uimask这几个控件,但是它们只是ui库的最基础,相比较完整的ui库,还有十万八千里的距离。
最难的不是显示一个图片、按钮,而是如何去组织它们,使多个控件组合成窗口、列表等复杂控件。
这最后的Layout布局运算,才是最复杂、最耗费心神的。
在github上你能看到的开源游戏引擎,它们的游戏gui实现,一般都很简单,能简单显示图片文字就行。
cocos2dx的gui都比它们复杂几倍,更别说商业游戏引擎的gui系统,复杂百倍。
各大游戏公司的自研引擎,也都是集成开源的gui库,例如cegui、cocos2dx等。
而编辑器的ui,大家都会选择ImGui,因为它真的特别简单。
2. 初试ImGui
Github下载代码:https://github.com/ocornut/imgui
ImGui核心就10个代码文件,直接复制粘贴到项目中就可以使用。
把代码下载过来,打开examples,可以看到有多个示例文件夹,每个示例都是不同的后端。
1. 前端后端ImGui采用前后端分离的架构。
ImGui自身就是前端,我们知道要渲染一个图片,需要计算4个顶点,然后准备纹理、Shader,然后送到OpenGL去渲染。
ImGui就只负责计算顶点数据、准备纹理、Shader,然后具体的渲染就交给后端。
例如example_sdl_opengl3就表示后端使用sdl_opengl3来渲染,而example_glfw_opengl3就表示后端使用glfw_opengl3来渲染。
sdl_opengl3和glfw_opengl3的区别又是什么?
OpenGL只是一个图形库,它在不同的操作系统上依赖于操作系统的GUI系统,我们在教程中使用glfw来创建Window并处理IO事件,而sdl是另外一套处理Window与IO事件的框架。
如果你使用的不是sdl、glfw 这个目录中的任何一个,例如你用的是Cocos2d-x、UnrealEngine等引擎,你也可以写一个自己的example_cocos2dx_opengl3、example_unrealengine_dx12之类的,只要将ImGui提供出来的顶点数据、纹理、shader用引擎接口进行处理送去渲染即可。
2. 实例源码结构打开examples/imgui_examples.sln,启动example_glfw_opengl3,F5运行。
sources目录下就是后端代码。
imgui_impl_glfw.cpp 负责使用glfw创建Window和处理IO。
imgui_impl_opengl3.cpp负责处理渲染相关事情,可以看到只需要实现几个接口,就可以将ImGui接入到自己的引擎项目中。
3. 实例源码解析代码并不多,分为以下几个步骤:
初始化glfw 创建window初始化ImGui初始化ImGui后端主循环,在每一帧里创建GUI并渲染//file:main.cppint main(int, char**){ // 1. 初始化glfw 创建window glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return 1; const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", NULL, NULL); if (window == NULL) return 1; glfwMakeContextCurrent(window); glfwSwapInterval(1); // 开启垂直同步 // 2. 初始化imgui IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; ImGui::StyleColorsDark(); // 3. 初始化imgui后端 ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); bool show_demo_window = true; bool show_another_window = false; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); // 4. 主循环,在每一帧里创建GUI并渲染 while (!glfwWindowShouldClose(window)) { glfwPollEvents(); // 开始新的一帧 ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); // 1. 显示大的demo窗口 if (show_demo_window) ImGui::ShowDemoWindow(&show_demo_window); // 2. 创建小的demo窗口,这里可以熟悉下按钮、选中框等的绘制 { static float f = 0.0f; static int counter = 0; ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) counter++; ImGui::SameLine(); ImGui::Text("counter = %d", counter); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::End(); } // 3. 创建一个窗口 里面放个按钮 if (show_another_window) { ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) ImGui::Text("Hello from another window!"); if (ImGui::Button("Close Me")) show_another_window = false; ImGui::End(); } // 渲染 ImGui::Render(); int display_w, display_h; glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); } // Cleanup ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); glfwTerminate(); return 0;}
相关知识
Kengine游戏引擎项目推荐
幻世与冒险兑换码怎么使用 幻世与冒险兑换码使用方法介绍
恋与深空怎么使用觉醒之心 恋与深空觉醒之心怎么使用
鸣潮暗夜矩阵暝光90面板多少
《文明与征服》军旗使用攻略
角色卡怎么获取与使用
暗区突围摔炮什么时候出 摔炮上线时间与使用效果介绍
地下城与勇士手游气功师技能使用技巧
创造与魔法图鉴魔法书怎么使用
《艾尔登法环》大箭购买地点与使用技巧介绍
推荐资讯
- 1老六爱找茬美女的烦恼怎么过- 4999
- 2博德之门3黄金雏龙法杖怎么得 4869
- 3《大侠立志传》剿灭摸金门任务 4312
- 4代号破晓官方正版角色介绍 4023
- 5赛马娘锻炼到底的伙伴支援卡事 3803
- 6闪烁之光11月兑换码大全20 3776
- 7原神原海异种刷怪路线-原神原 3547
- 8爆梗找茬王厕所特工怎么通关- 3544
- 9《我的世界》领地删除指令是什 3440
- 10原神开局星落湖怎么出去 原神 3426