为什么是 USD#

学习目标

  • 说清 USD 是什么,为什么它不只是"又一种机器人描述格式"

  • 对比 URDF、MJCF、SDF 与 USD 在描述范围、引用、物理、协作上的差别

  • 说出 Isaac Sim 把一切建立在 USD 上带来的好处和代价

前置知识

USD 是什么#

这一节回答:USD 到底是文件格式,还是别的什么?

USD(Universal Scene Description,也叫 OpenUSD)由 Pixar 开发并开源,用来交换和叠加编辑任意 3D 场景[1]。2023 年,Pixar、Adobe、Apple、Autodesk 与 NVIDIA 成立 Alliance for OpenUSD(AOUSD),推动它成为开放标准[2]。

把 USD 理解成文件格式是不够的。它由三部分组成:

  • 场景描述:场景里有什么东西、它们是什么类型、带哪些数据;

  • 合成引擎(composition engine):把分散在许多文件里的描述按固定规则合成为一个场景,官方 FAQ 说这才是 USD 的首要功能[3];

  • API:C++ 与 Python 接口,用来读写、遍历这个合成后的场景[1]。

合成后的整个场景叫 Stage,其中每个节点叫 Prim。这两个概念在 2.2 细讲。

文件扩展名一句话区分:.usda 是可读的文本,.usdc 是二进制(Crate 格式,支持随机访问),.usd 两者皆可,.usdz 是把 USD 与贴图等资源打进一个包[3]。

与 URDF、MJCF、SDF 对比#

这一节回答:机器人领域已经有好几种描述格式了,USD 有什么不同?

维度

URDF

MJCF

SDF

USD

描述范围

单个机器人,不能描述它在世界里的位置,也不能描述灯光等非机器人对象[4]

一个完整模型:worldbody 下的多个物体、物理选项、执行器、传感器[5]

整个世界:world 下含物理、场景、灯光、多个模型[6]

任意 3D 场景,机器人只是其中一部分[1]

层级与引用

link / joint 组成的树,不能描述闭环机构[4];文件本身没有引用机制,通常用 xacro 宏先生成再使用[7]

嵌套的 body 树;<include> 在解析时把其他文件并入[8]

<include> 按 URI 引入模型,可覆盖名字与位姿[6]

子 Layer、引用(reference)、载荷(payload)、变体(variant)等多种合成方式,规则统一[1]

物理

质量、惯量、关节限位等基本动力学,缺少摩擦等属性[4]

完整的物理参数、接触与执行器模型[5]

physics 元素描述引擎参数[6]

通过 Schema 扩展,如通用的 UsdPhysics[9],各引擎再加自己的 Schema(如 PhysX)[10]

外观与渲染

每个 link 的材质只有颜色和贴图文件[11]

网格、贴图、材质资源[8]

视觉与材质元素[6]

材质与着色网络(UsdShade)[12],可引用 MDL 等材质定义[13]

非破坏性编辑

不支持,要改就改文件或重新生成(推断:格式中没有覆盖机制)

default 类可统一设置默认值[8],但不能在不改原文件的情况下覆盖另一份文件(推断)

<include> 时可覆盖少数字段[6]

在更强的 Layer 里写覆盖,不动原文件[1]

多人协作

单文件,靠版本管理合并(推断)

同左(推断)

同左(推断)

不同的人在各自的 Layer 上工作,互不覆盖[1]

主要工具链

ROS(RViz 等)[7]

MuJoCo

Gazebo

Isaac Sim / Omniverse,以及 AOUSD 成员公司的内容创作软件(推断:依据成员名单[2])

表 1:四种格式的对比。MuJoCo 也能加载 URDF 与 OpenUSD[5],格式之间可以转换,但转换后各自的能力范围不变。

URDF、MJCF、SDF 都是为某个仿真器或框架设计的机器人或世界描述,一个文件大致对应一个完整模型。USD 是为多方协作搭建大型场景设计的场景合成系统,一个场景由许多文件叠加而成。

对机器人仿真意味着什么#

这一节回答:这些差别在机器人仿真里有什么用?

用本站主线机器人 Galbot One Golf 的描述仓库举例[7]。这个仓库同时提供 URDF(给 ROS)、MJCF(给 MuJoCo)和 USD(给 Isaac Sim)三份描述。它的 USD 入口文件本身很小,主要内容是"引用什么、怎么组合":

        %%{init: {"flowchart": {"rankSpacing": 34, "nodeSpacing": 18, "padding": 6}}}%%
