三维音频渲染
3D Audio Rendering
3D 音频渲染引擎要尽可能可信地重现"玩家若真在游戏世界里会听到什么"。它的输入是世界里大量的 3D 声音,输出是少数几路扬声器声道;主要任务是合成、空间化(距离衰减 + 声像定位)、声学建模(混响、遮挡、衍射)、多普勒和混音。GEA 给出了恒功率声像律、聚焦角、混响区域交叉混合、遮挡/阻挡/排除的分析方法,以及顽皮狗《最后生还者》的随机传播建模和声音门户(GEA4 卷 II 15.4)。
总览与音频世界模型
音频引擎除了 3D 声音,还要播放不在世界里的 2D 声音:音乐、菜单音效、旁白、第一人称主角的声音等,它们在 3D 空间化之后直接混入扬声器。理想输出是 7.1 或 5.1,但必须支持立体声和耳机(卷 II 15.4)。主要任务(卷 II 15.4.1):
- 声音合成:回放预录片段或运行时程序化生成;
- 空间化:用距离衰减表达远近,用声像定位 (pan) 控制各扬声器的相对音量来表达方向;
- 声学建模:模拟早期反射、晚期混响和障碍物,部分引擎还模拟大气吸收和 HRTF;
- 多普勒频移;
- 混音:物理与审美共同决定所有 2D、3D 声音的相对音量。
"音频世界模型"由三部分组成(卷 II 15.4.2):
| 元素 | 内容 |
|---|---|
| 3D 声源 | 单声道信号 + 位置、速度、辐射模式(全向/锥形/平面)、作用范围 |
| 听者 | 世界里的"虚拟麦克风":位置、速度、朝向 |
| 环境模型 | 表面与物体的几何和属性,或各收听空间的声学属性 |
位置和辐射模式用于距离衰减;听者朝向定义计算方位角的参考系,方位角决定声像;相对速度用于多普勒;环境模型用于声学和遮挡。
距离衰减
每个声源标注衰减最小半径 (FO min, )(以内满音量)和衰减最大半径 (FO max, )(以外视为静音、可以忽略),两者之间平滑降到零。这也是控制同时渲染声源数的手段(卷 II 15.4.3.1)。
- 可以用线性斜坡;物理上更正确的是增益按 下降(声强 )。 永远不到零,可以把曲线下移使其在 处过零,或直接在 时截断为零(卷 II 15.4.3.2)。
- 为游戏改规则:《最后生还者》中按 衰减的对话在中等距离就听不清,而潜行时听清敌人闲聊既是战术信息又推动剧情。顽皮狗改用"近处慢、中段快、远处又慢"的衰减曲线,并按游戏"紧张度"(敌人未察觉/搜索/交战)在运行时调整;还可以开一个"增色"混响,让对白在直达路径被完全挡住时也能绕过墙角。GEA 的结论是:只要游戏需要就大胆作弊,"物理定律不会生气"(卷 II 15.4.3.3)。
- 大气衰减:给每个 3D 声音加一个低通滤波器,通带随距离增大向低频滑动(《最后生还者》系列的做法)(卷 II 15.4.3.4)。
原书问题(前后不一致):15.4.3.2 明确说增益应按 衰减、声强按 ,15.4.3.3 却说对白"按 规则"衰减太快。原文没有说明这里的 指声强还是被直接用作增益;若直接作用于增益,衰减会比物理正确的 更快(核对依据即书中 15.4.3.2 与 15.4.3.3 两段原文,以及 15.1.3.1 的 、)。
声像定位 (Pan)
只调各扬声器的幅值来制造声源的"幻象",叫幅度声像 (amplitude panning),也叫 IID 声像。名字来自早期立体声的"全景电位器 (pan pot)"(卷 II 15.4.4)。设想听者在扬声器圆的中心:立体声音箱约在 ±45°,耳机在 ±90°(半径小得多);7.1 只考虑 7 个主扬声器(LFE 不提供方位信息),5.1 去掉两个侧环绕即可。
算法:在听者局部空间求声源的方位角 (0 为正前方),找到两侧相邻扬声器 ,求比例
- 恒增益声像:,。总增益不变,但感知响度随功率(幅值平方)变化,居中时总功率只有 ,听起来变小(卷 II 15.4.4.1)。
原书问题:GEA 说声强和功率"随 SPL 的平方变化",又说居中时响度只有一半。第一句应为随声压幅值的平方变化;SPL 本身是分贝值,功率与它是指数关系而不是平方关系(见 15.1.2 中 )。第二句里总功率减半只是 −3 dB,而感知响度减半大约对应 −10 dB(响度单位 sone 的定义:响度级每增加 10 phon 响度加倍,见 Wikipedia "Sone")。所以准确说法是"功率减半,听起来明显变小",不是"响度减半"。
- 恒功率声像律 (constant power pan law):用正弦和余弦插值,使 对任意 成立;居中时两边都是 。对应混音师的 "3 dB 规则":同一声音平分到两个扬声器时,每个的增益比只用一个时低 3 dB,因为 dB(卷 II 15.4.4.2)。
原书问题(公式,已核对渲染页 p.473、p.471):GEA 写作 、。按上面 的定义,声源正好在扬声器 1 处时 ,此时 、,声音全部出现在另一只扬声器里,与恒增益版本 的方向相反。正确写法应为 、(对比书中两式推出)。另外 15.4.4 写立体声"the front and right speakers"位于 ±45°,应为左右两只前置扬声器(front left and right)。依据:两式在 处代入即可验证;图 15.29 的扬声器布局。
下图示意一个声源在两只扬声器之间平移时的处理流程。
flowchart LR P["声源世界位置"] --> L["变换到听者局部空间"] L --> AZ["方位角 θs"] AZ --> ADJ["找相邻扬声器 θ1 θ2"] ADJ --> B["β = 比例"] B --> G["恒功率增益 A1 A2"] G --> SPK["写入两路扬声器声道"]
余量 (headroom):声音从两只扬声器移到一只时,恒功率律要求单只的增益更大,若原本两只都在满功率就会过载。所以要整体压低最大增益,给最坏情况留出余量;混音时多个声音幅值相加,同样要留余量(卷 II 15.4.4.3)。
要不要用中置声道:电影里对白历来放在中置,音效平移到四周,顺便把对白和音效隔开,避免大音效吃掉余量。游戏里玩家转动视角时对白也要跟着转,所以对白通常参与声像定位;但这又让枪声能淹没对白。顽皮狗的折中是始终把一部分对白放在中置,另一部分随音效一起平移(卷 II 15.4.4.4)。
聚焦角 (focus):声源靠近甚至进入扬声器圆时不能再当点声源,否则经过听者时声音会从前置"跳"到后置。把声源在扬声器圆上的投影看成一段弧,所张的角叫聚焦角 (点声源 ),类比渲染方程推导中的立体角(见 渲染方程)。渲染时找出与弧相交或相邻的扬声器分配功率,例如弧内扬声器等功率、两端相邻扬声器少分一些形成渐变;无论怎么分,各扬声器增益平方和必须等于原增益平方(卷 II 15.4.4.5)。
垂直方向:立体声和环绕声的扬声器基本在一个水平面上。真正的"全向 (periphonic)"声场需要球形布局,Ambisonics 可以支持,GEA 说"目前没有任何主机支持";索尼为 PS4 的 Platinum 无线耳机提供了 3D 音频技术。
原书问题(内容过时):这段沿用了旧版文字。PS5(2020)内置 Tempest Engine 硬件 3D 音频,支持数百个同时声源,PS4 约 50 个(Wikipedia "PlayStation 5" 引 Digital Foundry 2020 年 3 月报道);Xbox Series X|S 也支持 Windows Sonic / Dolby Atmos 等空间音频。即使如此,游戏仍要支持平面 5.1/7.1。GEA 的办法是把所有声音投影到水平面,对投影落在扬声器圆附近或圆内的声音使用非零聚焦角:远处的高处声音和不高的声音渲染得几乎一样,从头顶经过时则铺开到多只扬声器;再配合距离衰减和随频率的大气吸收,就能提供足够的上下方位线索(卷 II 15.4.4.6)。延伸阅读包括 Pulkki 的 VBAP(向量基幅度声像)论文(书中误拼为 "Pukki")和 Griesinger 的声像实践论文(卷 II 15.4.4.7)。
传播、混响与声学
只有衰减、声像和多普勒还不够,空间感主要来自多路径到达的早期反射、晚期混响和 HRTF。传播建模方法分三类:几何分析(模拟声波实际路径)、基于感知的模型(把收听空间当 LTI 系统)、ad hoc 近似(数据和运算都少,实际游戏中最常用)(卷 II 15.4.5)。
LTI 建模(卷积混响):只要测得房间对某对"声源点-听者点"的冲激响应 ,湿声就是 (数学见 信号与线性时不变系统)。现实中录一下"咔哒"声就近似得到 ,但虚拟空间需要昂贵的模拟;要覆盖大量点对,数据量巨大;卷积本身也不便宜。硬件变强后越来越可行(Micah Taylor 等人有实时卷积混响演示),但多数游戏仍用近似方法(卷 II 15.4.5.1)。
混响区域:在世界里手工摆放区域,每个标注预延迟、衰减、密度、扩散度等混响参数;听者进入时切换,进瓷砖大厅加强回声,进小壁橱几乎去掉混响。最好在区域之间按"进入区域多深"做逐参数线性插值的交叉混合,例如门口设一个过渡带,正中间是 50/50(卷 II 15.4.5.2)。
遮挡 (occlusion)、阻挡 (obstruction) 与排除 (exclusion):区域只给出整间房一套参数,表达不了障碍物(例如房间中央的柱子挡住角落的声源)。物体影响声音传播有三种情况(卷 II 15.4.5.3):
| 情况 | 直达路径 | 间接路径 | 效果 |
|---|---|---|---|
| 遮挡 | 不通 | 不通 | 干声、湿声都衰减或发闷,或完全听不到(薄墙薄门后仍可能听到) |
| 阻挡 | 不通 | 通 | 干声没有或很闷;湿声因路径更长更多反射也可能变化(如声源绕到车或柱子后) |
| 排除 | 通 | 受损 | 干声不变,湿声衰减、发闷,窄缝时完全没有(如经门窗传入) |
- 直达路径:从听者向声源做一次碰撞查询射线检测即可。要模拟穿墙,就在每个击中点查询材质吸收多少能量,有剩余就从障碍物另一侧继续投射,按剩余能量衰减干声增益。
- 间接路径:理想做法是搜索(如 A*)所有可行路径及其衰减,但太耗 CPU 和内存。近似规则:声源和听者在同一混响区域内就假设间接路径存在,不在同一区域就假设被遮挡;再结合直达射线的结果,即可区分自由、遮挡、阻挡、排除四种状态。
- 衍射:声波会绕过拐角和窄缝传播,只要直达路径与绕行路径的角度差不太大,就能像有直达路径一样听到。大多数碰撞引擎不支持曲线追踪,可以在直达射线周围用几段折线射线近似"弯曲"射线(例如 1 条直达 + 2 条各由两段组成的弯曲路径,共 5 次投射);直达射线被挡而弯曲射线可达,就说明听者在拐角的"衍射区"内,按未遮挡处理。
- 应用结果:根据直达和间接路径被挡的程度分别衰减干声和湿声,再根据路径信息加减混响。每个游戏需求不同,只能反复试验。
- 平滑过渡:状态切换(如从自由变为阻挡)时音色和响度会"跳变"。加迟滞 (hysteresis) 并在延迟窗口内交叉混合可以缓解,但延迟可能被察觉。顽皮狗高级音频程序员 Jonathan Lanier 为《神秘海域》和《最后生还者》系列发明了随机传播建模 (stochastic propagation modeling):每帧向每个声源投射一批直达和间接射线,跨多帧累计命中结果,得到干声和湿声被遮挡程度的概率模型,从而在完全阻挡和完全自由之间平滑过渡。
《最后生还者》的声音门户:为了让走廊里敌人的说话声从门口传来,而不是"穿墙"直线传来,顽皮狗用了由房间和门户两类区域组成的连通网络,连通关系由音效设计师摆放区域时提供。声源和听者在同一房间时,用《神秘海域》的遮挡/阻挡/排除分析;声源所在房间通过门户直接连到听者房间时,把声音当作位于门户区域中播放(一个"假声源")。实践中只需要在房间连通图里走"一跳"就覆盖了游戏中所有实际情况(卷 II 15.4.5.4)。这与图形学里的门户可见性思路相似,见 遮挡剔除。延伸阅读:育碧 Jean-François Guay 的实时声音传播、GDC 2003 Menshikov 的演讲、Jake Simpson 的《3D Sound in Games》(卷 II 15.4.5.5)。
下图示意 GEA 描述的声学分析在每个声源上的判定顺序(门户 + 遮挡分析的组合是对 15.4.5.3–15.4.5.4 的归纳)。
flowchart TD
S["声源"] --> R{"与听者同一房间?"}
R -->|"是"| D["直达射线 + 区域规则判定间接路径"]
D --> ST["自由 / 遮挡 / 阻挡 / 排除"]
ST --> M["分别衰减干声与湿声 调整混响"]
R -->|"否 但经门户相邻"| PO["在门户区域放假声源播放"]
R -->|"更远"| X["按遮挡处理"]多普勒频移
多普勒取决于相对速度 。最简单的近似是对信号做时间缩放(加快播放音调就升高,即"花栗鼠效应"),数字信号可以用采样率转换实现;但加快或放慢本身可能被听出来。理想做法是不改时间轴的变调 (pitch shift),例如相位声码器 (phase vocoder) 或时域谐波缩放 (time domain harmonic scaling)。这类技术反过来也能做到不改音高的变速(卷 II 15.4.6)。
注:GEA 说时间缩放"严格来说不正确"。从物理上看,匀速运动声源在听者处收到的信号本来就是原信号的时间缩放(再加传播延迟),时长也确实被压缩或拉伸,所以重采样或可变延迟线才是物理模型(见 J. O. Smith《Physical Audio Signal Processing》"Doppler Simulation via Delay Lines",CCRMA)。不改时长的变调是出于游戏需要(例如声音必须与动画、事件对齐),不是物理上更正确。公式与符号约定见 声音的物理与感知。
与 UE5 的对应
UE5 的 Sound Attenuation 有内区/外区和多种衰减函数、Non-Spatialized Radius(贴近大声源时过渡为非空间化,与 GEA 的聚焦角要解决的是同一个问题,这是对比归纳),见 音频系统与 MetaSounds。
出处
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 15 章 15.4 节