为方便开发者调试和接入腾讯云游戏多媒体引擎产品 API,本文向您介绍游戏多媒体引擎 3D 音效的接入技术。
使用场景
在普通的进房实时语音中,玩家的声音不具有 3D 音效的效果,玩家之间只能进行很简单的互动;而引入 3D 位置语音之后,玩家在喊话过程中会暴露自己的方位和位置信息,玩家的声音也会根据位置变化而实时改变。可以说,3D 音效让《大逃杀》这种玩家间的沟通和战斗体验更真实,感受更加沉浸式、更加身临其境的吃鸡玩法。
前提条件
已开通实时语音服务:可参见 语音服务开通指引。
已接入 GME SDK:包括核心接口和实时语音接口的接入,详情可参见 Native SDK 快速接入、Unity SDK 快速接入、Unreal SDK 快速接入。
实现流程
实现流程图
下图为 3D 音效实现的流程图,其中蓝色部分为对比普通进房实时语音需要接入的步骤。
初始化 3D 音效引擎
此函数用于初始化 3D 音效引擎,在进房后调用。在使用 3D 音效之前必须先调用此接口,只接收 3D 音效而不发出 3D 音效的用户也需要调用此接口。
函数原型
public abstract int InitSpatializer(string modelPath)
参数 | 类型 | 意义 |
modelPath | string | 3D 音效资源文件的绝对路径 |
参数中的 3D 音效资源文件,需要另外下载到本地,根据接入 SDK 的版本进行区分:
如果是v2.8以下版本,请单击 下载,md5: d0b76aa64c46598788c2f35f5a8a8694。
如果是v2.8-v2.9.5版本,请单击 下载,md5: 3d4d04b3949e267e34ca809e8a0b9243。
如果是v2.9.6及以上版本,由于3D音效资源文件已内置,此处 modelPath 可填空。
关于资源路径
以 Unity 为例,建议将 3D 文件放在项目的 StreamingAssets 目录下,并参考 SampleCode 中 copyFileFromAssetsToPersistent 函数写法,将资源文件拷贝到不同平台的相应目录中。
以 Unreal 为例,参考 SampleCode 中 CopyAllAssetsToExternal 函数写法,将 3D 模型文件拷贝后再读取路径。
开启或关闭 3D 音效
此函数用于开启或关闭 3D 音效。开启之后可以听到 3D 音效。
函数原型
public abstract int EnableSpatializer(bool enable, bool applyToTeam)
参数 | 类型 | 意义 |
enable | bool | 开启之后可以听到 3D 音效 |
applyToTeam | bool | 3D 语音是否作用于小队内部,仅 enable 为 true 时有效 |
获取当前 3D 音效状态
此函数用于获取当前 3D 音效状态。
函数原型
public abstract bool IsEnableSpatializer()
返回值 | 意义 |
true | 开启状态 |
false | 关闭状态 |
设置 3D 音效衰减距离
需要设置衰减距离,建议设置为 100。
距离与声音衰减的关系
3D 音效中,音源音量的大小与音源距离有一定的衰减关系。单位距离超过 range 之后,音量衰减到几乎为零。
距离范围(引擎单位) | 衰减公式 |
0 < N < range/10 | 衰减系数:1.0 (音量无衰减) |
N ≥ range/10 | 衰减系数:range/10/N |
函数原型
public abstract void UpdateAudioRecvRange(int range)
参数 | 类型 | 意义 |
range | int | 设定音效可接收的范围,建议设置100,此处的距离单位为游戏引擎中的距离单位 |
更新声源方位(包含朝向)
此函数用于更新声源方位角信息,每帧调用便可实现 3D 音效效果。
函数原型
public abstract int UpdateSelfPosition(int position[3], float axisForward[3], float axisRight[3], float axisUp[3])
参数 | 类型 | 意义 |
position | int[] | 自身在世界坐标系中的坐标,顺序是前、右、上 |
axisForward | float[] | 自身坐标系前轴的单位向量 |
axisRight | float[] | 自身坐标系右轴的单位向量 |
axisUp | float[] | 自身坐标系上轴的单位向量 |
示例代码
Unreal
FVector cameraLocation = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraLocation();FRotator cameraRotation = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraRotation();int position[] = { (int)cameraLocation.X,(int)cameraLocation.Y, (int)cameraLocation.Z };FMatrix matrix = ((FRotationMatrix)cameraRotation);float forward[] = { matrix.GetColumn(0).X,matrix.GetColumn(1).X,matrix.GetColumn(2).X };float right[] = { matrix.GetColumn(0).Y,matrix.GetColumn(1).Y,matrix.GetColumn(2).Y };float up[] = { matrix.GetColumn(0).Z,matrix.GetColumn(1).Z,matrix.GetColumn(2).Z};ITMGContextGetInstance()->GetRoom()->UpdateSelfPosition(position, forward, right, up);
Unity
Transform selftrans = currentPlayer.gameObject.transform;Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, selftrans.rotation, Vector3.one);int[] position = new int[3] { selftrans.position.z, selftrans.position.x, selftrans.position.y };float[] axisForward = new float[3] { matrix.m22, matrix.m02, matrix.m12 };float[] axisRight = new float[3] { matrix.m20, matrix.m00, matrix.m10 };float[] axisUp = new float[3] { matrix.m21, matrix.m01, matrix.m11 };ITMGContext.GetInstance().GetRoom().UpdateSelfPosition(position, axisForward, axisRight, axisUp);
本地方位接口(VR 场景)
本接口适用于 VR 设备中,对 3D 位置变化有极高要求的场景。此功能为高级接口,需要在 GME 2.9.2 以上版本才可使用。
在一般 3D 的场景中,用户只需要通过函数 UpdateSelfPosition 更新自己的位置信息,然后经网络发送给其他用户。UpdateOtherPosition支持本地传入其他玩家的位置信息,不经过网络发送,适用于 VR 游戏场景。
为了避免和远程更新的坐标发生冲突,只要您调用了UpdateOtherPosition,远程坐标便会被丢弃,这种影响持续到再一次进房。所以,您如果要通过本地方式更新玩家坐标,请更新所有玩家的坐标。
函数原型
public abstract int UpdateOtherPosition(string openID, int position[3])
参数 | 类型 | 意义 |
openID | string | 用户标识。 |
position | int[] | 其他玩家在世界坐标系中的坐标,顺序是前、右、上 |
注意
您如果要通过本地方式更新玩家坐标,请遍历所有的玩家坐标,通过此接口将坐标进行传入。
3D 语音黑名单接口
注意
此接口在 GME 2.9.3 及以上版本 SDK 生效。
目前 3D 音效调用后对房间内所有人都会生效。由于某些特定场景下,不希望接受到的某个人声音会有因 3D 音效而产生的衰减,可以通过调用此接口,将某个人加入 3D 语音黑名单中,加入后此 openid 的声音不再有 3D 音效效果。
virtual int AddSpatializerBlacklist(const char* openId);
如果需要将此 openid 从黑名单中移除,需要调用以下接口:
virtual int RemoveSpatializerBlacklist(const char* openId);
如果需要清空黑名单,需要调用以下接口:
virtual int ClearSpatializerBlacklist();
问题排查
如果接入后测试语音,没有 3D 音效效果,排查路径如下:
1. 确定是否已经进房成功及开启麦克风?双方能否听到声音?
2. 是否适用双声道耳机进行收听?
3. InitSpatializer 接口返回值是否为0?
4. UpdateAudioRecvRange 设置是否过小?
5. 是否有周期性的调用 UpdateSelfPosition 接口?
6. 通过 错误码文档 进行判断并解决。