2、核心概念解析:Stage、Prim、USD 与 OmniGraph 的关系
好,咱们进入第二章。说实话,很多新手刚接触 Isaac Sim 时,最懵的就是这几个词:Stage、Prim、USD、OmniGraph。它们到底是个啥关系?
我刚开始用的时候也绕了一阵子。后来发现,其实用一句话就能说清楚:Stage 是舞台,Prim 是演员,USD 是剧本,OmniGraph 是导演的调度系统。
嗯,这个比喻可能不太严谨,但特别管用。咱们一个一个拆开看。
2.1 USD:一切的基础
USD(Universal Scene Description)是皮克斯搞出来的场景描述格式。说白了,它就是一种分层、可复用、非破坏性的 3D 数据组织方式。
你想想看,一个机器人仿真场景里有多少东西?机器人本体、传感器、工作台、传送带、灯光、碰撞体……如果用传统格式(比如 OBJ、FBX),改一个零件就得重新导出整个文件,太痛苦了。
USD 不一样。它用 层(Layer) 的概念,把场景拆成多个文件。比如:
robot.usd—— 机器人模型shelf.usd—— 货架模型lighting.usd—— 灯光设置physics.usd—— 物理参数
这些层可以叠加在一起,互不干扰。改灯光?只改 lighting.usd 就行,机器人模型不用动。
layers/ 文件夹,把模型、物理、材质、灯光分开存。后期排查问题,定位特别快。
2.2 Stage:场景的容器
Stage 就是 USD 场景在 Isaac Sim 里的运行时实例。你可以把它理解成一个「活着的」场景快照。
USD 文件是存在硬盘上的剧本,Stage 是加载到内存里正在演的舞台。你在 UI 里看到的那个 3D 视口,背后就是一个 Stage 对象。
在代码里,获取当前 Stage 的方式很简单:
from pxr import Usd
# 获取当前活动的 Stage
stage = omni.usd.get_context().get_stage()
# 或者用更直接的方式
stage = Usd.Stage.Open("/path/to/your/scene.usd")
Stage 负责管理所有 Prim 的生命周期——创建、删除、变换、属性修改。你在 UI 里拖拽一个物体,本质上就是在操作 Stage 里的 Prim。
2.3 Prim:场景的基本单元
Prim 是 USD 里的最小可操作对象。一个机器人是一个 Prim,一个关节是一个 Prim,一个碰撞体也是一个 Prim。
每个 Prim 都有:
- 路径(Path):比如
/World/Robot/arm_01 - 类型(Type):比如
Xform、Mesh、Joint - 属性(Attributes):位置、旋转、缩放、颜色、质量……
- 关系(Relationships):父子层级、约束绑定
在 Isaac Sim 里,你几乎所有的操作都是围绕 Prim 展开的。比如获取一个机器人的末端执行器位置:
# 获取 Prim
prim = stage.GetPrimAtPath("/World/Robot/end_effector")
# 读取位置属性
pos_attr = prim.GetAttribute("xformOp:translate")
position = pos_attr.Get()
print(f"末端位置: {position}")
2.4 OmniGraph:行为与逻辑的编排器
好,重点来了。OmniGraph 是 Isaac Sim 的可视化脚本系统。它用节点图(Node Graph)的方式,让你不用写代码就能定义物体的行为。
我个人的理解:USD 定义了「有什么」,OmniGraph 定义了「怎么动」。
举个例子,你想让一个传送带持续旋转:
- 创建一个
On Tick节点(每帧触发) - 连接一个
Rotate节点 - 把旋转角度输出到传送带 Prim 的
orientation属性
就这么三步,不用写一行 Python。
OmniGraph 的核心组件:
| 组件 | 作用 | 我常用的场景 |
|---|---|---|
| On Tick | 每帧触发一次 | 持续运动、传感器采样 |
| On Playback Tick | 仅在仿真运行时触发 | 物理相关逻辑 |
| Read Prim Attribute | 读取 Prim 属性值 | 获取关节角度、位置 |
| Write Prim Attribute | 写入 Prim 属性值 | 控制电机、灯光 |
| Math | 数学运算(加减乘除、三角函数) | 坐标变换、插值 |
| Conditional | 条件判断(if/else) | 碰撞检测后的分支逻辑 |
On Tick 节点太多,每帧都在做大量计算。我的建议是:能用 On Playback Tick 就别用 On Tick,能合并计算就别拆成多个节点。
2.5 四者的关系:一张图说清楚
下面这张 SVG 图,是我自己总结的「四层关系模型」。你看完应该就全明白了。
2.6 实际项目中的协作流程
在真实项目里,这四个概念是怎么配合的?我拿一个典型的机器人抓取仿真来举例:
- USD 层:设计师把机器人模型导出为
robot.usd,场景工程师把产线布局存为factory.usd,物理参数写在physics.usd。 - Stage 层:启动 Isaac Sim 时,通过
omni.usd.get_context().open_stage()把这些层叠加加载到内存。 - Prim 层:程序通过路径
/World/Robot/arm_06获取末端 Prim,读取它的位置属性。 - OmniGraph 层:创建一个抓取逻辑图——检测到物体靠近 → 触发 Gripper 闭合 → 更新物体父级为末端 Prim。
你看,每一步都对应一个核心概念。搞懂这个流程,后面写代码、调报错就顺了。
2.7 常见误区
最后,我列几个新手容易踩的坑,你注意一下:
| 误区 | 正确理解 |
|---|---|
| 把 USD 当成模型格式 | USD 是场景描述格式,不只是模型,还包含材质、物理、动画、灯光等 |
| 认为 Stage 就是文件 | Stage 是内存中的运行时实例,文件是持久化存储 |
| Prim 路径写死 | 路径可能因加载顺序变化,建议用 stage.GetPrimAtPath() 动态获取 |
| OmniGraph 能替代所有代码 | 复杂逻辑(如路径规划、状态机)还是得用 Python 扩展节点 |
嗯,这一章的内容就到这儿。这四个概念是 Isaac Sim 的基石,你花点时间吃透它,后面学起来会轻松很多。