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 举例:球体有 radius 和 extent,并且可以有默认值(04:23)。当一个 Sphere Prim 没有显式设置 radius,它会使用 schema 里的默认半径 1。
Attribute 和 metadata:数据放在正确的层级
(05:12)Prim 的属性叫 Attribute。每个 Attribute 有类型和值。Prim、Attribute、Stage 还可以带 metadata(元数据)。metadata 是键值信息,用来描述场景的辅助数据。
演讲列出三个常见的 Stage metadata:metersPerUnit、upAxis、doc(06: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 一个 defaultPrim(09: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 概念,先输出
defaultPrim、metersPerUnit、upAxis、Prim path 列表。
2. 做一个商品材质配置器
- 做什么:同一件 3D 商品提供多种颜色或材质,用户在 App 中切换配置。
- 为什么值得做:variantSet 正好表达离散替代方案。演讲用棋子从 Light 切到 Dark 说明了这个工作流。
- 怎么开始:在资产制作阶段把材质选择建成
colorvariantSet,App 侧保存用户选择的 variant 名称。
3. 做一个大型场景的延迟加载浏览器
- 做什么:先显示场景结构和占位,用户靠近某个区域时再加载复杂模型。
- 为什么值得做:payload 用于复杂几何和大型 scene graph 的延迟加载。它能降低初始打开 Stage 的成本。
- 怎么开始:把大型道具或角色做成 payload 引用,浏览器先读取 Stage 层级,再按交互触发 payload 加载。
4. 做一个非破坏性的 AR 布局编辑器
- 做什么:让用户移动、旋转、摆放 3D 物体,但不改原始资产文件。
- 为什么值得做:Layering 可以把资产和布局拆开。演讲中的
Catalog.usda和Layout.usda就是这个模式。 - 怎么开始:把资产引用放在 catalog layer,把 transform 覆盖写入 layout layer,最终用一个 Stage 组合两层。
关联 Session
- Explore USD tools and rendering — 这场是 10129 的后续,讲 Apple 平台上的 USD 工具、检查、转换和渲染。
- Bring your world into augmented reality — 从 Object Capture 到 RealityKit 的 AR 资产流程,适合和 USD 资产管线一起理解。
- Discover ARKit 6 — 介绍 ARKit 6 的平台能力,帮助判断 USD 资产最终会服务哪些 AR 场景。
- Create parametric 3D room scans with RoomPlan — RoomPlan 生成结构化 3D 表示,和 USD 的场景层级、资产组织有相近的建模思路。
评论
GitHub Issues · utterances