美文网首页
Dear imgui & igl

Dear imgui & igl

作者: 坚果jimbowhy | 来源:发表于2020-07-12 21:39 被阅读0次
    103_Events.cpp 106-ViewMenu.cpp imgui v1.77 example_glfw_opengl2

    Introduction

    Libigl 是一个 C++ 几何处理库,用于产品三维原型的开发,或科研使用。

    IMGUI - Immediate Mode Graphical User interface,简称 Dear imgui 是 github 上 star 最多的 GUI 框架,Blizzard, Google, Nvidia, Ubisoft 等赞助,易学,易用,好用,功能也不弱,能够胜任绝大部分的桌面应用程序开发,甚至商业程序。

    对于游戏开发者来说,在开发过程中,加入 UI 的支持是不可或缺的一环,不过想要自己动手敲代码实现 UI 实属一件难事,后来 ImGUI 诞生为开发者们带来直接拿来用般的便利。

    GeeXLab 是基于 imgui 开发的一款界面原型编辑器:

    GeeXLab is a cross-platform proto-engine. It can be used for 2D/3D programming, game development, creative coding or prototyping. GeeXLab is based on Lua, Python, OpenGL, Vulkan and Direct3D 12.

    在 imgui.cpp 提供的文档中,提到此框架的目标:

     MISSION STATEMENT
     =================
    
     - Easy to use to create code-driven and data-driven tools.
     - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
     - Easy to hack and improve.
     - Minimize screen real-estate usage.
     - Minimize setup and maintenance.
     - Minimize state storage on user side.
     - Portable, minimize dependencies, run on target (consoles, phones, etc.).
     - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,.
       opening a tree node for the first time, etc. but a typical frame should not allocate anything).
    
     Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
     - Doesn't look fancy, doesn't animate.
     - Limited layout features, intricate layouts are typically crafted in code.
    

    大多数使用ImGUI风格的程序员发现,使用 ImGUI 来创建用户界面比使用传统的保留模式图形用户界面(GUI)要容易得多。而且性能会得到显著地提高。

    典型的面向对象的 GUI 框架是一个保留模式系统,在该系统中,你基本上创建了一个 GUI 框架控件(widget)的“场景图”(窗口、网格、滑块、按钮、复选框等等)。你将你的数据复制到这些控件中,等待事件(event)或回调(callback)在控件被编辑时接收到通知。然后查询控件的新值并将其复制回你的数据中。

    这种模式几乎应用于所有的 GUI 系统中,Windows、WFP、HTML DOM、Apple UIKit、Qt,你能叫出名字的 99% 的 GUI 框架都属于保留模式的,面向对象的,“场景图”式的GUI。

    这种模式的GUI存在的问题是:

    • 必须编写大量代码来管理 GUI 对象的创建和销毁。

      设想你有一个滚动列表,你经常需要创建 100 多个或 1000 多个GUI控件(就像HTML,创建一个TR,然后是 TD,然后是每个 TD 的内容,等等)。如果数据真的很大,你最终不得不创建一些控件的虚拟窗口,要么在用户滚动时创建新的窗口并且删除旧窗口,要么将旧窗口从后面拉出来,然后将其添加到前面。其结果是:你需要写的代码太多了。

    • 创建和销毁对象导致UI反应迟缓。

      由于GUI对象的创建和销毁速度很慢(通常它们是非常大的对象),因此通常需要编写大量的代码来帮助寻找和设计解决方案,以最小化需要创建和销毁的对象数量。

      想想 React 如何使用虚拟 DOM 来识别差异,然后将这些差异应用到实际的 GUI 控件和 DOM 树/场景图中。

    • 你必须编制数据传入/传出控件。

      这就需要先将数据复制到控件中,然后对事件做出响应,并将控件中的新数据读回。需要编写更多的代码。

    与此相反,ImGUI中没有对象,也几乎没有状态。大多数ImGUI的简单做法是像下面这样调用函数:

    if (ImGUI::Button("Click Me")) {
      IWasClickedSoDoSomething();
    }
    // draw slider
    ImGUI::SliderFloat("Speed:" &someInstance.speed, 0.0f, 100.0f);
    

    这里的 Button 和 Slider 做了两件事:

    • 它们将绘制控件所需的位置和纹理坐标添加到一个向量(数组)中。如果控件被裁剪出屏幕或在当前窗口/裁剪矩形之外,则坐标不被添加。
    • 它们检查鼠标指针的位置、键盘状态等,以操作该控件。如果数据发生变化,它们会立即返回。

    所以,这样做有如下优点:

    • 丝毫不需要分配内存,也即需要的内存为零!
    • 速度很快。即使使用非常复杂的 UI 并且只有单线程的情况下,大多数(如果不是全部)ImGUI 在 60fps 的速度下运行没有任何问题。
    • 不需要对必须管理的对象进行创建和销毁操作。
    • 没有状态,因为没有对象来存储状态。
    • 基本不需要编制数据。
    • 没有需要注册或响应的事件或回调。

    下面两点可能是这样做的缺点:

    • 可能需要更多的 CPU。

      保留模式 GUI 设计的初衷是为了尽量减少工作量。假设你有一个类似微软 Excel 的用户界面。它有 75 个工具栏按钮和显示 300 个单元格的电子表格。输入光标位于单元格 E7 中,并且在闪烁。如果回到 Windows 3.0 及更早版本,CPU 将绘制像素,GPU 那时不存在。GUI 系统确定只需要重新绘制光标本身大小的一些小区域,并且只需要将这些像素直接重新绘制到屏幕内存中。同样,如果键入字母,系统只能确定单元格 E7 已被修改,只需重新绘制单元格 E7。

      在 1993-1994 年的计算机上,这点很重要。因为计算机无法以每秒 60 帧的速度绘制整个屏幕。

      因此,对于传统的基于“场景图”的面向对象的保留模式 GUI 来说,这是最好的做法。

      需要注意的是,系统仍然需要检查图形用户界面的大部分地方来计算最小的影响区域是什么。这可能不如重新绘制每个像素的工作量大,但需要的工作量也不少。

      ImGUI 则相反,任何时候你想更改任何内容,整个图形用户界面就要重新绘制。即使是光标。以我们进入 Excel 示例,所有 75 个工具栏控件和 300 个单元格都将因为一个闪烁的光标而重新绘制。

      这是 ImGUI 的最坏情况,大量的 CPU 被浪费了。

      再拿滚动电子表格作个对比。

      在基于场景图的保留模式的图形用户界面中,假设您按下 page down 键,很可能 300 个单元格控件会被删除,300 个新的单元格控件会被创建,每个单元格的数据将被复制到每个单元格控件中。从所有这些来看,GUI 系统将遍历所有 300 个单元并将它们绘制出来。

      相反,在 ImGUI 的情况下,不会删除任何旧控件,不会创建任何新控件,也不复制任何数据, 300个单元格要像先前一样绘制出来。在这种情况下,ImGUI 为更新整个显示页面所需要的 CPU 工作量仅仅是保留模式GUI系统工作量的十分之一至百分之一。

      哪种情况更常见呢?对于一个文本编辑器来说,通常只有很小的变化,所以场景图式的 GUI 会获胜。但是对于 Instagram 或 Facebook 应用程序,人们几乎经常滚动页面,在这种情况下,ImGUI 以压倒性优势获胜。

    • 可访问性问题

      使用保留模式 GUI,所有控件的数据都已复制到 GUI 的场景图中。这意味着 GUI 系统本身可以查看这些数据并提供不同的接口(比如放大,说出它,变成盲文,等等)。

      而使用 ImGUI 的情况下,通常 GUI 不保留任何数据,所以它可能做不了保留模式 GUI 能够做的那些事情。

      这可能是一个值得研究的地方。可能存在一些方案可以使 ImGUI 能够比传统方法更好地处理可访问性问题。大多数 ImGUI 用于游戏开发,它针对的对象是同一团队中的游戏开发人员,而不是最终用户。也就是说,没有动力去推动对这些解决方案的探索。

    • 样式

      对于 ImGUI 来说,样式是由你来设计的。添加更多的样式选项,甚至是几乎所有的 CSS 或者至少是好的那部分 CSS,可能是相对容易实现的,而且能保持好的性能。更好的地方在于:你可以很容易选择需要这些样式或者不需要这些样式。所以如果你的应用程序不需要这样的样式,为什么要浪费内存或CPU时间来处理它呢?为什么要像大多数保留模式GUI那样,不管你使用如否,都要将所有的样式数据嵌入到每个控件中呢?考虑一下 HTML,如果每个元素都有 100 个样式设置(毫不夸张确实有 100 个设置),那是一件多么可怕的事。

    • 动画

      大多数 ImGUI 都是无状态的,所以所有的动画都取决于应用程序。虽然很容易想到使用存有少量动画状态数据的包装器 wrapper 可以很容易地将 UI 动画放回。但是事实上,包装器可以让你选择只在重要的地方支持动画,比如样式。大多数保留模式的GUI都保存有大量的数据、状态和每个控件的设置,无论你使用如否。

    示例

    请按 VCpkg 开源库管理工具 配置 VCpkg 模块管理工具,安装:

    vcpkg install opengl:x64-mingw
    vcpkg install glew:x64-mingw
    vcpkg install glfw3:x64-mingw
    vcpkg install eigen:x64-mingw
    vcpkg install imgui:x64-mingw
    vcpkg install libigl:x64-mingw
    

    由于模块更新不同步,libigl 中的头文件会需要相应的修改,例如 imgui 中提示的符号更新:

    • 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).

    字体部分另行下载;

    另外,比较怪异的是 libigl 的示例也依赖了 imgui 中示例的文件,需要给编译器设置好,否则找不到 ImGui_ImplGlfw_InitForOpenGL:

    • ../imgui/examples/imgui_impl_glfw.cpp
    • ../imgui/examples/imgui_impl_opengl3.cpp

    官方提供的示例,编译脚本写得过于复杂,编译前还要判断是否要下载模型文件,如果网络不好,很空间就失败了:

    https://github.com/libigl/libigl-tutorial-data

    libigl、eigen 这些库虽然可以直接使用头文件而不必事先编译,但是对于多例程的编译过程来说,使用预先编译好的静态库会大大提高编译效率。

    cmake ../ -DCMAKE_BUILD_TYPE=Release\
          -DLIBIGL_USE_STATIC_LIBRARY=ON\
          -DCMAKE_INSTALL_PREFIX=/path/to/custom/installation
    

    代码见 libigl 的 tutorial 目录。

    相关文章

      网友评论

          本文标题:Dear imgui & igl

          本文链接:https://www.haomeiwen.com/subject/gcsncktx.html