WWDC Quick Look 💓 By SwiftGGTeam
What's new in USD

What's new in USD

观看原视频

Highlight

Apple 与 Pixar 提出一组 preliminary AR USD schemas,让 Reality Composer 可以把锚定、行为、物理、空间音频、3D 文本和播放元数据写入 USDZ,并在 DCC 与 RealityKit 工作流之间保留这些 AR 信息。


核心内容

过去做 AR 资产,流程很容易在工具之间断开。艺术家在 Houdini 或 Maya 里改了模型,开发者在 Reality Composer 里加了行为、锚定和物理。文件再回到 DCC 时,DCC 可能不认识这些 AR 信息。模型还能显示,交互逻辑却可能成了旁路数据,团队只能手工重做或停止回流。

这场 session 解决的就是这个断点。Reality Composer 在 2020 年新增 USDZ 导出,Apple 又和 Pixar 合作提出一组 preliminary AR USD schemas。它们把 Reality Composer 里的 scene、anchoring、behavior、physics、spatial audio、3D text 和 playback metadata 都表达成 USD 结构。这样,一个资产可以从 Reality Composer 导出到 Houdini,继续编辑后再回到 Reality Composer,原来的行为仍在文件里。

演讲中的赛车 demo 很直观。旗帜资产先在 Reality Composer 里被加上 tap behavior。随后它被导出为 USDZ,放进 Houdini 组成赛车动画。Houdini 当时还不理解 behavior schema,所以不会播放旗帜交互;但它不会丢掉这段信息。资产回到 Reality Composer 后,原来的点击行为又能触发。USDZ 从“最终交付格式”变成了可以反复进出工具链的工作文件。

后半段转向 schema 本身。Apple 没有只介绍一个导出按钮,而是展示这些 AR 信息在 USDA 文本中如何组织:scene library 用 kind = "sceneLibrary" 放多个 scene;anchoring 用 applied schema 挂到 prim;behavior 用 trigger 和 action 关系描述交互;physics 用 collider、rigid body、material 和 gravity 描述模拟;audio 和 3D text 则用新的 prim 类型进入 USD 场景。


详细内容

1. Reality Composer 导出 USDZ 后,DCC 循环不会切断 AR 信息

03:31)演讲先给出新工作流:Reality Converter 把 DCC 资产转为 USDZ,Reality Composer 加上交互、物理和锚定,再导出 USDZ,之后可以继续进入支持 USDZ 的 DCC。关键变化是导出目标从 Reality File 扩展到 USDZ,资产不必停在一个只能预览或交付的终点。

关键点:

  • Houdini、Maya、Unity、Unreal Engine、Adobe Aero 等 DCC 已经在支持 USD 导入或导出。
  • Reality Converter 负责把外部资产带入 Apple 的 USDZ 工作流。
  • Reality Composer 是 AR 语义的编辑点,可以添加交互、物理和锚定。
  • USDZ 导出是 2020 年新增能力,让 Reality Composer 产物可以继续被 DCC 编辑。
  • RealityKit app 是最终使用位置,演讲者在 demo 结尾把内容导入 RealityKit 应用并准备发布。

07:44)demo 里,Houdini 不理解 behavior schema,所以不会播放旗帜行为。但行为仍留在 USDZ 内。文件回到 Reality Composer 或 RealityKit 应用后,这些行为会重新出现。

关键点:

  • 旗帜资产在 Reality Composer 中已有 tap behavior,会执行行为并显示额外内容。
  • Houdini 不理解 behavior schema,但仍能摆放资产并导出场景。
  • 新 schema 的兼容性目标是让未知 AR 信息保留在 USDZ 内。
  • 文件回到 Reality Composer 后,旗帜原来的点击行为仍能触发。

2. Scene library 让一个 USD 文件包含多个可加载场景

11:29)Reality Composer 项目可以有多个 scene。USD 里的表达方式是把根 prim 标成 sceneLibrary,再把每个 scene 放到它下面。def 表示 active scene,over 表示 inactive scene。RealityKit 可以按 scene name 加载其中一个场景。

def Xform "Root" (
    kind = "sceneLibrary"
)
{
    def Cube "MyCubeScene" (
        sceneName = "My Cube Scene"
    )
    {
        ...
    }

    over Sphere "MySphereScene" (
        sceneName = "My Sphere Scene"
    )
    {
        ...
    }
}

