Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE)
Audio & Video 高级 22m

探索 PHASE:基于物理几何的空间音频引擎

Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE)

2021年6月10日

在 Apple 官方观看视频

一句话判断

PHASE 是苹果给游戏和 AR 开发者准备的”穷人版 Wwise” —— 几何感知的空间音频、材质过滤、距离衰减全部内置,但和 AVFoundation 完全不互通,是一个独立的音频世界。

这场 Session 讲了什么

PHASE(Physical Audio Spatialization Engine)是苹果在 iOS 15 / macOS 12 中引入的全新音频引擎,专为需要物理级空间音频的游戏和 AR 体验设计。

核心概念是把声音源(Sound Event)放置在 3D 空间中,引擎会根据听者(Listener)的位置、朝向以及场景中的几何体(墙壁、障碍物)自动计算声音的传播路径。这包括:距离衰减、遮挡过滤(Occlusion,声音被墙壁挡住会变闷)、材质吸收(不同材质表面吸收不同频段)以及多普勒效应。

Session 演示了如何用 PHASE API 定义声源、配置空间化参数、添加几何体作为遮挡物,以及如何在游戏循环中实时更新听者和声源的位置。

值得深挖的点

几何感知的实现机制。PHASE 不是简单地算距离,而是会做射线追踪(Ray Tracing)来判断声源和听者之间有没有障碍物。你需要在 PHASE Engine 中注册场景的几何体(PHASEGeometricSpreading),引擎会在每帧更新遮挡关系。这意味着你有声源遮挡,但忘了注册墙壁几何体,声音会直接穿墙。

材质过滤的声音设计。PHASE 支持给场景几何体关联材质(PHASEMaterial),不同材质对声音的吸收系数不同。混凝土墙会高频全部挡掉,木板只吸收部分频段。这不是简单的音量调节,而是真实的频率过滤(Low-pass filter),听感上很自然。材质参数需要你在代码中手动配置,苹果提供了几个预设。

代码片段

初始化 PHASE Engine 和声源

import PHASE

// 创建 PHASE 引擎
let engine = try! PHASEEngine()

// 定义一个声源
let soundAsset = try! engine.assetRegistry.addSoundAsset(
    fileName: "explosion.wav",
    identifier: "explosion"
)
// 创建空间化参数
let spatialMixer = PHASESpatialMixerDefinition()
spatialMixer.spatialMode = .channelBased  // 使用声道空间化

// 创建声音事件
let eventDefinition = PHASESoundEventNodeDefinition(
    soundAssetIdentifier: "explosion",
    mixerDefinition: spatialMixer
)

设置距离衰减和空间化

import PHASE

func configureSpatialization(for engine: PHASEEngine) {
    // 配置几何扩散参数
    let geometricSpreading = PHASEGeometricSpreadingParameters()
    // 基于反平方定律的距离衰减
    geometricSpreading.mode = .inverseSquareLaw
    // 设置参考距离(在这个距离内音量不衰减)
    geometricSpreading.fadeOutParameters = PHASEDistanceFadeOutParameters(
        cullDistance: 100.0,  // 超过 100 米直接静音
        cullSleepDistance: 80.0
    )
    // 应用到空间混音器
    let spatialDefinition = PHASESpatialMixerDefinition()
    spatialDefinition.geometricSpreadingParameters = geometricSpreading
}

实时更新声源位置

import PHASE

class GameAudioManager {
    let engine: PHASEEngine
    var soundSource: PHASESource?

    init() {
        engine = try! PHASEEngine()
        engine.start()
    }

    // 每帧更新声源位置(在游戏循环中调用)
    func updateSourcePosition(_ position: SIMD3<Float>) {
        // 更新 PHASE 声源的世界坐标
        soundSource?.transform = Transform(
            translation: position
        ).simdTransform
    }

    func updateListenerPosition(_ position: SIMD3<Float>, rotation: simd_quatf) {
        // 更新听者(通常是摄像头/玩家)的位置和朝向
        engine.defaultListener.transform = Transform(
            translation: position,
            rotation: rotation
        ).simdTransform
    }
}

最佳实践

  1. PHASE 和 AVAudioEngine 不要混用。它们是独立的音频管道,同时运行会争抢音频资源。如果 app 同时需要音乐播放和游戏音效,用 PHASE 管游戏音、AVPlayer 管音乐,但要测试后台音频中断的处理。
  2. 几何体注册要精简。射线追踪的计算量和几何体复杂度成正比。用简化的碰撞盒代替精确的 3D 网格作为 PHASE 遮挡体,每帧多省几毫秒。
  3. 声源数量控制在 16 个以内。PHASE 没有官方声源数量上限,但实际测试中超过 16 个活跃声源后,中低端设备会出现掉帧。

还有什么值得关注

  • PHASE 支持多普勒效应,移动的声源会自动产生频率偏移,适合赛车类游戏。
  • 引擎内置了 Ambisonics 声场渲染,可以配合 AirPods Pro 的空间音频使用。
  • PHASE 目前只在 Apple 平台可用,没有跨平台支持,如果游戏需要多平台发布要考虑替代方案。
WWDC 2021