Understand USD fundamentals
System & Services 进阶 20m

USD 基础入门

Understand USD fundamentals

2022年6月6日

在 Apple 官方观看视频

一句话判断

Apple 把 Pixar 的 USD(Universal Scene Description)格式推到了台前——ARKit、RealityKit、Reality Composer Pro 都以 USD 为核心,如果你做 3D/AR 开发,这个格式是你绕不过去的基础设施。

这场 Session 讲了什么

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

USD 是什么。 USD(Universal Scene Description)不仅仅是一个文件格式——它是一个完整的场景描述系统。它定义了如何在文件中表达 3D 场景的所有元素:几何体、材质、灯光、动画、物理属性、层级关系等。USD 支持两种文件格式:.usda(ASCII 文本,人类可读)和 .usdc(二进制,加载更快)。还有 .usdz 格式,这是 Apple 推广的打包格式,把所有资源(模型、纹理、材质)打包到一个文件里。

USD 的层级结构。 USD 用”Stage”来表示一个场景,Stage 由多个”Layer”组成。每个 Layer 可以定义或覆盖上一层的属性。这就像 Photoshop 的图层概念——底层定义基础属性,上层可以覆盖或添加新属性。这种设计让多人协作变得容易——A 在一个 Layer 里做模型,B 在另一个 Layer 里做材质,最后合并到一个 Stage 里。

Prim(Primitive)概念。 USD 场景的基本单位是 Prim。一个 Prim 可以是一个几何体、一个灯光、一个材质、一个相机等。Prim 有层级关系——就像文件系统的目录结构。一个模型 Prim 下面可以有多个 mesh Prim 和 material Prim。

Attribute 和 Relationship。 每个 Prim 有多个 Attribute(属性)来描述它的参数——位置、颜色、材质引用等。Relationship 用来建立 Prim 之间的关联——比如一个 mesh Prim 通过 relationship 引用一个 material Prim。Attribute 有时间采样(time sample)的概念,可以存储动画数据——不同时间点上的不同值。

Composition(组合)。 这是 USD 最强大的特性。一个 Stage 可以由多个文件组合而成——你可以把一个基础模型文件、一个材质覆盖文件、一个动画文件组合成一个完整的场景。组合有明确的优先级规则:“stronger” 的 Layer 会覆盖 “weaker” 的 Layer。这个机制让资产复用变得极其灵活——同一个基础模型,加不同的材质文件就能生成多种变体。

Apple 生态中的 USD。 ARKit 的 ARReferenceObject 支持 USDZ 格式。RealityKit 的 ModelEntity 可以直接加载 USDZ 文件。Reality Composer Pro(Xcode 14 新增的工具)用 USD 作为原生格式来编辑 AR 场景。Apple 的 3D 模型预览(Quick Look)也支持 USDZ。

值得深挖的点

USDZ 和 USD 的区别。 USDZ 是 Apple 推广的”零压缩、自包含”格式。它把所有引用的外部资源(纹理、材质库)打包到一个文件里,不需要额外的资源文件夹。这使得 USDZ 可以像图片文件一样分享——通过 AirDrop、iMessage、网页下载。但 USDZ 不支持 USD 的一些高级特性(比如 composition arc),它是 USD 的一个受限子集。

Composition Arc 的优先级。 USD 定义了多种 composition arc(组合弧):sublayer、reference、payload、variant、inherit、specialize。它们的优先级从高到低排列:sublayer > reference > payload > variant > inherit > specialize。理解这个优先级是调试场景组合问题的关键——如果你发现某个属性没有被正确覆盖,很可能是因为优先级设置不对。

代码片段

USD 的 ASCII 格式(.usda)示例:

#usda 1.0
(
    defaultPrim = "MyModel"
    doc = "一个简单的 USD 场景示例"
)

def Xform "MyModel" {
    def Mesh "Body" {
        float3[] extent = [(-5, -5, -5), (5, 5, 5)]
        int[] faceVertexCounts = [3, 3, 3, 3]
        int[] faceVertexIndices = [0, 1, 2, 2, 1, 3, ...]
        point3f[] points = [(-1, -1, 0), (1, -1, 0), ...]
        rel material:binding = </MyModel/Materials/BodyMaterial>
    }

    def Material "BodyMaterial" {
        token outputs:surface.connect = </MyModel/Materials/BodyMaterial/surface>

        def Shader "surface" {
            uniform token info:id = "UsdPreviewSurface"
            color3f inputs:diffuseColor = (0.8, 0.2, 0.1)
            float inputs:metallic = 0.5
            float inputs:roughness = 0.3
        }
    }
}

在 RealityKit 中加载 USDZ:

import RealityKit

// 从 App bundle 加载 USDZ 模型
let entity = try Entity.load(named: "MyModel.usdz")

// 添加到 AR 场景
let anchor = AnchorEntity(plane: .horizontal)
anchor.addChild(entity)
arView.scene.anchors.append(anchor)

// 访问模型层级
for child in entity.children {
    print("Prim: \(child.name)")
    if let model = child as? ModelEntity {
        print("材质数量: \(model.model?.materials.count ?? 0)")
    }
}

最佳实践

创建 3D 资产时优先使用 USDZ 格式。如果你用 Blender 或 Maya 建模,导出时选择 USDZ 或 USD 格式。Apple 的工具链对 USDZ 的支持最好——Xcode 预览、Quick Look、Reality Composer Pro 都能直接打开。

场景层级要保持清晰。不要把所有 Prim 都放在根层级下面——按功能分组(几何体、材质、灯光、动画分开)。这不仅在 USD 文件里更容易管理,在 RealityKit 里遍历 entity 层级时也更方便。

纹理贴图使用 PNG 或 JPEG 格式,避免用 EXR 等 HDR 格式。USDZ 对纹理格式有要求——PNG 用于需要 alpha 通道的贴图,JPEG 用于 diffuse 贴图。HDR 纹理在 USDZ 里不受支持。

还有什么值得关注

  • Apple 在 macOS 13 中新增了 USDRenderer API,可以把 USD 场景渲染成图片或视频,不需要 RealityKit。
  • Xcode 14 的 Reality Composer Pro 可以直接编辑 USDA 文件,支持实时预览。
  • USD 格式支持 Unicode 字符和非 ASCII 文本,模型和材质可以用中文命名。
  • Pixar 维护的 USD 官方文档是学习 USD 最权威的资源,Apple 的文档更多聚焦在 Apple 生态中的使用方式。
WWDC 2022