关键点:

  • kind = "sceneLibrary" 把根节点声明为场景库。
  • def Cube "MyCubeScene" 定义一个 active scene,旧工具仍能看到这个活动场景。
  • over Sphere "MySphereScene" 定义 inactive scene,用于保存在同一文件中但默认不显示的场景。
  • sceneName 是可读名称,RealityKit 可以像加载 Reality File scene 一样按名称加载。
  • 演讲明确限制了当前支持范围:RealityKit、AR Quick Look 和 Reality Composer 只支持单个 active scene,暂不支持 nested scenes。

3. Anchoring schema 把真实世界锚点写到 prim 上

13:00)anchoring(锚定)描述内容应该出现在真实世界的哪个参照物上。schema 支持 horizontal plane、vertical plane、image 和 face 四种类型。AR object 与 geolocation anchors 当时尚未支持。

def Cube "ImageAnchoredCube" (
    prepend apiSchemas = [ "Preliminary_AnchoringAPI" ]
)
{
    uniform token preliminary:anchoring:type = "image"
    rel preliminary:imageAnchoring:referenceImage = <ImageReference>

    def Preliminary_ReferenceImage "ImageReference"
    {
        uniform asset image = @image.png@
        uniform double physicalWidth = 12
    }

    ...
}

关键点:

  • prepend apiSchemas 把 anchoring applied schema 挂到 cube prim。
  • preliminary:anchoring:type = "image" 表示这个 cube 对齐图像锚点。
  • referenceImage 关系指向同一 USD 中的 image reference prim。
  • image = @image.png@ 引用 JPG 或 PNG 图像,符合 USDZ 规格。
  • physicalWidth = 12 用厘米定义真实图像宽度,避免 DCC 改单位后影响锚点尺寸。

4. Behavior schema 用 trigger 与 action 关系描述交互

14:13)Reality Composer 的行为由 trigger(触发器)和 action(动作)组成。USD schema 里,Preliminary_Behavior 持有 trigger 与 action 的关系数组;trigger 和 action 再用 info:id 等属性说明类型。

def Preliminary_Behavior "TapAndBounce"
{
    rel triggers = [ <Tap> ]
    rel actions = [ <Bounce> ]

    def Preliminary_Trigger "Tap"
    {
        uniform token info:id = "tap"
        rel affectedObjects = [ </Cube> ]
    }

    def Preliminary_Action "Bounce"
    {
        uniform token info:id = "emphasize"
        uniform token motionType = "bounce"
        rel affectedObjects = [ </Cube> ]
    }

    ...
}

关键点:

  • rel triggers 指向会启动行为的 trigger prim。
  • rel actions 指向触发后执行的 action prim。
  • info:id = "tap" 把 trigger 标识为 tap trigger。
  • affectedObjects = [ </Cube> ] 指出被观察或被影响的对象。
  • info:id = "emphasize"motionType = "bounce" 组合出 Reality Composer 中的 bounce 效果。

16:18)同一个 behavior 可以有多个 trigger 和多个 action。多个 trigger 满足任意一个就会触发动作;多个 action 按顺序执行。action data schema 还支持 group action,用来表达串行或并行的动作组。

def Preliminary_Behavior "TapOrGetCloseAndBounceJiggleAndFlip"
{
    rel triggers = [ <Tap>, <Proximity> ]
    rel actions = [ <Bounce>, <Jiggle>, <Flip> ]

    ...
}

关键点:

  • <Tap><Proximity> 是两个触发入口,满足其中一个即可调用动作。
  • <Bounce><Jiggle><Flip> 会串行执行。
  • behavior 会随 scene 自动加载;如果在多 scene USD 中定义,会被限定在所在 scene 内。

5. Physics schema 覆盖碰撞体、刚体、材质、地面和重力

17:02)physics schema 用于描述 Reality Composer 中的物理模拟。演讲分几步建了一个木球:先给 prim 应用 collider 与 rigid body,再给材质应用 physics material,接着给 scene 增加 infinite collider plane,最后定义 gravity。

def Sphere "WoodenBall" (
    prepend apiSchemas = [ "Preliminary_PhysicsColliderAPI",
                           "Preliminary_PhysicsRigidBodyAPI" ]
)
{
    rel preliminary:physics:collider:convexShape = </WoodenBall>
    double preliminary:physics:rigidBody:mass = 10.0
}

