Version: 2023.2
Example native audio plug-ins included in the SDK
Audio playlist randomization

空间音响 SDK

空间音响 SDK 提供了相应的控制,用于更改您的应用程序将音频从音频源传输到周围空间的方式。它是原生音频插件 SDK 的扩展。

音频源的内置平移是一种简单的空间形式。它获取音频源并根据音频监听器与音频源之间的距离和角度来调节左耳和右耳效应的增益。在水平面上为玩家提供了简洁的方向提示。

Unity 空间音响 SDK 及示例实现

为了提供处理音频空间化的灵活性和支持,Unity 提供了一个开放接口,即空间音响 SDK,作为原生音频插件 SDK 之上的扩展。您可以将 Unity 中的标准平移器替换为更高级的平移器,并提供有关计算所需的音频源和监听器的重要元数据的访问权。

有关本机空间音响音频插件的示例,请参阅 Unity 原生音频插件 SDK。此插件仅支持直接的相关传输函数 (Head-Related Transfer Function, HRTF),目的仅限于提供示例。

您可以使用插件随附一个简单的混响,将音频数据从空间音响插件路由到混响插件。HRTF 过滤基于 KEMAR 数据集的修改版本。有关 KEMAR 数据集的更多信息,请参阅麻省理工学院媒体实验室的文档和测量文件

如果您想探索从人类受试者获得的数据集,请参阅 IRCAM 的数据集

初始化 Unity 空间音响

Unity 在音频源解码音频数据后直接应用空间音响效果。这会产生一个音频数据流,其中每个源都有自己单独的效果实例。Unity 仅处理来自该源的音频及其相应的效果实例。

要使插件作为空间音响工作,需要在效果的描述位字段中设置一个标志:

definition.flags |= UnityAudioEffectDefinitionFlags_IsSpatializer;

如果您设置了 UnityAudioEffectDefinitionFlags_IsSpatializer 标志,Unity 会在插件扫描阶段将插件识别为空间音响。在 Unity 创建此插件的实例时会为 UnityAudioEffectState 结构的 spatializerdata 成员分配 UnityAudioSpatializerData 结构。

要在项目中使用空间音响,请在项目设置中进行选择(菜单:Edit > Project Settings > Audio)。

空间音响插件选择器
空间音响插件选择器

然后,在要用于空间音响插件的音频源的 Inspector 窗口中,启用 Spatialize

音频源上的 Spatializer 复选框
音频源上的 Spatializer 复选框

您也可以使用 AudioSource.spatialize 属性通过 C# 脚本为音频源启用空间音响。

在具有大量音频的游戏中,您可希望仅对附近的声音启用空间音响,而对远处的声音使用传统方案,从而减少空间音响效果的混合线程上的 CPU 负载。

如果您希望 Unity 将空间数据传递给非空间音响的音频混音器插件,可以在描述位字段中使用以下标志:

definition.flags |= UnityAudioEffectDefinitionFlags_NeedsSpatializerData;

如果插件使用 UnityAudioEffectDefinitionFlags_NeedsSpatializerData 标志初始化,该插件将接受 UnityAudioSpatializerData 结构,但仅 listenermatrix 字段有效。有关 UnityAudioSpatializerData 的更多信息,请参阅空间音响效果元数据部分

要阻止 Unity 替空间音响插件应用距离衰减,请使用以下标志:

definition.flags |= UnityAudioEffectDefinitionFlags_AppliesDistanceAttenuation;

UnityAudioEffectDefinitionFlags_AppliesDistanceAttenuation 标志告知 Unity 将由空间音响来应用距离衰减。有关距离衰减的更多信息,请参阅衰减曲线和可听度部分。

空间音响效果元数据

与在混合声音上运行的其他 Unity 音频效果不同,Unity 在音频源解码音频数据后直接应用空间音响。空间音响效果的每个实例都有一个自身的 UnityAudioSpatializerData 实例,该实例主要与音频源的数据相关联。

struct UnityAudioSpatializerData
{
    float listenermatrix[16];   // 此矩阵用于将音频源位置变换为监听器的本地空间
    float sourcematrix[16];     // 音频源的变换矩阵
    float spatialblend;         // 距离控制的空间混合
    float reverbzonemix;        // 音频源上的混响区混音级别参数 
                                // (和曲线)
    float spread;               // 音频源的传播参数(0 到 360 度)
    float stereopan;            // 音频源的立体声平移参数(-1:全左,1:全右)
                                // 空间音响插件可以重写距离衰减
                                // 以便影响语音优先级(将此回调保留为 NULL 可使用 
                                // 内置音频源衰减曲线)
    UnityAudioEffect_DistanceAttenuationCallback distanceattenuationcallback;
    float minDistance;          // 音频源的最小距离。
                                // 该值可用于确定何时应用近场效果。
    float maxDistance;          // 音频源的最大距离, 
                                // 或监听器听不见音频的距离。
    
};

该结构包含的字段对应于 Inspector 中音频源组件的属性:Spatial BlendReverb Zone MixSpreadStereo PanMinimum DistanceMaximum Distance

