基于 Qt Quick 和 OpenUSD 的轻量级 3D 场景浏览与编辑器,内置 MCP Inspector 支持运行时 UI 自动化。
- 3D 视口:基于 Qt RHI 的实时渲染,支持旋转/平移/缩放相机
- 变换操控:移动、旋转、缩放 Gizmo,支持多选操作
- 网格与吸附:可切换地面网格(主/次线 + 坐标轴),移动吸附到 1cm 网格
- Prim 层级树:浏览和管理 USD 场景层级,支持可见性切换
- 属性编辑:查看和修改 Prim 属性,实时同步到视口
- 撤销/重做:完整的操作历史记录
- 文件支持:打开/保存
.usd、.usda、.usdc、.usdz格式 - Python 绑定:通过 pybind11 暴露
pyusdSim模块,支持 Python-C++ 共享 USD Stage
├── src/
│ ├── main.cpp # 应用入口
│ ├── UsdSimApp.h/cpp # App 封装:类型注册、初始化、findDocument、processEvents
│ ├── UsdViewportItem.h/cpp # 3D 视口渲染(RHI)、Gizmo、网格、相机
│ ├── UsdDocument.h/cpp # USD Stage 管理、Prim/属性 CRUD、StageCache 共享、撤销/重做
│ ├── UndoStack.h # 撤销/重做栈
│ ├── UndoCommands.h/cpp # 撤销/重做命令实现
│ ├── PrimInfo.h / AttrInfo.h # 数据结构
│ ├── bindings.cpp # pybind11 模块(pyusdSim)
│ ├── qml/
│ │ ├── main.qml # 主窗口布局(三栏分割)
│ │ ├── ViewportPanel.qml # 视口面板
│ │ ├── PrimTreePanel.qml # Prim 层级树面板
│ │ ├── AttributePanel.qml # 属性编辑面板
│ │ ├── HistoryPanel.qml # 操作历史面板
│ │ └── ... # 其他 QML 组件
│ ├── shaders/ # GLSL 顶点/片段着色器
│ └── icons/ # SVG 图标资源
├── python/examples/
│ └── test_shared_stage/
│ ├── main.py # Python-C++ 共享 Stage 演示
│ └── sample.usda # 测试用 USD 文件
├── build.py # 构建脚本(同时生成 build/usdsim_env.py)
├── pixi.toml # Pixi (conda-forge) 环境配置 + 任务定义
├── third_party/
│ ├── playqmlright/ # Git 子模块:Qt Inspector + MCP Server
│ └── prism_all/ # Git 子模块:UI 框架库
项目使用 Pixi 管理开发环境(Python 3.11 + Qt6 6.8.3 + PySide6 6.8.3 共享同一份 Qt 库)。
# 安装 pixi(如未安装)
curl -fsSL https://pixi.sh/install.sh | bash
# 初始化子模块
git submodule update --init --recursive
# 安装环境依赖
pixi install# 传入 OpenUSD 安装目录
pixi run build <pxr_install_dir>构建完成后会自动生成 build/usdsim_env.py,用于设置 Python 运行时所需的路径。
./build/bin/usdSim应用启动后会在端口 37521 上开启 Inspector Server(可通过 QML_INSPECTOR_PORT 环境变量修改)。
pixi run py-example python/examples/test_shared_stage/main.pypy-example 任务通过 build/usdsim_env.py 自动设置 sys.path(pyusdSim + pxr)和 LD_LIBRARY_PATH(conda libstdc++、USD 动态库),跨平台兼容。
项目配置了三个 MCP 服务器(见 .mcp.json):
| 服务器 | 用途 |
|---|---|
| playqmlright | Qt UI 自动化:截图、点击、输入、树结构查询 |
| context7-mcp | 查阅 Qt/USD 等外部文档 |
| playwright-mcp | Web 浏览器自动化 |
- 启动应用(自动嵌入 InspectorServer)
- Claude Code 通过
.mcp.json配置的 MCP 工具与应用交互 - 工具通过 TCP JSON-RPC 与 InspectorServer 通信
- 所有交互为合成事件注入,无需窗口前台焦点
通过 UsdUtilsStageCache 实现 Python 和 C++ 共享同一个 USD Stage 实例:
from pxr import Usd, UsdUtils
import pyusdSim
# Python 端打开 Stage 并放入缓存
stage = Usd.Stage.Open("scene.usda")
cache_id = UsdUtils.StageCache.Get().Insert(stage)
# 启动 Qt 应用
app = pyusdSim.UsdSimApp()
app.register_types()
app.init(["usdSim"])
# C++ 端通过 cache ID 加载同一个 Stage
doc = app.find_document()
doc.open_from_stage_cache(cache_id.ToLongInt())
# Python 修改 Stage 后通知 C++ 刷新视口
# 传入修改的 prim 路径列表,属性面板仅在选中的 prim 被修改时才刷新
doc.notify_stage_modified(["/World/Cube"])
# 事件循环
while True:
app.process_events()| 类 | 方法 | 说明 |
|---|---|---|
UsdSimApp |
register_types() |
注册 QML 类型 |
init(args) |
初始化 Qt 应用和 QML 引擎 | |
exec() |
进入 Qt 事件循环(阻塞) | |
find_document() |
获取 QML 中的 UsdDocument 实例 | |
process_events() |
手动处理一轮 Qt 事件(非阻塞) | |
uninit() / unregister_types() |
清理 | |
UsdDocument |
open(path) |
打开 USD 文件 |
open_from_stage_cache(id) |
从 StageCache 加载已有 Stage | |
insert_to_stage_cache() |
将当前 Stage 放入 StageCache,返回 ID | |
notify_stage_modified(paths=[]) |
通知视口重建 mesh,可选传入修改的 prim 路径 | |
is_open() / file_path() |
查询状态 |
| 操作 | 方式 |
|---|---|
| 旋转视角 | 拖拽 |
| 平移视角 | Alt + 拖拽 / 中键拖拽 |
| 缩放 | 滚轮 |
| 选择 | 左键点击 |
| 多选 | Ctrl + 点击 |
| 撤销/重做 | Ctrl+Z / Ctrl+Y |
私有项目。