关键点:

  • Preliminary_PhysicsColliderAPI 让这个 sphere 参与碰撞检测。
  • Preliminary_PhysicsRigidBodyAPI 让对象参与刚体模拟。
  • convexShape = </WoodenBall> 使用对象自身几何作为凸碰撞体。
  • mass = 10.0 用千克记录质量,减少 composition 或 DCC 单位变化造成的误差。
def Material "Wood" (
    prepend apiSchemas = ["Preliminary_PhysicsMaterialAPI"]
)
{
    double preliminary:physics:material:restitution = 0.603
    double preliminary:physics:material:friction:static = 0.375
    double preliminary:physics:material:friction:dynamic = 0.375
}

def Sphere "WoodenBall" (
    prepend apiSchemas = [ "Preliminary_PhysicsColliderAPI",
                           "Preliminary_PhysicsRigidBodyAPI" ]
)
{
    rel preliminary:physics:collider:convexShape = </WoodenBall>
    double preliminary:physics:rigidBody:mass = 10.0
    rel material:binding = </Wood>
}

关键点:

  • Preliminary_PhysicsMaterialAPI 被应用到已有 Material prim 上。
  • restitution 描述反弹特性。
  • friction:staticfriction:dynamic 描述静摩擦和动摩擦。
  • material:binding = </Wood> 把物理材质绑定到球体。

18:40)地面用 infinite collider plane 表示,并通过 custom data 标记为 scene ground plane。演讲说明,这样旧版 USD 也能打开文件。

def Xform "MyScene" (
    prepend apiSchemas = ["Preliminary_PhysicsColliderAPI"]
)
{
    def Preliminary_InfiniteColliderPlane "groundPlane" (
        customData = {
            bool preliminary_isSceneGroundPlane = 1
        }
    ) {
        point3d position = (0, 0, -2)
        vector3d normal = (0, 1, 0)
        rel preliminary:physics:collider:convexShape = </MyScene/groundPlane>
    }
    rel material:binding = </Wood>
}

关键点:

  • Preliminary_InfiniteColliderPlane 定义无限碰撞平面。
  • preliminary_isSceneGroundPlane = 1 把它标成场景地面。
  • positionnormal 指定平面位置和法线。
  • material:binding = </Wood> 复用前面定义的 wood physics material。

19:08)重力用 scene 内的 gravitational force prim 表示。演讲建议一个 scene 只定义一个 gravitational force。

def Preliminary_PhysicsGravitationalForce "MoonsGravity"
{
    vector3d physics:gravitationalForce:acceleration = (0, -1.625, 0)
}

关键点:

  • Preliminary_PhysicsGravitationalForce 定义 scene 中的重力。
  • (0, -1.625, 0) 是演讲中使用的月球重力示例。
  • 演讲建议每个 scene 只定义一个 gravitational force。

6. Spatial audio、3D text 与播放元数据进入 USD

19:35)audio schema 与 behavior schema 分开。行为可以触发 play audio action;audio schema 本身负责把音频内容嵌入 USD,并指定播放模式、开始时间、media offset、音量和空间位置。

def SpatialAudio "HorseNeigh"
{
    uniform asset filePath        = @Horse.m4a@
    uniform token auralMode       = "spatial"
    uniform timeCode startTime    =  65.0
    uniform double mediaOffset    =  0.33333333333
    double3 xformOp:translate = (0, 0.5, 0.1)
    uniform token[] xformOpOrder = ["xformOp:translate"]
}

关键点:

  • SpatialAudio 是新的 prim type,用来描述 USD 中的音频。
  • filePath = @Horse.m4a@ 引用音频文件。
  • auralMode = "spatial" 表示声音从特定 transform 发出。
  • startTimemediaOffset 控制音频在时间轴上的开始点和素材内部偏移。
  • xformOp:translate 把声音放到空间位置,演讲中的例子是从马嘴附近发出。

21:26)3D text schema 把 Reality Composer 的文字内容、字体、换行和对齐信息写入 USD。

def Preliminary_Text "heading"
{
    string content = "#WWDC20"
    string[] font = [ "Helvetica", "Arial" ]
    token wrapMode = "singleLine"
    token horizontalAlignment = "center"
    token verticalAlignment = "baseline"
}

关键点:

  • content = "#WWDC20" 是演讲中的文字内容示例。
  • font 支持主字体与 fallback font。
  • wrapMode 控制单行或换行。
  • horizontalAlignmentverticalAlignment 控制文字对齐。

22:46)播放元数据告诉 viewer 动画与音频是否循环、是否自动播放。演讲提到,Reality Composer 导出的内容默认关闭 autoplay,方便由 behavior 显式驱动。

