用户界面#
MuJoCo 拥有一个原生 UI 框架。其用法在 simulate.cc 查看器中得到了展示。它被设计为在更新和渲染方面速度快、对开发者和用户都易于使用、跨平台,并与原生 MuJoCo 渲染器集成。为了实现这些设计目标,我们省略了其他 UI 框架中可用的许多功能和自定义选项,转而专注于效率和自动化。
设计概述#
- 原生 OpenGL 渲染
我们不使用任何辅助工具或库。相反,我们提供 C 代码,用于直接在 OpenGL 中渲染所有 UI 元素。我们支持多个 UI,每个 UI 都是一个虚拟矩形,其高度可以超过可见窗口。每个 UI 的元素通过最小化更新,仅在必要时才在辅助 OpenGL 缓冲区中进行离屏渲染。在每次屏幕刷新时,我们再将像素从这些辅助缓冲区复制到窗口帧缓冲区,并在窗口小于 UI 时实现垂直滚动条。这种复制操作在 GPU 上完成,速度非常快。
- 平台抽象
软件设计有 3 个层次:与 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 也是可行的,例如在用与 MuJoCo 模型关节相对应的滑块填充 UI 时。
- 最小化状态
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 的辅助函数。