WWDC Quick Look 💓 By SwiftGGTeam
Understand USD fundamentals

Understand USD fundamentals

观看原视频

Highlight

这场 Session 是 USD 格式的入门介绍,面向不熟悉 USD 的 Apple 平台开发者。USD 是 Pixar 开发的通用 3D 场景描述格式,Apple 在 ARKit 和 RealityKit 中大量使用了它。


核心内容

很多团队第一次接触 USD(Universal Scene Description,通用场景描述)时,会把它当成一种 3D 文件格式。这个理解太窄。Session 开头给出的定义更准确:USD 有三部分,场景描述规范、API、渲染系统(01:22)。这场演讲只讲第一部分:场景数据如何描述、组织,并落到文件里。

问题来自 3D 资产的协作。一个 AR 商品模型可能有几何、材质、灯光、动画和物理属性。模型师、材质师、工具链和 App 都要改同一个资产。把所有内容烘进一个文件,任何修改都会变成全量替换。USD 的答案是把场景拆成 Stage、Layer、Prim、Attribute,再用 Composition 把它们组合起来。

Apple 用两个例子解释这套模型。第一个是煎饼场景:一个 Pancakes transform 下面放 Blueberry_01,蓝莓里再放 mesh 和材质绑定(06:55)。第二个是棋盘场景:棋子资产来自 catalog layer,位置来自 layout layer,颜色通过 variantSet 切换,重复棋子通过 instanceable metadata 复用(08:05)。

这就是 USD 的核心价值。资产文件保存基础数据,布局文件保存摆放位置,变体文件保存可切换方案。最终 Stage 由这些 Layer 组合而成。你可以替换某一层,而不用破坏其他层。

详细内容

Stage、Layer、Prim:先把场景拆成层级

02:43)USD 的 Stage 是一个 scene graph(场景图)。它把所有场景元素按层级组织起来。Stage 由一个或多个 Layer 组成;Layer 通常就是包含场景信息的文件。Stage 里的基本容器是 Prim。Prim 可以继续包含 Prim,形成树状结构。

下面是根据演讲中 “Sphere 和 Cube” 示例整理的概念性 USDA 片段:

#usda 1.0

def Sphere "Sphere"
{
}

def Cube "Cube"
{
}

关键点:

  • #usda 1.0 表示这是 USD 的 ASCII 文本表示,演讲中用它来解释文件内容。
  • def Sphere "Sphere" 定义一个名为 Sphere 的 Prim,类型也是 Sphere
  • def Cube "Cube" 定义一个名为 Cube 的 Prim,类型是 Cube
  • Prim 类型来自 schema。演讲中说 schema 为几何、材质等常见概念提供结构化含义(04:10)。

Schema 还会声明 attribute(属性)。演讲用 Sphere schema 举例:球体有 radiusextent,并且可以有默认值(04:23)。当一个 Sphere Prim 没有显式设置 radius,它会使用 schema 里的默认半径 1

Attribute 和 metadata:数据放在正确的层级

05:12)Prim 的属性叫 Attribute。每个 Attribute 有类型和值。Prim、Attribute、Stage 还可以带 metadata(元数据)。metadata 是键值信息,用来描述场景的辅助数据。

演讲列出三个常见的 Stage metadata:metersPerUnitupAxisdoc06:26)。下面是概念性写法:

#usda 1.0
(
    metersPerUnit = 1
    upAxis = "Y"
    doc = "Pancakes scene for workflow tracking"
)

关键点:

  • metersPerUnit 定义场景尺度单位。它影响整个 Stage,所以放在 Stage metadata。
  • upAxis 定义哪个轴是相机中的向上方向。演讲明确提到它可以是 X、Y、Z 之一。
  • doc 保存说明文字,可用于工作流追踪。
  • metadata 应该写在它影响的层级。影响全局就写在 Stage;只影响单个 Prim 就写在 Prim。

这条规则很实用。AR 资产进入 App 后,尺度和坐标方向出错,会直接导致模型大小不对、朝向不对。把全局 metadata 写清楚,比在 App 里临时修正更可靠。

Reference 和 defaultPrim:复用资产,不复制数据

08:40)棋盘示例从 reference 开始。Reference 的作用是让一个 Stage 里的 Prim 引用另一个 Layer 或同一 Stage 里的 Prim,而不复制数据。这样可以减少重复,也允许不同人和不同应用分开更新数据。

演讲建议 USD 资产总是 author 一个 defaultPrim09:28)。当外部 Layer 引用这个资产时,USD 就知道默认应该带入哪个 Prim。

概念性示例:

# Pawn.usda
(
    defaultPrim = "Pawn"
)

def Xform "Pawn"
{
}

关键点:

  • defaultPrim = "Pawn" 写在 Stage metadata,指定这个文件默认导出的 Prim。
  • def Xform "Pawn" 定义资产根 Prim。
  • 其他 Layer 引用 Pawn.usda 时,可以直接取到 Pawn,不用额外写路径。

如果没有 defaultPrim,或者想引用的不是默认 Prim,演讲给出另一个办法:显式指定 Prim path(09:53)。Prim path 是 Stage 中 Prim 的唯一标识,比如 /World/Pawn/World/Knight

Payload:大型数据延迟加载

10:44)Reference 会把资产带入场景。对于大型场景,这可能太重。USD 提供 payload,它是一类可以延迟加载的 reference。演讲建议在引用复杂几何、大型 scene graph、道具或角色时使用 payload。

概念性示例:

# Catalog.usda

def Xform "Pawn"
(
    payload = @Pawn.usda@
)
{
}