#usda 1.0
(
    endTimeCode = 300
    startTimeCode = 1
    timeCodesPerSecond = 30
    playbackMode = "loop"
    autoPlay = false
)

def Xform “AnimatedCube"
{
    ...
}

关键点:

  • playbackMode = "loop" 提示 viewer 循环播放动画。
  • autoPlay = false 表示加载时不自动开始。
  • timeCodesPerSecond = 30 定义时间码速度,配合 stage animation 与 audio 使用。

23:08)scene understanding metadata 允许场景内容和 LiDAR 生成的真实环境进行物理交互。

def Xform "Root" (
    kind = "sceneLibrary"
)
{
    def Xform "MyScene" (
        sceneName = "My Scene"
        preliminary_collidesWithEnvironment = true
    )
    {
        def Xform "DigitalBug"
        {
            ...
        }
    }
}

关键点:

  • preliminary_collidesWithEnvironment = true 标记这个 scene 的内容会与 scene understanding 生成的真实环境交互。
  • 这个能力对应 RealityKit 与 ARKit 在带 LiDAR Scanner 的 iPad Pro 上提供的 scene understanding。
  • metadata 放在 scene 上,表达的是 scene 级别的环境交互意图。

核心启发

1. 做一个可往返编辑的 AR 资产验收工具

  • 做什么:导入美术给出的 USDZ,检查是否包含 scene library、anchoring、behavior、physics、audio 和 playback metadata,并生成验收报告。
  • 为什么值得做:这场 session 的核心是 AR 信息要在 DCC 往返中保留。验收工具可以在资产进入应用前发现 behavior 丢失、锚点缺失或 autoplay 配置错误。
  • 怎么开始:用 USD 工具读取 USDA/USDZ,先检查 kind = "sceneLibrary"Preliminary_AnchoringAPIPreliminary_BehaviorSpatialAudioautoPlay 等字段,再把结果展示给美术和开发团队。

2. 做一套 Reality Composer 与 Houdini 的赛车模板

  • 做什么:把车辆、道路、旗帜、音频和 tap behavior 做成一个可复用模板,让艺术家只替换模型和动画曲线。
  • 为什么值得做:session demo 已经证明,Reality Composer 行为可以穿过 Houdini 往返后继续生效。这类模板适合营销页、展厅、教育演示中的短 AR 动画。
  • 怎么开始:先在 Reality Composer 中给关键对象添加 tap behavior 和 play animation action,再导出 USDZ 到 Houdini 编排大动画,最后回到 Reality Composer 添加 spatial audio 与最终触发逻辑。

3. 做图片锚定的产品说明卡

  • 做什么:扫描产品包装或说明书图片后,在上方显示 3D 文本、模型分解动画和空间音效。
  • 为什么值得做:anchoring schema 支持 image anchoring,3D text schema 支持文字,spatial audio schema 支持声音位置。三者组合后,可以把静态纸面变成 AR 说明书。
  • 怎么开始:在 USD 中给模型 prim 应用 Preliminary_AnchoringAPI,把 preliminary:anchoring:type 设为 image,再添加 Preliminary_TextSpatialAudio prim。图像宽度用厘米填入 physicalWidth

4. 做一个带物理材质的 AR 教学实验

  • 做什么:让学生在桌面上比较木球、橡胶球、塑料球在不同重力下的弹跳和摩擦。
  • 为什么值得做:physics schema 覆盖 rigid body、collider、physics material、ground plane 和 gravity。它适合把抽象物理参数转成可观察的 AR 场景。
  • 怎么开始:给球体应用 collider 与 rigid body schema,给不同 material 设置 restitutionfriction,再用 Preliminary_PhysicsGravitationalForce 切换地球、月球等重力参数。

5. 做一套 AR 动画播放器的内容规范

  • 做什么:为应用内 USDZ 动画规定统一的 playbackModeautoPlay、音频偏移和 scene understanding 规则。
  • 为什么值得做:session 里提到 playback metadata 会提示 viewer 如何展示播放按钮和循环方式,Reality Composer 导出内容默认不 autoplay,方便用 behavior 驱动。
  • 怎么开始:在资产导出管线中检查 startTimeCodeendTimeCodetimeCodesPerSecondplaybackModeautoPlay。需要与真实环境碰撞的 scene,再加上 preliminary_collidesWithEnvironment = true

关联 Session

评论

GitHub Issues · utterances