flowchart TB
    ROOT["galbot_one_golf.usda<br/>入口"]
    BASE["base.usda<br/>几何与材质"]
    VPHY["Physics 变体<br/>默认选 physx"]
    VOTH["Sensor / Robot / ROS 变体<br/>各有 none 与启用两档"]
    PHYSX["physx.usda<br/>PhysX 专用参数"]
    PHY["physics.usda<br/>通用物理"]
    ROOT --> BASE
    ROOT --> VPHY
    ROOT --> VOTH
    VPHY --> PHYSX
    PHYSX --> PHY
    

图 1:Galbot USD 资产的组织方式,自上而下,底层在下。箭头表示"引用 / 叠加了下面的文件":入口引用几何本体,再用四组变体按需加载物理、传感器等内容;physx.usda 叠加在通用的 physics.usda 之上。

从这个例子可以看出三点:

  • 同一份资产服务多种用途。 几何、材质、物理、传感器写在同一个资产里,渲染、物理仿真、合成数据用的是同一份数据。

  • 按需组合,而不是复制出多个版本。 要不要物理、要不要传感器,由入口文件里的变体(variant)选择,不需要为每种组合各存一份文件[14]。

  • 分层覆盖,不改原文件。 通用物理写在 physics.usda(UsdPhysics 的刚体、质量、关节驱动),PhysX 专用参数写在 physx.usda,后者把前者作为子 Layer 叠加进来[10]。换物理引擎时只需换上面那一层。这种覆盖机制在 2.3 Layer 与合成 细讲。

场景层面也一样:Isaac Lab 搭建训练场景时,机器人、桌子、物体各是一份 USD,由场景引用组装起来,再复制成成千上万份(见 3.7 场景组装与 Cloner)。

Isaac Sim 与 USD 的关系#

这一节回答:USD 在 Isaac Sim 里处于什么位置?

在 Isaac Sim 里,Stage 就是仿真世界。你在界面里看到的、物理引擎在算的、传感器在拍的,都是同一个 Stage 上的 Prim。导入 URDF 或 MJCF,实际上是把它们转换成 USD[15];之后仿真读的是 USD。USD 是 Omniverse Kit 的组成部分,在分层图中的位置见 0.2。

相关页面:

代价#

这一节回答:用 USD 要付出什么?

  • 概念多。 Layer、引用、载荷、变体、合成强弱顺序,都要先弄懂,才能判断"这个值最终从哪来"。URDF 打开一个文件就能看全。

  • 调试方式不同。 某个属性的值可能来自好几层中的任意一层,出了问题要看合成结果,而不是只看某一个文件。需要借助 Isaac Sim 界面里的属性面板或 USD 的 Python API(见 2.5)。

  • 二进制文件难以直接比较。 .usdc 与 .usd(二进制时)不能直接 diff,需要先转成 .usda。

  • 机器人生态还在迁移。 ROS 工具链仍以 URDF 为主,同一个机器人往往要同时维护多份描述,Galbot 仓库就是例子[7]。

常见误解#

误解一:USD 是 NVIDIA 的格式

不是。USD 由 Pixar 开发并开源[1],目前由 Pixar、Adobe、Apple、Autodesk、NVIDIA 等成立的 AOUSD 推动标准化[2]。NVIDIA 是主要推动者之一,Omniverse 以它为基础。

误解二:导入 URDF 以后,URDF 还在起作用

导入是一次性转换,结果是一份 USD[15]。之后在 Isaac Sim 里改的是 USD;再改 URDF 不会自动同步,需要重新导入。

误解三:USD 文件就是一个 3D 模型

一个 USD 文件可以只是一个模型,也可以只是一组覆盖、一个变体,或者一个只负责"引用谁"的入口,比如 Galbot 的入口文件[14]。你在 Stage 上看到的是许多文件合成后的结果。

误解四:有了 USD,URDF 和 MJCF 就没用了

它们服务于不同的工具链。ROS 仍以 URDF 为主,MuJoCo 以 MJCF 为主。本站主线用 USD,但真机部署时通常还要 URDF。

延伸阅读#

版本说明#

本页不涉及具体 API,内容对 5.1.0 与 6.1 都成立。Isaac Lab 3.0 引入了不启动 Kit 的运行方式(Kit-less),这种模式下 USD 的角色有何变化,见 8.1 3.0 改了什么、为什么改。