用户界面#
MuJoCo 拥有一个原生 UI 框架。其使用方法在 simulate.cc 查看器中有所体现。该框架的设计目标是:在更新和渲染方面保持高速,对于开发者和用户都易于使用,支持跨平台,并与原生的 MuJoCo 渲染器集成。为了实现这些设计目标,我们省略了其他 UI 框架中常见的许多功能和自定义选项,转而专注于效率和自动化。
设计概览#
- 原生 OpenGL 渲染
我们不使用任何辅助工具或库。相反,我们提供了直接在 OpenGL 中渲染所有 UI 元素的 C 代码。我们支持多个 UI,每个 UI 都是一个虚拟矩形,其高度可以超过可见窗口。每个 UI 的元素仅在必要时通过最小化更新,在辅助 OpenGL 缓冲区中进行离屏渲染。在每次屏幕刷新时,我们会将这些辅助缓冲区的像素复制到窗口帧缓冲区,并在窗口小于 UI 时实现垂直滚动条。此复制操作在 GPU 上完成,速度非常快。
- 平台抽象
软件设计分为三个层级:与 MuJoCo 渲染器(完全跨平台)协同工作的 UI 元素 OpenGL 渲染;用于访问窗口、键盘和鼠标的抽象函数,这些函数在
PlatformUIAdapter类中定义为纯虚函数;以及派生类GlfwAdapter中对这些函数的实现。GLFW 本身是跨平台的。尽管如此,我们还是选择了这种分层设计,以便将通用功能与平台特定功能分离开来。如果由于某种原因需要将 GLFW 替换为其他类似的框架,则仅需重写GlfwAdapter。- 主题与外观
单个 UI 元素不允许在外观或布局上进行自定义。相反,我们使用主题来控制颜色和间距,并自动排列所有 UI 元素。框架提供了几种内置主题,用户也可以设计自定义主题,但整个 UI 对所有元素使用单一主题。外观采用极简风格:主要是带有文本的彩色矩形。不支持位图和其他自定义装饰。UI 元素类型包括:复选框、单选按钮组、选择列表、滑块、文本编辑框、静态文本、按钮、分隔符。这些元素被组织成可以展开和折叠的部分。
- 布局与矩形
每个 UI 都是一个虚拟矩形,其宽度由主题决定,高度则由各个部分、各部分内的项目以及每个部分的展开/折叠状态决定。更新 UI 时,这些虚拟矩形的大小和辅助缓冲区会自动处理。每个 UI 在屏幕上都有一个可见矩形,此外还有其他矩形——用于 3D 渲染、2D 图形以及可能的自定义 OpenGL 渲染。所有这些可见矩形都会被保存(在 mjuiState 中),并用于确定鼠标事件的指向。矩形布局由用户提供的回调函数更新。
- 静态分配与创建
我们没有分配和释放大量对应于 UI 对象的内存并将其链接起来,而是创建了一个单一的 C 结构体(类型为 mjUI),通过静态分配支持最大数量的部分和元素,并记录当前正在使用的数量。UI 的创建通过辅助函数简化,其输入是一个 C 结构体(类型为 mjuiDef),本质上是一个表格,其中每一行描述一个 UI 元素(见下文)。这使得用极少的 C 代码构建复杂的 UI 成为可能。程序化创建 UI 也是可行的,例如在填充对应于 MuJoCo 模型关节的滑块时。
- 最小状态
UI 设计尽可能无状态,以简化开发。这体现在两个方面。首先,我们不复制 UI 元素中的用户数据,而是存储指向用户数据的指针。例如,我们可以创建一个 UI 滑块并将其数据指针设置为
mjData* d->qpos+7。该滑块将可视化并控制 MuJoCo 模型 qpos 向量的第 7 个标量分量。因此,当模拟更新时,我们必须记得同时更新 UI。此外,当模拟正在更新时,我们还必须禁用 UI 编辑。但这样做的好处是 UI 构建更容易,且不会出现用户数据与 UI 之间不一致的风险。其次,UI 元素本身大多是无状态的。相反,我们维护一组最小的全局状态,特别是鼠标和键盘状态、部分的展开/折叠状态,以及正在编辑的文本框的内容(如果有的话)。- 自动启用与禁用
虽然每个 UI 项目都可以直接设置为启用或禁用状态,但我们也提供了如下的自动化功能。每个 UI 项目都可以分配一个整数类别。然后,mjfItemEnable 回调函数会根据程序特定的条件,确定每个类别应该被启用还是禁用。例如,在更新模拟状态时,应禁用那些可以更改 MuJoCo 模型关节值的滑块。
主要 API#
点击下方链接查看主要 UI 数据结构和函数的详细 API 参考。
主要数据结构
主要函数
mjui_update:主要的 UI 更新函数。
mjui_render:渲染 UI。
mjui_event:低级事件处理器。
mjui_add:用于构建 UI 的辅助函数。