Dive into RealityKit 2
Augmented Reality 进阶 28m

深入 RealityKit 2

Dive into RealityKit 2

2021年6月10日

在 Apple 官方观看视频

一句话判断

RealityKit 2 终于不是玩具了 —— 自定义材质、程序化网格生成、角色动画系统这三个功能补齐之后,Unity 开发者总算有理由认真看一眼这个框架了。

这场 Session 讲了什么

RealityKit 2 是一次重大的功能扩展,把 RealityKit 从一个”只能加载 USDZ 模型并放在平面上”的简单框架,提升到了可以构建完整 AR 应用的水平。

核心更新包括:自定义材质系统(Custom Material),开发者可以编写 Metal shader 来控制渲染效果;程序化网格生成(MeshDescriptor),用代码创建几何体而不依赖预制的 3D 模型文件;角色动画(Animation Library)的增强,支持动画混合、动画事件回调和程序化动画。此外还有物理模拟的改进、空间音频的集成、以及对 Entity Component System(ECS)架构的更多控制。

Session 用一个示例 AR 游戏贯穿全程,展示了如何用新 API 构建一个有碰撞检测、自定义视觉效果和音效的交互体验。

值得深挖的点

Custom Material 的 shader 架构。RealityKit 2 的 CustomMaterial 允许你写 Surface Shader 和 Geometry Modifier。Surface Shader 控制每个像素的颜色输出,Geometry Modifier 可以在 GPU 端修改顶点位置(比如做波浪变形)。这和 Unity 的 Shader Graph 概念类似,但你需要直接写 Metal 代码,没有可视化编辑器。shader 代码通过 CustomMaterialsurfaceShader 属性注入,支持传递自定义参数。

MeshDescriptor 的程序化建模MeshDescriptor 让你用代码定义顶点、法线、纹理坐标和索引,直接生成 MeshResource。这对需要动态生成几何体的场景(如数据可视化、动态地形)非常有用。性能方面,MeshResource 可以在后台线程生成,不会阻塞渲染。但生成的网格不支持实时修改顶点(不支持 morph target),要变形还是得依赖 Geometry Modifier shader。

代码片段

程序化创建网格

import RealityKit

func createCustomMesh() -> ModelEntity {
    // 创建一个简单的立方体网格
    var descriptor = MeshDescriptor()
    let halfSize: Float = 0.05
    // 定义立方体的 8 个顶点
    let positions: [SIMD3<Float>] = [
        [-halfSize, -halfSize, -halfSize],
        [ halfSize, -halfSize, -halfSize],
        [ halfSize,  halfSize, -halfSize],
        [-halfSize,  halfSize, -halfSize],
        [-halfSize, -halfSize,  halfSize],
        [ halfSize, -halfSize,  halfSize],
        [ halfSize,  halfSize,  halfSize],
        [-halfSize,  halfSize,  halfSize],
    ]
    descriptor.positions = MeshBuffer(positions)
    // 定义三角面片索引(6 个面,每个面 2 个三角形)
    descriptor.primitives = .triangles([
        0,1,2, 0,2,3, // 前
        4,6,5, 4,7,6, // 后
        // ... 其他面
    ])
    let meshResource = try! MeshResource.generate(from: [descriptor])
    let material = SimpleMaterial(color: .blue, isMetallic: true)
    return ModelEntity(mesh: meshResource, materials: [material])
}

使用自定义材质和 Shader

import RealityKit

func createCustomMaterial() -> CustomMaterial {
    // 加载 Metal shader 函数
    let surfaceShader = CustomMaterial.SurfaceShader(
        name: "hologramSurface",
        library: try! CustomMaterial.DefaultLibrary()
    )
    var material = CustomMaterial(
        surfaceShader: surfaceShader,
        lightingModel: .lit
    )
    // 传递自定义参数给 shader
    material.customParameter = SIMD4<Float>(0.5, 0.8, 1.0, 1.0)
    return material
}

动画播放和混合

import RealityKit

func playAnimation(on entity: Entity) {
    // 加载带动画的模型
    guard let animation = entity.availableAnimations.first else { return }
    // 创建循环播放的动画
    let loopingAnimation = animation.repeat(duration: .infinity)
    // 播放动画并持有控制器引用
    let controller = entity.playAnimation(loopingAnimation)
    // 在 2 秒后淡出停止
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        controller.stop()
    }
}

最佳实践

  1. Custom Material 的 shader 尽量保持简单。RealityKit 不像 Unity 有完整的 shader 调试工具,shader 编译错误只会在运行时出现。先在 Xcode 的 Metal shader playground 中验证逻辑,再搬到 RealityKit。
  2. 程序化网格适合静态几何体,动态内容还是用 Entity 层的 transform 动画。MeshResource 生成后不支持顶点级别的实时修改,需要形变效果请用 Geometry Modifier。
  3. 动画混合用 tryAnimationblend 方法。RealityKit 2 支持多个动画之间的平滑过渡,设置合适的 blend duration(建议 0.3 秒),避免动画跳变。

还有什么值得关注

  • RealityKit 2 的 PhysicsBodyComponent 支持了更多物理形状(Convex、Decomposed),碰撞检测更精确。
  • AudioComponent 现在支持空间音频(Spatial Audio),声音会根据 Entity 和摄像头的相对位置自动调整。
  • SynchronizationComponent 让 Entity 状态可以通过 MultipeerConnectivity 自动同步,简化多人 AR 开发。
WWDC 2021