关键点:

  • Pawn 是 catalog layer 中的 Prim。
  • payload = @Pawn.usda@ 表示这个 Prim 的实际场景描述来自外部资产。
  • 打开 Stage 时可以先不加载 payload,场景会显示为空。
  • 启用 payload 加载后,棋子才进入场景。

这适合资产浏览器、关卡编辑器和大型 AR 场景。用户先看到结构和占位,需要细节时再加载几何,内存压力会小很多。

Layering:在新 Layer 里改位置

11:28)棋子带进来后,还要摆到棋盘上。演讲没有修改 catalog layer,而是创建 ChessSet Stage,并通过 sublayers 引入 catalog layer 和 layout layer(12:06)。

Layer 的顺序有强弱关系。上层更强,可以添加或覆盖下层数据(11:30)。这让移动棋子变成非破坏性修改。

概念性示例:

# ChessSet.usda
(
    subLayers = [
        @Catalog.usda@,
        @Layout.usda@
    ]
)

关键点:

  • ChessSet.usda 是最终打开的 Stage 文件。
  • Catalog.usda 提供棋子资产。
  • Layout.usda 保存棋子位置覆盖。
  • 移动 Pawn_01 时,只改 layout layer 中的 translation attribute,不需要改 pawn 资产本身。

这种工作流很适合多人协作。资产团队维护 Catalog.usda,关卡或空间布局团队维护 Layout.usda。最终 App 加载组合后的 Stage。

VariantSets:同一个资产切换不同方案

13:39)棋盘的对手方需要深色棋子。演讲没有再做一套深色模型,而是给资产加 variantSet。VariantSet 可以在 Stage 上动态切换离散选项。选项可以是材质、几何,或任何 USD 能表达的数据。

概念性示例:

# Pawn.usda

def Xform "Pawn" (
    variants = {
        string color = "Light"
    }
    prepend variantSets = "color"
)
{
    variantSet "color" = {
        "Light" {
            # use light material
        }
        "Dark" {
            # use dark material
        }
    }
}

关键点:

  • variantSets = "color" 表示这个 Prim 有一个名为 color 的变体集。
  • string color = "Light" 设置默认变体。演讲中默认棋子使用 light material。
  • "Light""Dark" 是两个可切换变体。
  • 在 catalog layer 中把某个 Pawn 的 variant 改成 Dark,该棋子就会使用深色材质(14:49)。

这个概念可以直接迁移到产品配置器。家具的木纹、汽车的颜色、角色的装备,都可以用 variantSet 表达。资产只有一份,配置保存为选择结果。

Instancing:重复场景图共享数据

15:09)棋盘里有很多重复棋子。USD 的 scene graph instancing 可以让 Stage 上的多个 Prim 共享同一段场景图。演讲指出,它能带来内存和性能改进。

概念性示例:

def Xform "Pawn_01" (
    instanceable = true
    payload = @Pawn.usda@
)
{
}

def Xform "Pawn_02" (
    instanceable = true
    payload = @Pawn.usda@
)
{
}

关键点:

  • instanceable = true 是写在 Prim 上的 metadata。
  • 两个 Pawn 都引用同一个 Pawn.usda
  • USD 可以把这些 Prim 当作候选实例,复用相同场景图。
  • 画面不变,但重复数据减少。

棋子只是例子。演讲还提到 foliage、furniture 等有大量重复物体的场景(15:20)。移动端 AR 场景尤其需要这类优化。

文件格式:usda、usdc、usd、usdz

16:48)最后,演讲把 USD 文件格式收束为四类:

  • .usda:ASCII 文本,可读,Session 中的示例都用它解释。
  • .usdc:Crate 二进制格式,更紧凑,加载更高效。
  • .usd:可以是 ASCII,也可以是二进制 crate。
  • .usdz:未压缩 zip 包,包含 USD 文件和纹理等辅助文件。

开发时可以用 .usda 看清结构。发布到 Apple 平台时,经常会遇到 .usdz,因为它把模型、纹理、材质等资源打包成单个文件,适合传输和预览。

核心启发

1. 做一个 AR 资产结构检查器

  • 做什么:读取 USD 或 USDZ 资产,列出 Stage metadata、defaultPrim、Prim 层级和 payload 使用情况。
  • 为什么值得做:演讲建议总是 author defaultPrim,并强调 metadata 放在正确层级。检查器可以提前发现资产进入 App 前的结构问题。
  • 怎么开始:从 Pixar USD 文档学习 Stage、Prim、Layer 概念,先输出 defaultPrimmetersPerUnitupAxis、Prim path 列表。

2. 做一个商品材质配置器

  • 做什么:同一件 3D 商品提供多种颜色或材质,用户在 App 中切换配置。
  • 为什么值得做:variantSet 正好表达离散替代方案。演讲用棋子从 Light 切到 Dark 说明了这个工作流。
  • 怎么开始:在资产制作阶段把材质选择建成 color variantSet,App 侧保存用户选择的 variant 名称。

3. 做一个大型场景的延迟加载浏览器

  • 做什么:先显示场景结构和占位,用户靠近某个区域时再加载复杂模型。
  • 为什么值得做:payload 用于复杂几何和大型 scene graph 的延迟加载。它能降低初始打开 Stage 的成本。
  • 怎么开始:把大型道具或角色做成 payload 引用,浏览器先读取 Stage 层级,再按交互触发 payload 加载。

4. 做一个非破坏性的 AR 布局编辑器

  • 做什么:让用户移动、旋转、摆放 3D 物体,但不改原始资产文件。
  • 为什么值得做:Layering 可以把资产和布局拆开。演讲中的 Catalog.usdaLayout.usda 就是这个模式。
  • 怎么开始:把资产引用放在 catalog layer,把 transform 覆盖写入 layout layer,最终用一个 Stage 组合两层。

关联 Session

评论

GitHub Issues · utterances