UnityAudioSpatializerData 结构包含用于音频监听器和音频源的完整 4x4 变换矩阵。已计算监听器矩阵的逆矩阵,因此可将两个矩阵相乘以获得相对方向矢量。监听器矩阵始终是正交的,因此可以快速计算逆矩阵。

Unity 的音频系统仅将原始源声音作为立体声信号提供。即使源是单声道或多声道,信号也是立体声的,并且 Unity 根据需要使用向上或向下混合。

矩阵协议

sourcematrix 字段包含与音频源相关联的变换矩阵的副本。对于游戏对象上未旋转的默认音频源,这是一个转换矩阵,在元素 12、13 和 14 位置处编码。

listenermatrix 字段包含音频监听器的变换矩阵的逆矩阵。

您可以确定从音频监听器到音频源的方向矢量,如下所示,其中 L 是 listenermatrix,S 是sourcematrix

float dir_x = L[0] * S[12] + L[4] * S[13] + L[ 8] * S[14] + L[12];
float dir_y = L[1] * S[12] + L[5] * S[13] + L[ 9] * S[14] + L[13];
float dir_z = L[2] * S[12] + L[6] * S[13] + L[10] * S[14] + L[14];

(L[12], L[13], L[14]) 中的位置实际上是您在 Unity 的 Inspector 窗口中看到的摄像机矩阵的负值。如果摄像机也已旋转,您还需要首先撤消旋转的效果。要对变换-旋转矩阵进行求逆,转置 L 的左上角 3x3 旋转矩阵,并按如下所示来计算位置:

float listenerpos_x = -(L[0] * L[12] + L[ 1] * L[13] + L[ 2] * L[14]);
float listenerpos_y = -(L[4] * L[12] + L[ 5] * L[13] + L[ 6] * L[14]);
float listenerpos_z = -(L[8] * L[12] + L[ 9] * L[13] + L[10] * L[14]);

有关空间音响插件代码中的示例,请参阅 Plugin_Spatializer.cpp 文件 中的第 215 行。

衰减曲线和可听度

除非您按照初始化 Unity 空间音响一节所述指定了 UnityAudioEffectDefinitionFlags_AppliesDistanceAttenuation 标志,Unity 音频系统仍将控制距离衰减。Unity 在声音进入空间化阶段之前对其应用距离衰减,并让音频系统知道音频源的近似可听度。音频系统根据重要性使用近似可听度进行声音的动态虚拟化,以匹配用户定义的 Max Real Voices 限制。

Unity 并不从实际信号水平测量中获得可听度信息,而是对应于我们从距离控制衰减曲线、Volume 属性和混音器应用的衰减中读取的值的组合结果。

您可以直接覆盖衰减曲线,或者使用通过音频源的曲线计算出的值作为修改基础。要覆盖该值,使用 UnityAudioSpatializerData 结构中回调,如下所示:

typedef UNITY_AUDIODSP_RESULT (UNITY_AUDIODSP_CALLBACK* UnityAudioEffect_DistanceAttenuationCallback)(
    UnityAudioEffectState* state,
    float distanceIn,
    float attenuationIn,
    float* attenuationOut);

您也可以使用一个简单的自定义对数曲线,如下所示:

UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK SimpleLogAttenuation(
    UnityAudioEffectState* state,
    float distanceIn,
    float attenuationIn,
    float* attenuationOut)
{
    const float rollOffScale = 1.0f; // 类似于音频项目设置
    *attenuationOut = 1.0f / max(1.0f, rollOffScale * distanceIn);
    return UNITY_AUDIODSP_OK;
}

使用来自 Unity API 的 C# 脚本

音频源中还有两个方法,允许从空间音响效果中设置和获取参数:SetSpatializerFloatGetSpatializerFloat。这些方法的工作方式类似于通用原生音频插件接口中 SetFloatParameterGetFloatParameter 方法。但是,SetSpatializerFloatGetSpatializerFloat 接受必须设置或读取的参数的索引,而 SetFloatParameterGetFloatParameter 按名称引用这些参数。

在 Unity 的音频源的 Inspector 窗口中,布尔属性 AudioSource.spatializer 链接到 Spatialize 选项。该属性控制 Unity 如何根据音频项目设置中选择的插件来实例化和取消分配空间音响效果。

如果空间音响效果的实例化非常耗费资源(内存或项目中的其他资源),从预设的“池”中分配空间化效果可能是有效的,这样 Unity 就不必在每次需要时创建一个空间音响的新实例。如果您保持 Unity 插件接口绑定非常轻量级并动态分配音响效果,可以避免项目中出现丢帧或其他性能问题。

示例插件的已知限制

由于使用了快速卷积算法,快速移动会导致一些拉链瑕疵,这些瑕疵可以通过使用重叠保存卷积或交叉淡化缓冲来消除。

该代码也不支持倾斜监听器的头部,无论监听器是直接连接到玩家角色,还是位于其他地方的摄像机。

Example native audio plug-ins included in the SDK
Audio playlist randomization